test and validate signup with dispersable keypad and login with non-dispersable keypad

This commit is contained in:
2024-07-24 14:17:56 -05:00
parent 50dc917a90
commit 772c93c8a8
11 changed files with 227 additions and 142 deletions

View File

@@ -28,18 +28,21 @@ class NKodeAPI(BaseModel):
def generate_index_interface(self, customer_id: UUID) -> tuple[UUID, list[int]]: def generate_index_interface(self, customer_id: UUID) -> tuple[UUID, list[int]]:
assert (customer_id in self.customers.keys()) assert (customer_id in self.customers.keys())
customer = self.customers[customer_id] customer = self.customers[customer_id]
set_interface = UserInterface.new(customer.attributes.keypad_size) login_interface = UserInterface.new(customer.attributes.keypad_size)
set_interface = login_interface.sign_up_interface()
new_session = UserSignupSession( new_session = UserSignupSession(
session_id=uuid4(), session_id=uuid4(),
login_interface=login_interface,
set_interface=set_interface.interface, set_interface=set_interface.interface,
customer_id=customer_id, customer_id=customer_id,
keypad_size=customer.attributes.keypad_size, keypad_size=set_interface.keypad_size,
) )
self.signup_sessions[new_session.session_id] = new_session self.signup_sessions[new_session.session_id] = new_session
return new_session.session_id, new_session.set_interface return new_session.session_id, new_session.set_interface
def set_nkode( def set_nkode(
self, username: str, self,
username: str,
customer_id: UUID, customer_id: UUID,
key_selection: list[int], key_selection: list[int],
session_id: UUID session_id: UUID
@@ -71,10 +74,7 @@ class NKodeAPI(BaseModel):
username=username, username=username,
enciphered_passcode=enciphered_passcode, enciphered_passcode=enciphered_passcode,
user_keys=new_user_keys, user_keys=new_user_keys,
user_interface=UserInterface( user_interface=self.signup_sessions[session_id].login_interface,
interface=self.signup_sessions[session_id].confirm_interface,
keypad_size=customer.attributes.keypad_size
),
) )
self.customers[customer_id].add_new_user(new_user) self.customers[customer_id].add_new_user(new_user)
del self.signup_sessions[session_id] del self.signup_sessions[session_id]
@@ -88,7 +88,7 @@ class NKodeAPI(BaseModel):
customer = self.customers[customer_id] customer = self.customers[customer_id]
assert (username in customer.users.keys()) assert (username in customer.users.keys())
user = customer.users[username] user = customer.users[username]
user.user_interface.shuffle_interface() user.user_interface.partial_interface_shuffle()
return user.user_interface.interface return user.user_interface.interface
def login(self, customer_id: UUID, username: str, key_selection: list[int]) -> bool: def login(self, customer_id: UUID, username: str, key_selection: list[int]) -> bool:

View File

@@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 11, "execution_count": 62,
"outputs": [], "outputs": [],
"source": [ "source": [
"from nkode_api import NKodeAPI\n", "from nkode_api import NKodeAPI\n",
@@ -14,14 +14,14 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:26.168590Z", "end_time": "2024-07-22T16:43:14.323435Z",
"start_time": "2024-07-19T19:42:26.080917Z" "start_time": "2024-07-22T16:43:14.225885Z"
} }
} }
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 12, "execution_count": 63,
"outputs": [], "outputs": [],
"source": [ "source": [
"def random_username() -> str:\n", "def random_username() -> str:\n",
@@ -40,14 +40,14 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:26.169484Z", "end_time": "2024-07-22T16:43:14.323797Z",
"start_time": "2024-07-19T19:42:26.084626Z" "start_time": "2024-07-22T16:43:14.229848Z"
} }
} }
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 13, "execution_count": 64,
"outputs": [], "outputs": [],
"source": [ "source": [
"api = NKodeAPI()" "api = NKodeAPI()"
@@ -55,8 +55,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:26.169561Z", "end_time": "2024-07-22T16:43:14.323871Z",
"start_time": "2024-07-19T19:42:26.087253Z" "start_time": "2024-07-22T16:43:14.232313Z"
} }
} }
}, },
@@ -79,7 +79,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 65,
"outputs": [], "outputs": [],
"source": [ "source": [
"policy = NKodePolicy(\n", "policy = NKodePolicy(\n",
@@ -89,8 +89,8 @@
" distinct_attributes=4\n", " distinct_attributes=4\n",
")\n", ")\n",
"keypad_size = KeypadSize(\n", "keypad_size = KeypadSize(\n",
" numb_of_keys = 10,\n", " numb_of_keys = 5,\n",
" attrs_per_key = 7 # aka number of sets\n", " attrs_per_key = 4 # aka number of sets\n",
")\n", ")\n",
"customer_id = api.create_new_customer(keypad_size, policy)\n", "customer_id = api.create_new_customer(keypad_size, policy)\n",
"customer = api.customers[customer_id]" "customer = api.customers[customer_id]"
@@ -98,8 +98,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:26.266945Z", "end_time": "2024-07-22T16:43:14.414667Z",
"start_time": "2024-07-19T19:42:26.091559Z" "start_time": "2024-07-22T16:43:14.238210Z"
} }
} }
}, },
@@ -126,14 +126,14 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 16, "execution_count": 66,
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Customer Sets: [36939, 30293, 19380, 1964, 37282, 10031, 35065]\n", "Customer Sets: [6259, 41347, 52298, 30406]\n",
"Customer Attributes: [3505, 54543, 45347, 44748, 53903, 52815, 60524, 9975, 48764, 34550, 64903, 32542, 23911, 35423, 63534, 65510, 21500, 37871, 19901, 6884, 255, 17031, 63424, 28925, 34144, 42192, 31390, 40124, 17254, 48729, 39518, 57631, 43182, 61064, 4422, 53465, 55843, 37538, 60243, 21929, 51240, 24244, 27507, 57663, 45226, 31543, 58101, 37770, 62668, 49947, 64348, 20373, 64786, 14379, 13970, 11323, 3662, 62709, 37802, 27817, 60687, 22963, 42846, 3620, 9784, 48482, 13855, 60342, 34564, 45989]\n" "Customer Attributes: [65233, 63177, 42010, 46768, 5724, 12484, 7294, 20676, 9411, 8047, 18067, 6808, 51196, 46992, 15995, 34735, 37237, 57815, 17974, 10378]\n"
] ]
} }
], ],
@@ -146,8 +146,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:43.930527Z", "end_time": "2024-07-22T16:43:14.431062Z",
"start_time": "2024-07-19T19:42:43.924673Z" "start_time": "2024-07-22T16:43:14.413572Z"
} }
} }
}, },
@@ -162,20 +162,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 67,
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Set to Attribute Map:\n", "Set to Attribute Map:\n",
"36939: [3505, 9975, 63534, 17031, 17254, 53465, 27507, 49947, 3662, 3620]\n", "6259: [65233, 5724, 9411, 51196, 37237]\n",
"30293: [54543, 48764, 65510, 63424, 48729, 55843, 57663, 64348, 62709, 9784]\n", "41347: [63177, 12484, 8047, 46992, 57815]\n",
"19380: [45347, 34550, 21500, 28925, 39518, 37538, 45226, 20373, 37802, 48482]\n", "52298: [42010, 7294, 18067, 15995, 17974]\n",
"1964: [44748, 64903, 37871, 34144, 57631, 60243, 31543, 64786, 27817, 13855]\n", "30406: [46768, 20676, 6808, 34735, 10378]\n"
"37282: [53903, 32542, 19901, 42192, 43182, 21929, 58101, 14379, 60687, 60342]\n",
"10031: [52815, 23911, 6884, 31390, 61064, 51240, 37770, 13970, 22963, 34564]\n",
"35065: [60524, 35423, 255, 40124, 4422, 24244, 62668, 11323, 42846, 45989]\n"
] ]
} }
], ],
@@ -190,8 +187,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:46.177582Z", "end_time": "2024-07-22T16:43:14.431341Z",
"start_time": "2024-07-19T19:42:46.173094Z" "start_time": "2024-07-22T16:43:14.417167Z"
} }
} }
}, },
@@ -206,7 +203,7 @@
"\n", "\n",
"#### Generate Index Interface\n", "#### Generate Index Interface\n",
"- random interface is generated. Run the cell below over and over to see it change. Notice that values never move out of their columns jus their rows.\n", "- random interface is generated. Run the cell below over and over to see it change. Notice that values never move out of their columns jus their rows.\n",
"- each value in the interface is the index value of an attribute in the customer interface\n", "- each value in the interface is the index value of a customer attribute\n",
"- the user never learns what their \"real\" attribute is. All they do is specify an index in the customer interface\n" "- the user never learns what their \"real\" attribute is. All they do is specify an index in the customer interface\n"
], ],
"metadata": { "metadata": {
@@ -215,16 +212,26 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 18, "execution_count": 68,
"outputs": [], "outputs": [
{
"data": {
"text/plain": "[[4, 1, 10, 3],\n [8, 5, 2, 15],\n [0, 13, 14, 11],\n [16, 9, 6, 7],\n [12, 17, 18, 19]]"
},
"execution_count": 68,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [ "source": [
"session_id, signup_interface = api.generate_index_interface(customer_id)" "session_id, signup_interface = api.generate_index_interface(customer_id)\n",
"list_to_matrix(signup_interface, keypad_size.attrs_per_key)"
], ],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:47.644598Z", "end_time": "2024-07-22T16:43:14.431562Z",
"start_time": "2024-07-19T19:42:47.640134Z" "start_time": "2024-07-22T16:43:14.420566Z"
} }
} }
}, },
@@ -232,7 +239,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"source": [ "source": [
"#### Set NKode\n", "#### Set NKode\n",
"The user identifies attributes in the interface they want in their nkode. Each attribute in the gui has an index value. Below the user has selected 12, 2, 52, 28. Graphiclly represent with anything. The only requirment is that the graphical must be associated with the same number everytime the user goes to login. If the user wants to change anything about their interface, they must also change their nkode." "The user identifies attributes in the interface they want in their nkode. Each attribute in the gui has an index value. Below the user has selected 16, 9, 6, 19. Graphiclly represent with anything. The only requirment is that the graphical must be associated with the same number everytime the user goes to login. If the user wants to change anything about their interface, they must also change their nkode."
], ],
"metadata": { "metadata": {
"collapsed": false "collapsed": false
@@ -240,64 +247,54 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": 69,
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Keypad View\n", "Keypad View\n",
"Key 0: [63, 1, 16, 59, 32, 19, 34]\n", "Key 0: [4, 1, 10, 3]\n",
"Key 1: [49, 57, 65, 66, 4, 47, 48]\n", "Key 1: [8, 5, 2, 15]\n",
"Key 2: [28, 50, 58, 10, 11, 5, 27]\n", "Key 2: [0, 13, 14, 11]\n",
"Key 3: [21, 43, 51, 52, 25, 68, 41]\n", "Key 3: [16, 9, 6, 7]\n",
"Key 4: [7, 64, 2, 38, 60, 54, 62]\n", "Key 4: [12, 17, 18, 19]\n",
"Key 5: [56, 29, 23, 31, 67, 61, 20]\n",
"Key 6: [42, 15, 9, 24, 53, 26, 13]\n",
"Key 7: [14, 36, 30, 45, 46, 33, 69]\n",
"Key 8: [0, 22, 44, 17, 39, 40, 55]\n",
"Key 9: [35, 8, 37, 3, 18, 12, 6]\n",
"Selected Keys\n", "Selected Keys\n",
"[9, 4, 3, 2]\n" "[3, 3, 3, 4]\n"
] ]
} }
], ],
"source": [ "source": [
"keypad_view(signup_interface, keypad_size.attrs_per_key)\n", "keypad_view(signup_interface, keypad_size.attrs_per_key)\n",
"username = random_username()\n", "username = random_username()\n",
"user_passcode = [12, 2, 52, 28]\n", "user_passcode = [16, 9, 6, 19]\n",
"selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.attrs_per_key)\n", "selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.attrs_per_key)\n",
"print(f\"Selected Keys\\n{selected_keys_set}\")" "print(f\"Selected Keys\\n{selected_keys_set}\")"
], ],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:48.948115Z", "end_time": "2024-07-22T16:43:14.431673Z",
"start_time": "2024-07-19T19:42:48.942682Z" "start_time": "2024-07-22T16:43:14.424684Z"
} }
} }
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 70,
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Keypad View\n", "Keypad View\n",
"Key 0: [49, 22, 23, 59, 11, 12, 62]\n", "Key 0: [12, 9, 14, 15]\n",
"Key 1: [42, 64, 44, 52, 46, 5, 6]\n", "Key 1: [0, 17, 2, 3]\n",
"Key 2: [56, 8, 2, 66, 32, 33, 27]\n", "Key 2: [8, 13, 10, 7]\n",
"Key 3: [0, 50, 37, 24, 25, 19, 69]\n", "Key 3: [4, 5, 6, 19]\n",
"Key 4: [7, 36, 58, 31, 4, 68, 34]\n", "Key 4: [16, 1, 18, 11]\n",
"Key 5: [35, 1, 30, 17, 53, 47, 41]\n",
"Key 6: [28, 43, 16, 38, 67, 26, 48]\n",
"Key 7: [14, 57, 51, 3, 39, 61, 13]\n",
"Key 8: [63, 15, 65, 10, 60, 40, 20]\n",
"Key 9: [21, 29, 9, 45, 18, 54, 55]\n",
"Selected Keys\n", "Selected Keys\n",
"[0, 2, 1, 6]\n" "[4, 0, 3, 3]\n"
] ]
} }
], ],
@@ -310,8 +307,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:49.532737Z", "end_time": "2024-07-22T16:43:14.431769Z",
"start_time": "2024-07-19T19:42:49.528687Z" "start_time": "2024-07-22T16:43:14.427713Z"
} }
} }
}, },
@@ -329,7 +326,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 21, "execution_count": 71,
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
@@ -337,16 +334,11 @@
"text": [ "text": [
"Set Interface\n", "Set Interface\n",
"Keypad View\n", "Keypad View\n",
"Key 0: [63, 1, 16, 59, 32, 19, 34]\n", "Key 0: [4, 1, 10, 3]\n",
"Key 1: [49, 57, 65, 66, 4, 47, 48]\n", "Key 1: [8, 5, 2, 15]\n",
"Key 2: [28, 50, 58, 10, 11, 5, 27]\n", "Key 2: [0, 13, 14, 11]\n",
"Key 3: [21, 43, 51, 52, 25, 68, 41]\n", "Key 3: [16, 9, 6, 7]\n",
"Key 4: [7, 64, 2, 38, 60, 54, 62]\n", "Key 4: [12, 17, 18, 19]\n"
"Key 5: [56, 29, 23, 31, 67, 61, 20]\n",
"Key 6: [42, 15, 9, 24, 53, 26, 13]\n",
"Key 7: [14, 36, 30, 45, 46, 33, 69]\n",
"Key 8: [0, 22, 44, 17, 39, 40, 55]\n",
"Key 9: [35, 8, 37, 3, 18, 12, 6]\n"
] ]
} }
], ],
@@ -357,14 +349,14 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:50.432534Z", "end_time": "2024-07-22T16:43:14.447860Z",
"start_time": "2024-07-19T19:42:50.427816Z" "start_time": "2024-07-22T16:43:14.430888Z"
} }
} }
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 22, "execution_count": 72,
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
@@ -372,16 +364,11 @@
"text": [ "text": [
"Confirm Interface\n", "Confirm Interface\n",
"Keypad View\n", "Keypad View\n",
"Key 0: [49, 22, 23, 59, 11, 12, 62]\n", "Key 0: [12, 9, 14, 15]\n",
"Key 1: [42, 64, 44, 52, 46, 5, 6]\n", "Key 1: [0, 17, 2, 3]\n",
"Key 2: [56, 8, 2, 66, 32, 33, 27]\n", "Key 2: [8, 13, 10, 7]\n",
"Key 3: [0, 50, 37, 24, 25, 19, 69]\n", "Key 3: [4, 5, 6, 19]\n",
"Key 4: [7, 36, 58, 31, 4, 68, 34]\n", "Key 4: [16, 1, 18, 11]\n"
"Key 5: [35, 1, 30, 17, 53, 47, 41]\n",
"Key 6: [28, 43, 16, 38, 67, 26, 48]\n",
"Key 7: [14, 57, 51, 3, 39, 61, 13]\n",
"Key 8: [63, 15, 65, 10, 60, 40, 20]\n",
"Key 9: [21, 29, 9, 45, 18, 54, 55]\n"
] ]
} }
], ],
@@ -392,14 +379,14 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:50.897855Z", "end_time": "2024-07-22T16:43:14.448110Z",
"start_time": "2024-07-19T19:42:50.894734Z" "start_time": "2024-07-22T16:43:14.433535Z"
} }
} }
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 23, "execution_count": 73,
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
@@ -420,8 +407,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:51.884002Z", "end_time": "2024-07-22T16:43:15.081248Z",
"start_time": "2024-07-19T19:42:51.198018Z" "start_time": "2024-07-22T16:43:14.437249Z"
} }
} }
}, },
@@ -438,14 +425,14 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 23, "execution_count": 73,
"outputs": [], "outputs": [],
"source": [], "source": [],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:53.411190Z", "end_time": "2024-07-22T16:43:15.083482Z",
"start_time": "2024-07-19T19:42:53.406912Z" "start_time": "2024-07-22T16:43:15.078924Z"
} }
} }
}, },
@@ -471,7 +458,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 24, "execution_count": 74,
"outputs": [ "outputs": [
{ {
"data": { "data": {
@@ -513,19 +500,19 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:55.684088Z", "end_time": "2024-07-22T16:43:15.097910Z",
"start_time": "2024-07-19T19:42:55.680817Z" "start_time": "2024-07-22T16:43:15.084617Z"
} }
} }
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 25, "execution_count": 75,
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": "<IPython.core.display.Markdown object>", "text/plain": "<IPython.core.display.Markdown object>",
"text/markdown": "|key|set0|set1|set2|set3|\n|-|-|-|-|-|\n|key1|5|50|55|500|\n|key2|3|30|33|300|\n|key3|2|20|22|200|\n|key4|4|40|44|400|\n|key5|1|10|11|100|" "text/markdown": "|key|set0|set1|set2|set3|\n|-|-|-|-|-|\n|key1|4|40|44|400|\n|key2|2|20|22|200|\n|key3|1|10|11|100|\n|key4|5|50|55|500|\n|key5|3|30|33|300|"
}, },
"metadata": {}, "metadata": {},
"output_type": "display_data" "output_type": "display_data"
@@ -540,19 +527,19 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:56.543819Z", "end_time": "2024-07-22T16:43:15.098089Z",
"start_time": "2024-07-19T19:42:56.537207Z" "start_time": "2024-07-22T16:43:15.088214Z"
} }
} }
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 26, "execution_count": 76,
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": "<IPython.core.display.Markdown object>", "text/plain": "<IPython.core.display.Markdown object>",
"text/markdown": "|key|set0|set1|set2|set3|\n|-|-|-|-|-|\n|key1|3|40|11|200|\n|key2|2|10|55|400|\n|key3|4|50|33|100|\n|key4|1|30|22|500|\n|key5|5|20|44|300|" "text/markdown": "|key|set0|set1|set2|set3|\n|-|-|-|-|-|\n|key1|2|10|44|500|\n|key2|1|50|22|300|\n|key3|5|30|11|400|\n|key4|3|40|55|200|\n|key5|4|20|33|100|"
}, },
"metadata": {}, "metadata": {},
"output_type": "display_data" "output_type": "display_data"
@@ -570,8 +557,65 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2024-07-19T19:42:56.940543Z", "end_time": "2024-07-22T16:43:15.098218Z",
"start_time": "2024-07-19T19:42:56.935742Z" "start_time": "2024-07-22T16:43:15.091198Z"
}
}
},
{
"cell_type": "markdown",
"source": [],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"execution_count": 80,
"outputs": [
{
"data": {
"text/plain": "'$2b$12$M2kUbtPVmpphEHJIw/AKc.v96GcyR9WqPzNcbQqSHJWjiZJ6NwqMm'"
},
"execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"user_hash = list(api.customers[customer_id].users.values())[0].enciphered_passcode.code\n",
"user_hash\n"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-07-22T16:46:22.182625Z",
"start_time": "2024-07-22T16:46:22.178757Z"
}
}
},
{
"cell_type": "code",
"execution_count": 84,
"outputs": [
{
"data": {
"text/plain": "[27172,\n 59678,\n 42816,\n 42517,\n 14869,\n 3862,\n 33437,\n 50365,\n 1299,\n 423,\n 16708,\n 23065,\n 1118,\n 54789,\n 22038,\n 22603,\n 36630,\n 18246,\n 48084,\n 32460]"
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(api.customers[customer_id].users.values())[0].user_keys.alpha_key\n",
"\n"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-07-22T16:48:52.733419Z",
"start_time": "2024-07-22T16:48:52.728228Z"
} }
} }
}, },
@@ -581,10 +625,7 @@
"outputs": [], "outputs": [],
"source": [], "source": [],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false
"ExecuteTime": {
"start_time": "2024-07-19T19:42:26.284802Z"
}
} }
} }
], ],

View File

@@ -12,6 +12,9 @@ class Customer(BaseModel):
attributes: CustomerAttributes attributes: CustomerAttributes
users: dict[str, User] users: dict[str, User]
# TODO: validate policy and keypad size don't conflict
def add_new_user(self, user: User): def add_new_user(self, user: User):
self.users[user.username] = user self.users[user.username] = user

View File

@@ -1,4 +1,4 @@
from pydantic import BaseModel from pydantic import BaseModel, model_validator
from src.models import KeypadSize from src.models import KeypadSize
from src.utils import generate_random_nonrepeating_list from src.utils import generate_random_nonrepeating_list
@@ -9,6 +9,13 @@ class CustomerAttributes(BaseModel):
set_vals: list[int] set_vals: list[int]
keypad_size: KeypadSize keypad_size: KeypadSize
@model_validator(mode='after')
def check_keys_vs_attrs(self):
if self.keypad_size.is_dispersable:
raise ValueError("number of keys must be less than the number of "
"attributes per key to be dispersion resistant")
return self
@staticmethod @staticmethod
def new(keypad_size: KeypadSize): def new(keypad_size: KeypadSize):
assert (keypad_size.numb_of_keys <= 256) assert (keypad_size.numb_of_keys <= 256)

View File

@@ -16,7 +16,7 @@ class NKodePolicy(BaseModel):
min_nkode_len: int = 4 min_nkode_len: int = 4
distinct_sets: int = 0 distinct_sets: int = 0
distinct_attributes: int = 4 distinct_attributes: int = 4
# TODO: bytes_per_attr byte_len: int = 2 # Todo: this should change the total number of bytes an attribute or set value can be
class KeypadSize(BaseModel): class KeypadSize(BaseModel):
@@ -26,3 +26,7 @@ class KeypadSize(BaseModel):
@property @property
def numb_of_attrs(self) -> int: def numb_of_attrs(self) -> int:
return self.attrs_per_key * self.numb_of_keys return self.attrs_per_key * self.numb_of_keys
@property
def is_dispersable(self) -> bool:
return self.attrs_per_key <= self.numb_of_keys

View File

@@ -16,28 +16,55 @@ class UserInterface(BaseModel):
interface=list(range(keypad_size.numb_of_attrs)), interface=list(range(keypad_size.numb_of_attrs)),
keypad_size=keypad_size keypad_size=keypad_size
) )
interface.disperse_interface() interface.random_interface_shuffle()
for _ in range(10):
interface.shuffle_interface()
return interface return interface
def sign_up_interface(self):
assert (not self.keypad_size.is_dispersable)
self.random_interface_shuffle()
interface_matrix = self.interface_keypad_matrix()
attr_set_view = matrix_transpose(interface_matrix)
attr_set_view = secure_fisher_yates_shuffle(attr_set_view)
attr_set_view = attr_set_view[:self.keypad_size.numb_of_keys]
interface_matrix = matrix_transpose(attr_set_view)
return UserInterface(
interface=matrix_to_list(interface_matrix),
keypad_size=KeypadSize(
numb_of_keys=self.keypad_size.numb_of_keys,
attrs_per_key=self.keypad_size.numb_of_keys
)
)
def interface_keypad_matrix(self) -> list[list[int]]:
return list_to_matrix(self.interface, self.keypad_size.attrs_per_key)
def random_interface_shuffle(self):
keypad_view = self.interface_keypad_matrix()
keypad_view = secure_fisher_yates_shuffle(keypad_view)
set_view = matrix_transpose(keypad_view)
set_view = [secure_fisher_yates_shuffle(attr_set) for attr_set in set_view]
keypad_view = matrix_transpose(set_view)
self.interface = matrix_to_list(keypad_view)
def disperse_interface(self): def disperse_interface(self):
assert (self.keypad_size.is_dispersable)
user_interface_matrix = list_to_matrix(self.interface, self.keypad_size.attrs_per_key) user_interface_matrix = list_to_matrix(self.interface, self.keypad_size.attrs_per_key)
shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix) shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix)
attr_rotation = secure_fisher_yates_shuffle(list(range(self.keypad_size.numb_of_keys)))[:self.keypad_size.attrs_per_key] attr_rotation = secure_fisher_yates_shuffle(list(range(self.keypad_size.numb_of_keys)))[
:self.keypad_size.attrs_per_key]
dispersed_interface = self.random_attribute_rotation( dispersed_interface = self.random_attribute_rotation(
shuffled_keys, shuffled_keys,
attr_rotation, attr_rotation,
) )
self.interface = matrix_to_list(dispersed_interface) self.interface = matrix_to_list(dispersed_interface)
def shuffle_interface(self): def partial_interface_shuffle(self):
numb_of_selected_sets = self.keypad_size.attrs_per_key // 2 numb_of_selected_sets = self.keypad_size.attrs_per_key // 2
# randomly shuffle half the sets. if attrs_per_key is odd, randomly add one 50% of the time # randomly shuffle half the sets. if attrs_per_key is odd, randomly add one 50% of the time
numb_of_selected_sets += choice([0, 1]) if (self.keypad_size.attrs_per_key & 1) == 1 else 0 numb_of_selected_sets += choice([0, 1]) if (self.keypad_size.attrs_per_key & 1) == 1 else 0
selected_sets = secure_fisher_yates_shuffle(list(range(self.keypad_size.attrs_per_key)))[:numb_of_selected_sets] selected_sets = secure_fisher_yates_shuffle(list(range(self.keypad_size.attrs_per_key)))[:numb_of_selected_sets]
user_interface_matrix = list_to_matrix(self.interface, self.keypad_size.attrs_per_key) user_interface_matrix = self.interface_keypad_matrix()
shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix) shuffled_keys = secure_fisher_yates_shuffle(user_interface_matrix)
interface_by_sets = [] interface_by_sets = []
for idx, attrs in enumerate(matrix_transpose(shuffled_keys)): for idx, attrs in enumerate(matrix_transpose(shuffled_keys)):
@@ -60,7 +87,7 @@ class UserInterface(BaseModel):
return matrix_transpose(transposed_user_interface) return matrix_transpose(transposed_user_interface)
def attribute_adjacency_graph(self) -> dict[int, set[int]]: def attribute_adjacency_graph(self) -> dict[int, set[int]]:
user_interface_keypad = list_to_matrix(self.interface, self.keypad_size.attrs_per_key) user_interface_keypad = self.interface_keypad_matrix()
graph = {} graph = {}
for key in user_interface_keypad: for key in user_interface_keypad:
for attr in key: for attr in key:
@@ -71,5 +98,5 @@ class UserInterface(BaseModel):
def get_key_attr_idxs(self, key_numb: int) -> list[int]: def get_key_attr_idxs(self, key_numb: int) -> list[int]:
assert (0 <= key_numb < self.keypad_size.numb_of_keys) assert (0 <= key_numb < self.keypad_size.numb_of_keys)
keypad_attr_idx = list_to_matrix(self.interface, self.keypad_size.attrs_per_key) keypad_attr_idx = self.interface_keypad_matrix()
return keypad_attr_idx[key_numb] return keypad_attr_idx[key_numb]

View File

@@ -9,6 +9,8 @@ from src.models import KeypadSize
class UserSignupSession(BaseModel): class UserSignupSession(BaseModel):
session_id: UUID session_id: UUID
customer_id: UUID customer_id: UUID
login_interface: UserInterface
keypad_size: KeypadSize keypad_size: KeypadSize
set_interface: list[int] | None = None set_interface: list[int] | None = None
confirm_interface: list[int] | None = None confirm_interface: list[int] | None = None

View File

@@ -8,17 +8,17 @@ def nkode_api() -> NKodeAPI:
return NKodeAPI() return NKodeAPI()
@pytest.mark.parametrize("keypad_size,user_passcode", [ @pytest.mark.parametrize("keypad_size,passocode_len", [
(KeypadSize(numb_of_keys=10, attrs_per_key=7), [3, 10, 27, 68]), (KeypadSize(numb_of_keys=10, attrs_per_key=11), 4),
(KeypadSize(numb_of_keys=10, attrs_per_key=7), [3, 10, 27, 68, 32]), (KeypadSize(numb_of_keys=10, attrs_per_key=12), 5),
]) ])
def test_create_new_user_and_renew_keys(nkode_api, keypad_size, user_passcode): def test_create_new_user_and_renew_keys(nkode_api, keypad_size, passocode_len):
username = "test_username" username = "test_username"
nkode_policy = NKodePolicy() # default policy nkode_policy = NKodePolicy() # default policy
customer_id = nkode_api.create_new_customer(keypad_size, nkode_policy) customer_id = nkode_api.create_new_customer(keypad_size, nkode_policy)
session_id, set_interface = nkode_api.generate_index_interface(customer_id) session_id, set_interface = nkode_api.generate_index_interface(customer_id)
user_passcode = set_interface[:passocode_len]
key_selection = lambda interface: [interface.index(attr) // keypad_size.attrs_per_key for attr in user_passcode] key_selection = lambda interface: [interface.index(attr) // keypad_size.numb_of_keys for attr in user_passcode]
set_key_selection = key_selection(set_interface) set_key_selection = key_selection(set_interface)
confirm_interface = nkode_api.set_nkode(username, customer_id, set_key_selection, session_id) confirm_interface = nkode_api.set_nkode(username, customer_id, set_key_selection, session_id)
@@ -31,6 +31,7 @@ def test_create_new_user_and_renew_keys(nkode_api, keypad_size, user_passcode):
) )
assert successful_confirm assert successful_confirm
key_selection = lambda interface: [interface.index(attr) // keypad_size.attrs_per_key for attr in user_passcode]
login_interface = nkode_api.get_login_index_interface(username, customer_id) login_interface = nkode_api.get_login_index_interface(username, customer_id)
login_key_selection = key_selection(login_interface) login_key_selection = key_selection(login_interface)
successful_login = nkode_api.login(customer_id, username, login_key_selection) successful_login = nkode_api.login(customer_id, username, login_key_selection)

View File

@@ -5,11 +5,11 @@ from src.models import KeypadSize
@pytest.mark.parametrize( @pytest.mark.parametrize(
"keypad_size", "keypad_size",
[KeypadSize(numb_of_keys=10, attrs_per_key=7)] [KeypadSize(numb_of_keys=10, attrs_per_key=11)]
) )
def test_attr_set_idx(keypad_size): def test_attr_set_idx(keypad_size):
user_interface = UserInterface.new(keypad_size) user_interface = UserInterface.new(keypad_size)
for attr_idx in range(70): for attr_idx in range(keypad_size.numb_of_attrs):
user_interface_idx = user_interface.interface[attr_idx] user_interface_idx = user_interface.interface[attr_idx]
assert (attr_idx % keypad_size.attrs_per_key == user_interface_idx % keypad_size.attrs_per_key) assert (attr_idx % keypad_size.attrs_per_key == user_interface_idx % keypad_size.attrs_per_key)

View File

@@ -22,9 +22,9 @@ def test_encode_decode_base64(passcode_len):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"keypad_size,max_nkode_len", "keypad_size,max_nkode_len",
[ [
(KeypadSize(numb_of_keys=10, attrs_per_key=7), 10), (KeypadSize(numb_of_keys=10, attrs_per_key=11), 10),
(KeypadSize(numb_of_keys=9, attrs_per_key=7), 10), (KeypadSize(numb_of_keys=9, attrs_per_key=11), 10),
(KeypadSize(numb_of_keys=8, attrs_per_key=7), 12), (KeypadSize(numb_of_keys=8, attrs_per_key=11), 12),
]) ])
def test_decode_mask(keypad_size, max_nkode_len): def test_decode_mask(keypad_size, max_nkode_len):
customer = CustomerAttributes.new(keypad_size) customer = CustomerAttributes.new(keypad_size)

View File

@@ -26,7 +26,7 @@ def test_shuffle_attrs(user_interface):
- the order in which the attributes move from key to key is random (i.e. the distance traveled is uniform) - the order in which the attributes move from key to key is random (i.e. the distance traveled is uniform)
""" """
pre_shuffle_interface = user_interface.interface pre_shuffle_interface = user_interface.interface
user_interface.shuffle_interface() user_interface.partial_interface_shuffle()
post_shuffle_interface = user_interface.interface post_shuffle_interface = user_interface.interface
for i in range(1000): for i in range(1000):
assert (not all( assert (not all(