fix nkode api; username should be specified at the beginning of the enrollment

This commit is contained in:
2025-03-24 15:24:53 -05:00
parent 1846dc1065
commit 3a9fadfc03
10 changed files with 281 additions and 199 deletions

View File

@@ -12,26 +12,26 @@ sequenceDiagram
Server->>Server: Create Signup Session Server->>Server: Create Signup Session
Note over User,Server: Set nKode Note over User,Server: Set nKode
Server-->>-Client: signup_session_id, set_keypad, icons Server-->>-Client: signup_session_id, set_keypad, icons
Note left of Server: signup_session_id:<br/>51b187b9-c930-4f5d-81da-c11c082f2c64 Note left of Server: signup_session_id:<br/>1334d391-3c8a-431a-8186-e91b29d42750
Note left of Server: set_keypad:<br/>Key 0: [ 9 29 3 49 50 25]<br/>Key 1: [27 2 12 22 14 16]<br/>Key 2: [36 47 21 13 23 7]<br/>Key 3: [45 11 30 4 32 43]<br/>Key 4: [18 20 39 40 41 52]<br/>Key 5: [ 0 38 48 31 5 34]<br/> Note left of Server: set_keypad:<br/>Key 0: [18 2 39 13 23 16]<br/>Key 1: [36 20 21 49 5 43]<br/>Key 2: [ 0 47 48 4 50 25]<br/>Key 3: [27 38 12 40 32 52]<br/>Key 4: [45 29 3 31 41 34]<br/>Key 5: [ 9 11 30 22 14 7]<br/>
Note left of Server: Icons:<br/>[🍎,🍏,🍊,🍋,🍌,🍉<br/>🍇,🍓,🍒,🍑,🥭,🍍<br/>🥥,🥝,🍅,🍆,🥑,🥕<br/>🌽,🥔,🍠,🥐,🥖,🥨<br/>🥯,🥞,🧀,🍖,🍗,🥚<br/>🍔,🍟,🍕,🌭,🥪,🌮<br/>🌯,🍣,🍤,🍙,🍚,🍜<br/>🍲,🍛,🍱,🥟,🍦,🍧<br/>🍨,🍩,🍪,🎂,🍰,🧁] Note left of Server: Icons:<br/>[🍎,🍏,🍊,🍋,🍌,🍉<br/>🍇,🍓,🍒,🍑,🥭,🍍<br/>🥥,🥝,🍅,🍆,🥑,🥕<br/>🌽,🥔,🍠,🥐,🥖,🥨<br/>🥯,🥞,🧀,🍖,🍗,🥚<br/>🍔,🍟,🍕,🌭,🥪,🌮<br/>🌯,🍣,🍤,🍙,🍚,🍜<br/>🍲,🍛,🍱,🥟,🍦,🍧<br/>🍨,🍩,🍪,🎂,🍰,🧁]
Client->>Client: Order Icons by keypad Client->>Client: Order Icons by keypad
Client->>User: Display Keypad Client->>User: Display Keypad
Note left of Client: Key 0: ['🍑' '🥚' '🍋' '🍩' '🍪' '🥞']<br/>Key 1: ['🍖' '🍊' '🥥' '🥖' '🍅' '🥑']<br/>Key 2: ['🌯' '🍧' '🥐' '🥝' '🥨' '🍓']<br/>Key 3: ['🥟' '🍍' '🍔' '🍌' '🍕' '🍛']<br/>Key 4: ['🌽' '🍠' '🍙' '🍚' '🍜' '🍰']<br/>Key 5: ['🍎' '🍤' '🍨' '🍟' '🍉' '🥪']<br/> Note left of Client: Key 0: ['🌽' '🍊' '🍙' '🥝' '🥨' '🥑']<br/>Key 1: ['🌯' '🍠' '🥐' '🍩' '🍉' '🍛']<br/>Key 2: ['🍎' '🍧' '🍨' '🍌' '🍪' '🥞']<br/>Key 3: ['🍖' '🍤' '🥥' '🍚' '🍕' '🍰']<br/>Key 4: ['🥟' '🥚' '🍋' '🍟' '🍜' '🥪']<br/>Key 5: ['🍑' '🍍' '🍔' '🥖' '🍅' '🍓']<br/>
Note left of User: User icons: ['🌯' '🍖' '🍰' '🍓'] Note left of User: User icons: ['🍌' '🍟' '🌽' '🥝']
User->>Client: Set Key Selection: [2, 1, 4, 2] User->>Client: Set Key Selection: [2, 4, 0, 0]
Client->>+Server: Set nKode:<br/>51b187b9-c930-4f5d-81da-c11c082f2c64<br/>[2, 1, 4, 2] Client->>+Server: Set nKode:<br/>1334d391-3c8a-431a-8186-e91b29d42750<br/>[2, 4, 0, 0]
Server->>Server: Disperse Set Keypad Server->>Server: Disperse Set Keypad
Note over User,Server: Confirm nKode Note over User,Server: Confirm nKode
Server-->>-Client: signup_session_id, confirm_keypad, icons Server-->>-Client: signup_session_id, confirm_keypad, icons
Note left of Server: signup_session_id:<br/>51b187b9-c930-4f5d-81da-c11c082f2c64 Note left of Server: signup_session_id:<br/>1334d391-3c8a-431a-8186-e91b29d42750
Note left of Server: confirm_keypad:<br/>Key 0: [27 47 39 4 5 25]<br/>Key 1: [45 20 48 49 14 7]<br/>Key 2: [ 9 38 12 13 32 52]<br/>Key 3: [36 2 30 40 50 34]<br/>Key 4: [18 11 3 31 23 16]<br/>Key 5: [ 0 29 21 22 41 43]<br/> Note left of Server: confirm_keypad:<br/>Key 0: [27 47 3 13 14 43]<br/>Key 1: [ 0 29 30 49 23 52]<br/>Key 2: [45 11 39 40 5 25]<br/>Key 3: [ 9 2 21 4 32 34]<br/>Key 4: [18 20 12 31 50 7]<br/>Key 5: [36 38 48 22 41 16]<br/>
Client->>Client: Order Icons by keypad Client->>Client: Order Icons by keypad
Client->>User: Display Keypad Client->>User: Display Keypad
Note left of Client: Key 0: ['🍖' '🍧' '🍙' '🍌' '🍉' '🥞']<br/>Key 1: ['🥟' '🍠' '🍨' '🍩' '🍅' '🍓']<br/>Key 2: ['🍑' '🍤' '🥥' '🥝' '🍕' '🍰']<br/>Key 3: ['🌯' '🍊' '🍔' '🍚' '🍪' '🥪']<br/>Key 4: ['🌽' '🍍' '🍋' '🍟' '🥨' '🥑']<br/>Key 5: ['🍎' '🥚' '🥐' '🥖' '🍜' '🍛']<br/> Note left of Client: Key 0: ['🍖' '🍧' '🍋' '🥝' '🍅' '🍛']<br/>Key 1: ['🍎' '🥚' '🍔' '🍩' '🥨' '🍰']<br/>Key 2: ['🥟' '🍍' '🍙' '🍚' '🍉' '🥞']<br/>Key 3: ['🍑' '🍊' '🥐' '🍌' '🍕' '🥪']<br/>Key 4: ['🌽' '🍠' '🥥' '🍟' '🍪' '🍓']<br/>Key 5: ['🌯' '🍤' '🍨' '🥖' '🍜' '🥑']<br/>
Note left of User: User icons: ['🌯' '🍖' '🍰' '🍓'] Note left of User: User icons: ['🍌' '🍟' '🌽' '🥝']
User->>Client: Key Selection: [3, 0, 2, 1] User->>Client: Key Selection: [3, 4, 4, 0]
Client->>+Server: Confirm nKode:<br/>51b187b9-c930-4f5d-81da-c11c082f2c64<br/>[3, 0, 2, 1] Client->>+Server: Confirm nKode:<br/>1334d391-3c8a-431a-8186-e91b29d42750<br/>[3, 4, 4, 0]
Server->>Server: Create User Server->>Server: Create User
Server-->>-Client: Success Server-->>-Client: Success
``` ```

View File

@@ -10,13 +10,13 @@ sequenceDiagram
Note left of User: email: user@example.com Note left of User: email: user@example.com
User->>Server: Submit Email User->>Server: Submit Email
Server->>Client: login_keypad, icons Server->>Client: login_keypad, icons
Note left of Server: Login Keypad:<br/>Key 0: [ 9 1 29 3 49 50 33 25 35]<br/>Key 1: [27 28 2 12 22 14 24 16 17]<br/>Key 2: [36 37 47 21 13 23 42 7 26]<br/>Key 3: [45 19 11 30 4 32 51 43 8]<br/>Key 4: [18 46 20 39 40 41 15 52 44]<br/>Key 5: [ 0 10 38 48 31 5 6 34 53]<br/> Note left of Server: Login Keypad:<br/>Key 0: [18 46 2 39 13 23 6 16 53]<br/>Key 1: [36 28 20 21 49 5 15 43 8]<br/>Key 2: [ 0 10 47 48 4 50 51 25 35]<br/>Key 3: [27 1 38 12 40 32 42 52 17]<br/>Key 4: [45 37 29 3 31 41 24 34 44]<br/>Key 5: [ 9 19 11 30 22 14 33 7 26]<br/>
Note left of Server: Icons:<br/>[🍎,🍏,🍊,🍋,🍌,🍉<br/>🍇,🍓,🍒,🍑,🥭,🍍<br/>🥥,🥝,🍅,🍆,🥑,🥕<br/>🌽,🥔,🍠,🥐,🥖,🥨<br/>🥯,🥞,🧀,🍖,🍗,🥚<br/>🍔,🍟,🍕,🌭,🥪,🌮<br/>🌯,🍣,🍤,🍙,🍚,🍜<br/>🍲,🍛,🍱,🥟,🍦,🍧<br/>🍨,🍩,🍪,🎂,🍰,🧁] Note left of Server: Icons:<br/>[🍎,🍏,🍊,🍋,🍌,🍉<br/>🍇,🍓,🍒,🍑,🥭,🍍<br/>🥥,🥝,🍅,🍆,🥑,🥕<br/>🌽,🥔,🍠,🥐,🥖,🥨<br/>🥯,🥞,🧀,🍖,🍗,🥚<br/>🍔,🍟,🍕,🌭,🥪,🌮<br/>🌯,🍣,🍤,🍙,🍚,🍜<br/>🍲,🍛,🍱,🥟,🍦,🍧<br/>🍨,🍩,🍪,🎂,🍰,🧁]
Client->>Client: Order Icons Client->>Client: Order Icons
Client->>User: Display Keypad Client->>User: Display Keypad
Note left of Client: Key 0: ['🍑' '🍏' '🥚' '🍋' '🍩' '🍪' '🌭' '🥞' '🌮']<br/>Key 1: ['🍖' '🍗' '🍊' '🥥' '🥖' '🍅' '🥯' '🥑' '🥕']<br/>Key 2: ['🌯' '🍣' '🍧' '🥐' '🥝' '🥨' '🍲' '🍓' '🧀']<br/>Key 3: ['🥟' '🥔' '🍍' '🍔' '🍌' '🍕' '🎂' '🍛' '🍒']<br/>Key 4: ['🌽' '🍦' '🍠' '🍙' '🍚' '🍜' '🍆' '🍰' '🍱']<br/>Key 5: ['🍎' '🥭' '🍤' '🍨' '🍟' '🍉' '🍇' '🥪' '🧁']<br/> Note left of Client: Key 0: ['🌽' '🍦' '🍊' '🍙' '🥝' '🥨' '🍇' '🥑' '🧁']<br/>Key 1: ['🌯' '🍗' '🍠' '🥐' '🍩' '🍉' '🍆' '🍛' '🍒']<br/>Key 2: ['🍎' '🥭' '🍧' '🍨' '🍌' '🍪' '🎂' '🥞' '🌮']<br/>Key 3: ['🍖' '🍏' '🍤' '🥥' '🍚' '🍕' '🍲' '🍰' '🥕']<br/>Key 4: ['🥟' '🍣' '🥚' '🍋' '🍟' '🍜' '🥯' '🥪' '🍱']<br/>Key 5: ['🍑' '🥔' '🍍' '🍔' '🥖' '🍅' '🌭' '🍓' '🧀']<br/>
Note left of User: User passcode icons: ['🌯' '🍖' '🍰' '🍓'] Note left of User: User passcode icons: ['🍌' '🍟' '🌽' '🥝']
User->>Client: Selected Keys<br/>[2, 1, 4, 2] User->>Client: Selected Keys<br/>[2, 4, 0, 0]
Client->>Server: Login:<br/>email: user@example.com<br/>selected_keys: [2, 1, 4, 2] Client->>Server: Login:<br/>email: user@example.com<br/>selected_keys: [2, 4, 0, 0]
Server-->>Client: Success Server-->>Client: Success
``` ```

View File

@@ -39,20 +39,20 @@ if __name__ == "__main__":
props_per_key=9 props_per_key=9
) )
customer_id = api.create_new_customer(keypad_size, policy) customer_id = api.create_new_customer(keypad_size, policy)
signup_session_id, set_signup_keypad = api.generate_signup_keypad(customer_id)
ordered_set_icons = emojis[set_signup_keypad]
username = "test_username" + "".join([choice(ascii_lowercase) for _ in range(6)]) username = "test_username" + "".join([choice(ascii_lowercase) for _ in range(6)])
signup_session_id, set_signup_keypad = api.generate_signup_keypad(customer_id, username)
ordered_set_icons = emojis[set_signup_keypad]
passcode_len = 4 passcode_len = 4
passcode_property_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len, passcode_property_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len,
replace=False).tolist() replace=False).tolist()
selected_keys_set = select_keys_with_passcode_values(passcode_property_indices, set_signup_keypad, selected_keys_set = select_keys_with_passcode_values(passcode_property_indices, set_signup_keypad,
keypad_size.numb_of_keys) keypad_size.numb_of_keys)
confirm_keypad = api.set_nkode(username, customer_id, selected_keys_set, signup_session_id) confirm_keypad = api.set_nkode(customer_id, selected_keys_set, signup_session_id)
selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad, selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad,
keypad_size.numb_of_keys) keypad_size.numb_of_keys)
ordered_confirm_icons = emojis[confirm_keypad] ordered_confirm_icons = emojis[confirm_keypad]
print(f"Selected Keys\n{selected_keys_confirm}") print(f"Selected Keys\n{selected_keys_confirm}")
success = api.confirm_nkode(username, customer_id, selected_keys_confirm, signup_session_id) success = api.confirm_nkode(customer_id, selected_keys_confirm, signup_session_id)
context = { context = {
"email": "user@example.com", "email": "user@example.com",
"signup_session_id": signup_session_id, "signup_session_id": signup_session_id,

View File

View File

View File

@@ -29,15 +29,18 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-24T09:48:10.442598Z", "end_time": "2025-03-24T20:06:28.904351Z",
"start_time": "2025-03-24T09:48:10.410209Z" "start_time": "2025-03-24T20:06:28.864248Z"
} }
}, },
"outputs": [], "outputs": [],
"execution_count": 1 "execution_count": 4
}, },
{ {
"metadata": {},
"cell_type": "code", "cell_type": "code",
"outputs": [],
"execution_count": null,
"source": [ "source": [
"api = NKodeAPI()\n", "api = NKodeAPI()\n",
"user_icons = np.array([\n", "user_icons = np.array([\n",
@@ -48,16 +51,7 @@
" \"🦁\", \"🐻\", \"🐸\", \"🐙\", \"🦄\",\n", " \"🦁\", \"🐻\", \"🐸\", \"🐙\", \"🦄\",\n",
" \"🌟\", \"⚡\", \"🔥\", \"🍕\", \"🎉\"\n", " \"🌟\", \"⚡\", \"🔥\", \"🍕\", \"🎉\"\n",
"])" "])"
], ]
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-24T09:48:10.450851Z",
"start_time": "2025-03-24T09:48:10.448737Z"
}
},
"outputs": [],
"execution_count": 2
}, },
{ {
"metadata": {}, "metadata": {},
@@ -70,6 +64,7 @@
] ]
}, },
{ {
"metadata": {},
"cell_type": "markdown", "cell_type": "markdown",
"source": [ "source": [
"#### Customer Cipher Keys\n", "#### Customer Cipher Keys\n",
@@ -78,13 +73,13 @@
"There are two types of Customer Cipher Keys:\n", "There are two types of Customer Cipher Keys:\n",
"1. property key: Combined with the user property key to get the server-side representation of a users icons.\n", "1. property key: Combined with the user property key to get the server-side representation of a users icons.\n",
"2. position key: Combined with the user position key to get the server-side representation the position in each key.\n" "2. position key: Combined with the user position key to get the server-side representation the position in each key.\n"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"metadata": {},
"cell_type": "code", "cell_type": "code",
"outputs": [],
"execution_count": null,
"source": [ "source": [
"policy = NKodePolicy(\n", "policy = NKodePolicy(\n",
" max_nkode_len=10,\n", " max_nkode_len=10,\n",
@@ -107,69 +102,20 @@
"print(f\"Position to Properties Map:\")\n", "print(f\"Position to Properties Map:\")\n",
"for pos_val, props in position_properties_dict.items():\n", "for pos_val, props in position_properties_dict.items():\n",
" print(f\"{pos_val}: {props}\")" " print(f\"{pos_val}: {props}\")"
], ]
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-24T09:48:10.468165Z",
"start_time": "2025-03-24T09:48:10.456820Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Customer Position Key: [ 4136 64524 15410 9988 20496 18918]\n",
"Customer Properties Key:\n",
"[46103 19687 10938 59248 5143 27050]\n",
"[26684 7431 59668 28699 6929 18710]\n",
"[12853 35476 62914 24111 36473 25394]\n",
"[63988 14898 1879 44350 53666 23249]\n",
"[23805 45848 21514 8782 7583 36157]\n",
"Position to Properties Map:\n",
"4136: [46103 26684 12853 63988 23805]\n",
"64524: [19687 7431 35476 14898 45848]\n",
"15410: [10938 59668 62914 1879 21514]\n",
"9988: [59248 28699 24111 44350 8782]\n",
"20496: [ 5143 6929 36473 53666 7583]\n",
"18918: [27050 18710 25394 23249 36157]\n"
]
}
],
"execution_count": 3
}, },
{ {
"metadata": { "metadata": {},
"ExecuteTime": {
"end_time": "2025-03-24T09:48:10.593687Z",
"start_time": "2025-03-24T09:48:10.591235Z"
}
},
"cell_type": "code", "cell_type": "code",
"outputs": [],
"execution_count": null,
"source": [ "source": [
"user_icon_keypad = user_icons.reshape(-1, keypad_size.props_per_key)\n", "user_icon_keypad = user_icons.reshape(-1, keypad_size.props_per_key)\n",
"pos_icons_dict = dict(zip(customer.cipher.position_key, user_icon_keypad.T))\n", "pos_icons_dict = dict(zip(customer.cipher.position_key, user_icon_keypad.T))\n",
"print(\"Position Value to Icons Map:\")\n", "print(\"Position Value to Icons Map:\")\n",
"for pos_val, icons in pos_icons_dict.items():\n", "for pos_val, icons in pos_icons_dict.items():\n",
" print(f\"{pos_val}: {icons}\")\n" " print(f\"{pos_val}: {icons}\")\n"
], ]
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Position Value to Icons Map:\n",
"4136: ['😀' '🥺' '🤔' '🐱' '🦄']\n",
"64524: ['😂' '😡' '🙃' '🐶' '🌟']\n",
"15410: ['🥳' '😱' '😇' '🦁' '⚡']\n",
"9988: ['😍' '🤯' '🤖' '🐻' '🔥']\n",
"20496: ['🤓' '🥰' '👽' '🐸' '🍕']\n",
"18918: ['😎' '😴' '👾' '🐙' '🎉']\n"
]
}
],
"execution_count": 4
}, },
{ {
"metadata": {}, "metadata": {},
@@ -191,88 +137,20 @@
] ]
}, },
{ {
"metadata": { "metadata": {},
"ExecuteTime": {
"end_time": "2025-03-24T09:48:10.653252Z",
"start_time": "2025-03-24T09:48:10.646267Z"
}
},
"cell_type": "code", "cell_type": "code",
"outputs": [],
"execution_count": null,
"source": [ "source": [
"signup_session_id, set_signup_keypad = api.generate_signup_keypad(customer_id)\n", "username = random_username()\n",
"signup_session_id, set_signup_keypad = api.generate_signup_keypad(customer_id, username)\n",
"display(Markdown(\"\"\"### Icon Keypad\"\"\"))\n", "display(Markdown(\"\"\"### Icon Keypad\"\"\"))\n",
"keypad_view(user_icons[set_signup_keypad], keypad_size.numb_of_keys)\n", "keypad_view(user_icons[set_signup_keypad], keypad_size.numb_of_keys)\n",
"display(Markdown(\"\"\"### Index Keypad\"\"\"))\n", "display(Markdown(\"\"\"### Index Keypad\"\"\"))\n",
"keypad_view(set_signup_keypad, keypad_size.numb_of_keys)\n", "keypad_view(set_signup_keypad, keypad_size.numb_of_keys)\n",
"display(Markdown(\"\"\"### Customer Properties Keypad\"\"\"))\n", "display(Markdown(\"\"\"### Customer Properties Keypad\"\"\"))\n",
"keypad_view(customer.cipher.property_key[set_signup_keypad], keypad_size.numb_of_keys)" "keypad_view(customer.cipher.property_key[set_signup_keypad], keypad_size.numb_of_keys)"
], ]
"outputs": [
{
"data": {
"text/plain": [
"<IPython.core.display.Markdown object>"
],
"text/markdown": "### Icon Keypad"
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Key 0: ['😂' '🥳' '🐻' '🍕' '😎']\n",
"Key 1: ['🐶' '⚡' '🤖' '🥰' '🎉']\n",
"Key 2: ['🌟' '😇' '😍' '🤓' '🐙']\n",
"Key 3: ['😡' '😱' '🔥' '👽' '😴']\n",
"Key 4: ['🙃' '🦁' '🤯' '🐸' '👾']\n"
]
},
{
"data": {
"text/plain": [
"<IPython.core.display.Markdown object>"
],
"text/markdown": "### Index Keypad"
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Key 0: [ 1 2 21 28 5]\n",
"Key 1: [19 26 15 10 29]\n",
"Key 2: [25 14 3 4 23]\n",
"Key 3: [ 7 8 27 16 11]\n",
"Key 4: [13 20 9 22 17]\n"
]
},
{
"data": {
"text/plain": [
"<IPython.core.display.Markdown object>"
],
"text/markdown": "### Customer Properties Keypad"
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Key 0: [19687 10938 44350 7583 27050]\n",
"Key 1: [14898 21514 24111 6929 36157]\n",
"Key 2: [45848 62914 59248 5143 23249]\n",
"Key 3: [ 7431 59668 8782 36473 18710]\n",
"Key 4: [35476 1879 28699 53666 25394]\n"
]
}
],
"execution_count": 5
}, },
{ {
"metadata": {}, "metadata": {},
@@ -290,16 +168,6 @@
} }
}, },
"cell_type": "code", "cell_type": "code",
"source": [
"username = random_username()\n",
"passcode_len = 4\n",
"passcode_property_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len, replace=False).tolist()\n",
"selected_keys_set = select_keys_with_passcode_values(passcode_property_indices, set_signup_keypad, keypad_size.numb_of_keys)\n",
"print(f\"User Passcode Indices: {passcode_property_indices}\")\n",
"print(f\"User Passcode Icons: {user_icons[passcode_property_indices]}\")\n",
"print(f\"User Passcode Server-side properties: {customer.cipher.property_key[passcode_property_indices]}\")\n",
"print(f\"Selected Keys: {selected_keys_set}\")"
],
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
@@ -312,7 +180,16 @@
] ]
} }
], ],
"execution_count": 6 "execution_count": 6,
"source": [
"passcode_len = 4\n",
"passcode_property_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len, replace=False).tolist()\n",
"selected_keys_set = select_keys_with_passcode_values(passcode_property_indices, set_signup_keypad, keypad_size.numb_of_keys)\n",
"print(f\"User Passcode Indices: {passcode_property_indices}\")\n",
"print(f\"User Passcode Icons: {user_icons[passcode_property_indices]}\")\n",
"print(f\"User Passcode Server-side properties: {customer.cipher.property_key[passcode_property_indices]}\")\n",
"print(f\"Selected Keys: {selected_keys_set}\")"
]
}, },
{ {
"metadata": {}, "metadata": {},
@@ -331,11 +208,11 @@
}, },
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"confirm_keypad = api.set_nkode(username, customer_id, selected_keys_set, signup_session_id)\n", "confirm_keypad = api.set_nkode(customer_id, selected_keys_set, signup_session_id)\n",
"keypad_view(confirm_keypad, keypad_size.numb_of_keys)\n", "keypad_view(confirm_keypad, keypad_size.numb_of_keys)\n",
"selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad, keypad_size.numb_of_keys)\n", "selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad, keypad_size.numb_of_keys)\n",
"print(f\"Selected Keys\\n{selected_keys_confirm}\")\n", "print(f\"Selected Keys\\n{selected_keys_confirm}\")\n",
"success = api.confirm_nkode(username, customer_id, selected_keys_confirm, signup_session_id)\n", "success = api.confirm_nkode(customer_id, selected_keys_confirm, signup_session_id)\n",
"assert success" "assert success"
], ],
"outputs": [ "outputs": [

View File

@@ -0,0 +1,210 @@
{
"cells": [
{
"cell_type": "code",
"source": [
"import sys\n",
"import os\n",
"sys.path.append(os.path.abspath('..')) # Adds the parent directory to path\n",
"from src.nkode_api import NKodeAPI\n",
"from src.models import NKodePolicy, KeypadSize\n",
"from src.utils import select_keys_with_passcode_values\n",
"from secrets import choice\n",
"from string import ascii_lowercase\n",
"import numpy as np\n",
"\n",
"def random_username() -> str:\n",
" return \"test_username\" + \"\".join([choice(ascii_lowercase) for _ in range(6)])\n"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-24T20:18:04.947152Z",
"start_time": "2025-03-24T20:18:04.916604Z"
}
},
"outputs": [],
"execution_count": 1
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Initialize nKode API"
},
{
"cell_type": "code",
"source": [
"api = NKodeAPI()\n",
"policy = NKodePolicy(\n",
" max_nkode_len=10,\n",
" min_nkode_len=4,\n",
" distinct_positions=0,\n",
" distinct_properties=4,\n",
")\n",
"keypad_size = KeypadSize(\n",
" numb_of_keys = 5,\n",
" props_per_key = 6\n",
")\n",
"customer_id = api.create_new_customer(keypad_size, policy)\n",
"customer = api.get_customer(customer_id)"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-24T20:18:04.960698Z",
"start_time": "2025-03-24T20:18:04.950723Z"
}
},
"outputs": [],
"execution_count": 2
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## nKode Enrollment\n",
"Users enroll in three steps:\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-24T20:18:04.989029Z",
"start_time": "2025-03-24T20:18:04.986797Z"
}
},
"cell_type": "code",
"source": [
"username = random_username()\n",
"signup_session_id, set_signup_keypad = api.generate_signup_keypad(customer_id, username)"
],
"outputs": [],
"execution_count": 3
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### Set nKode\n",
"The client receives `user_icons`, `set_signup_keypad`\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-24T20:18:04.997252Z",
"start_time": "2025-03-24T20:18:04.995177Z"
}
},
"cell_type": "code",
"source": [
"passcode_len = 4\n",
"passcode_property_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len, replace=False).tolist()\n",
"selected_keys_set = select_keys_with_passcode_values(passcode_property_indices, set_signup_keypad, keypad_size.numb_of_keys)"
],
"outputs": [],
"execution_count": 4
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### Confirm nKode\n",
"Submit the set key entry to render the confirm keypad."
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-24T20:18:05.239384Z",
"start_time": "2025-03-24T20:18:05.002825Z"
}
},
"cell_type": "code",
"source": [
"confirm_keypad = api.set_nkode(username, customer_id, selected_keys_set, signup_session_id)\n",
"selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad, keypad_size.numb_of_keys)\n",
"success = api.confirm_nkode(username, customer_id, selected_keys_confirm, signup_session_id)\n",
"assert success"
],
"outputs": [],
"execution_count": 5
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### User Login\n",
"1. Get login keypad\n",
"2. Select keys with passcode icons (in our case, passcode property indices)\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-24T20:18:05.478978Z",
"start_time": "2025-03-24T20:18:05.245767Z"
}
},
"cell_type": "code",
"source": [
"login_keypad = api.get_login_keypad(username, customer_id)\n",
"selected_keys_login = select_keys_with_passcode_values(passcode_property_indices, login_keypad, keypad_size.props_per_key)\n",
"success = api.login(customer_id, username, selected_keys_login)\n",
"assert success"
],
"outputs": [],
"execution_count": 6
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## Renew Properties\n",
"1. Renew Customer Properties\n",
"2. Renew User Keys\n",
"3. Refresh User on Login\n",
"\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-24T20:18:05.950627Z",
"start_time": "2025-03-24T20:18:05.484941Z"
}
},
"cell_type": "code",
"source": [
"api.renew_keys(customer_id) # Steps 1 and 2\n",
"login_keypad = api.get_login_keypad(username, customer_id)\n",
"selected_keys_login = select_keys_with_passcode_values(passcode_property_indices, login_keypad, keypad_size.props_per_key)\n",
"success = api.login(customer_id, username, selected_keys_login) # Step 3\n",
"assert success"
],
"outputs": [],
"execution_count": 7
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -15,6 +15,9 @@ class NKodeAPI:
customers: dict[UUID, Customer] = field(default_factory=dict) customers: dict[UUID, Customer] = field(default_factory=dict)
signup_sessions: dict[UUID, UserSignupSession] = field(default_factory=dict) signup_sessions: dict[UUID, UserSignupSession] = field(default_factory=dict)
def get_customer(self, customer_id: UUID) -> Customer:
return self.customers[customer_id]
def create_new_customer(self, keypad_size: KeypadSize, nkode_policy: NKodePolicy) -> UUID: def create_new_customer(self, keypad_size: KeypadSize, nkode_policy: NKodePolicy) -> UUID:
new_customer = Customer.create( new_customer = Customer.create(
cipher=CustomerCipher.create(keypad_size), cipher=CustomerCipher.create(keypad_size),
@@ -23,13 +26,17 @@ class NKodeAPI:
self.customers[new_customer.customer_id] = new_customer self.customers[new_customer.customer_id] = new_customer
return new_customer.customer_id return new_customer.customer_id
def generate_signup_keypad(self, customer_id: UUID) -> tuple[UUID, np.ndarray]: def generate_signup_keypad(self, customer_id: UUID, username: str) -> tuple[UUID, np.ndarray]:
if customer_id not in self.customers.keys(): if customer_id not in self.customers.keys():
raise ValueError(f"Customer with ID '{customer_id}' does not exist") raise ValueError(f"Customer with ID '{customer_id}' does not exist")
customer = self.customers[customer_id] customer = self.customers[customer_id]
if username in customer.users.keys():
raise ValueError(f"Username '{username}' already exists for this customer")
customer = self.customers[customer_id]
login_keypad = UserKeypad.create(customer.cipher.keypad_size) login_keypad = UserKeypad.create(customer.cipher.keypad_size)
set_keypad = login_keypad.sign_up_keypad() set_keypad = login_keypad.sign_up_keypad()
new_session = UserSignupSession( new_session = UserSignupSession(
username=username,
session_id=uuid4(), session_id=uuid4(),
login_keypad=login_keypad, login_keypad=login_keypad,
set_keypad=set_keypad.keypad, set_keypad=set_keypad.keypad,
@@ -41,24 +48,20 @@ class NKodeAPI:
def set_nkode( def set_nkode(
self, self,
username: str,
customer_id: UUID, customer_id: UUID,
key_selection: list[int], key_selection: list[int],
session_id: UUID session_id: UUID
) -> np.ndarray: ) -> np.ndarray:
if customer_id not in self.customers.keys(): if customer_id not in self.customers.keys():
raise ValueError(f"Customer ID {customer_id} not found") raise ValueError(f"Customer ID {customer_id} not found")
customer = self.customers[customer_id]
if username in customer.users.keys():
raise ValueError(f"Username '{username}' already exists for this customer")
if session_id not in self.signup_sessions.keys(): if session_id not in self.signup_sessions.keys():
raise ValueError(f"Session ID {session_id} not found") raise ValueError(f"Session ID {session_id} not found")
self.signup_sessions[session_id].set_user_nkode(username, key_selection) session = self.signup_sessions[session_id]
self.signup_sessions[session_id].set_user_nkode(session.username, key_selection)
return self.signup_sessions[session_id].confirm_keypad return self.signup_sessions[session_id].confirm_keypad
def confirm_nkode( def confirm_nkode(
self, self,
username: str,
customer_id: UUID, customer_id: UUID,
confirm_key_entry: list[int], confirm_key_entry: list[int],
session_id: UUID session_id: UUID
@@ -68,8 +71,6 @@ class NKodeAPI:
session = self.signup_sessions[session_id] session = self.signup_sessions[session_id]
if customer_id != session.customer_id: if customer_id != session.customer_id:
raise AssertionError(f"Customer ID mismatch: {customer_id} vs {session.customer_id}") raise AssertionError(f"Customer ID mismatch: {customer_id} vs {session.customer_id}")
if username != session.username:
raise AssertionError(f"Username mismatch: {username} vs {session.username}")
customer = self.customers[customer_id] customer = self.customers[customer_id]
passcode = self.signup_sessions[session_id].deduce_passcode(confirm_key_entry) passcode = self.signup_sessions[session_id].deduce_passcode(confirm_key_entry)
new_user_keys = UserCipher.create( new_user_keys = UserCipher.create(
@@ -79,7 +80,7 @@ class NKodeAPI:
) )
enciphered_passcode = new_user_keys.encipher_nkode(passcode, customer.cipher) enciphered_passcode = new_user_keys.encipher_nkode(passcode, customer.cipher)
new_user = User( new_user = User(
username=username, username=session.username,
enciphered_passcode=enciphered_passcode, enciphered_passcode=enciphered_passcode,
cipher=new_user_keys, cipher=new_user_keys,
user_keypad=self.signup_sessions[session_id].login_keypad, user_keypad=self.signup_sessions[session_id].login_keypad,

View File

@@ -11,11 +11,10 @@ class UserSignupSession:
customer_id: UUID customer_id: UUID
login_keypad: UserKeypad login_keypad: UserKeypad
keypad_size: KeypadSize keypad_size: KeypadSize
# TODO: revert back to list[int] username: str
set_keypad: Optional[np.ndarray] = None set_keypad: Optional[np.ndarray] = None
confirm_keypad: Optional[np.ndarray] = None confirm_keypad: Optional[np.ndarray] = None
set_key_entry: Optional[np.ndarray] = None set_key_entry: Optional[np.ndarray] = None
username: Optional[str] = None
def deduce_passcode(self, confirm_key_entry: list[int]) -> list[int]: def deduce_passcode(self, confirm_key_entry: list[int]) -> list[int]:
if not all(0 <= key <= self.keypad_size.numb_of_keys for key in confirm_key_entry): if not all(0 <= key <= self.keypad_size.numb_of_keys for key in confirm_key_entry):

View File

@@ -15,20 +15,15 @@ def test_create_new_user_and_renew_keys(nkode_api, keypad_size, passcode_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_keypad = nkode_api.generate_signup_keypad(customer_id) session_id, set_keypad = nkode_api.generate_signup_keypad(customer_id, username)
user_passcode = set_keypad[:passcode_len] user_passcode = set_keypad[:passcode_len]
signup_key_selection = lambda keypad: [int(np.where(keypad == prop)[0][0]) // keypad_size.numb_of_keys for prop in user_passcode] signup_key_selection = lambda keypad: [int(np.where(keypad == prop)[0][0]) // keypad_size.numb_of_keys for prop in user_passcode]
set_key_selection = signup_key_selection(set_keypad) set_key_selection = signup_key_selection(set_keypad)
confirm_keypad = nkode_api.set_nkode(username, customer_id, set_key_selection, session_id) confirm_keypad = nkode_api.set_nkode(customer_id, set_key_selection, session_id)
confirm_key_selection = signup_key_selection(confirm_keypad) confirm_key_selection = signup_key_selection(confirm_keypad)
successful_confirm = nkode_api.confirm_nkode( successful_confirm = nkode_api.confirm_nkode(customer_id, confirm_key_selection, session_id)
username,
customer_id,
confirm_key_selection,
session_id
)
assert successful_confirm assert successful_confirm
sign_in_key_selection = lambda keypad: [int(np.where(keypad ==prop)[0][0]) // keypad_size.props_per_key for prop in user_passcode] sign_in_key_selection = lambda keypad: [int(np.where(keypad ==prop)[0][0]) // keypad_size.props_per_key for prop in user_passcode]