From cfef58613c9cb377b7a415a03af815895984d84f Mon Sep 17 00:00:00 2001 From: Donovan Date: Mon, 17 Mar 2025 09:58:28 -0500 Subject: [PATCH] fix bugs --- docs/render_readme.py | 9 +- notebooks/nkode_tutorial.ipynb | 276 ++++++++++++++++----------------- src/customer.py | 24 +-- src/models.py | 4 +- src/nkode_api.py | 5 +- src/user_cipher.py | 3 +- src/user_keypad.py | 31 ++-- src/user_signup_session.py | 1 + test/test_nkode_api.py | 2 - 9 files changed, 170 insertions(+), 185 deletions(-) diff --git a/docs/render_readme.py b/docs/render_readme.py index df4551c..b33f7af 100644 --- a/docs/render_readme.py +++ b/docs/render_readme.py @@ -145,14 +145,7 @@ if __name__ == "__main__": """ set_vals_idx = [customer.cipher.get_set_index(set_val) for set_val in login_passcode_sets] - - presumed_selected_properties_idx = [] - for idx in range(passcode_len): - key_numb = selected_keys_login[idx] - set_idx = set_vals_idx[idx] - selected_prop_idx = customer.users[username].user_keypad.get_prop_idx_by_keynumb_setidx(key_numb, set_idx) - presumed_selected_properties_idx.append(selected_prop_idx) - + presumed_selected_properties_idx = customer.users[username].user_keypad.get_prop_idxs_by_keynumb_setidx(selected_keys_login, set_vals_idx) """ RENEW KEYS """ diff --git a/notebooks/nkode_tutorial.ipynb b/notebooks/nkode_tutorial.ipynb index b67acaa..c396758 100644 --- a/notebooks/nkode_tutorial.ipynb +++ b/notebooks/nkode_tutorial.ipynb @@ -13,12 +13,12 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.430038Z", - "start_time": "2025-03-16T12:51:50.426267Z" + "end_time": "2025-03-17T14:56:54.677924Z", + "start_time": "2025-03-17T14:56:54.674055Z" } }, "outputs": [], - "execution_count": 17 + "execution_count": 52 }, { "cell_type": "code", @@ -33,7 +33,7 @@ "\n", "\n", "def keypad_view(keypad: np.ndarray, props_per_key: int):\n", - " print(\"Keypad View\")\n", + " print(\"\\nKeypad View\")\n", " interface_keypad = keypad.reshape(-1, props_per_key)\n", " for idx, key_vals in enumerate(interface_keypad):\n", " print(f\"Key {idx}: {key_vals}\")\n" @@ -41,12 +41,12 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.441672Z", - "start_time": "2025-03-16T12:51:50.437979Z" + "end_time": "2025-03-17T14:56:54.687467Z", + "start_time": "2025-03-17T14:56:54.683811Z" } }, "outputs": [], - "execution_count": 18 + "execution_count": 53 }, { "cell_type": "code", @@ -56,12 +56,12 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.451921Z", - "start_time": "2025-03-16T12:51:50.449896Z" + "end_time": "2025-03-17T14:56:54.698258Z", + "start_time": "2025-03-17T14:56:54.696478Z" } }, "outputs": [], - "execution_count": 19 + "execution_count": 54 }, { "cell_type": "markdown", @@ -101,12 +101,12 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.462932Z", - "start_time": "2025-03-16T12:51:50.458899Z" + "end_time": "2025-03-17T14:56:54.710370Z", + "start_time": "2025-03-17T14:56:54.706283Z" } }, "outputs": [], - "execution_count": 20 + "execution_count": 55 }, { "cell_type": "markdown", @@ -139,8 +139,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.471838Z", - "start_time": "2025-03-16T12:51:50.469241Z" + "end_time": "2025-03-17T14:56:54.735642Z", + "start_time": "2025-03-17T14:56:54.732921Z" } }, "outputs": [ @@ -148,17 +148,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "Customer Set Key: [29252 55146 27501 36339 61988 56812]\n", + "Customer Set Key: [15749 12291 52872 49860 5208 28289]\n", "Customer Properties Key:\n", - "[58958 438 23479 56544 19227 62335]\n", - "[19972 45333 49189 28952 25210 7101]\n", - "[27924 36712 27932 6192 11310 25890]\n", - "[41961 42300 62264 30572 21755 25167]\n", - "[56659 59117 55559 18611 58570 62570]\n" + "[42849 39396 49203 20824 30786 27252]\n", + "[16470 25626 64566 34252 23582 48009]\n", + "[20454 51880 19394 58106 12995 59391]\n", + "[43703 4483 7702 5423 24081 57678]\n", + "[43822 27495 59095 24249 60164 21395]\n" ] } ], - "execution_count": 21 + "execution_count": 56 }, { "cell_type": "markdown", @@ -178,8 +178,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.482832Z", - "start_time": "2025-03-16T12:51:50.480624Z" + "end_time": "2025-03-17T14:56:54.781223Z", + "start_time": "2025-03-17T14:56:54.778381Z" } }, "outputs": [ @@ -188,16 +188,16 @@ "output_type": "stream", "text": [ "Set to Properties Map:\n", - "29252: [58958 19972 27924 41961 56659]\n", - "55146: [ 438 45333 36712 42300 59117]\n", - "27501: [23479 49189 27932 62264 55559]\n", - "36339: [56544 28952 6192 30572 18611]\n", - "61988: [19227 25210 11310 21755 58570]\n", - "56812: [62335 7101 25890 25167 62570]\n" + "15749: [42849 16470 20454 43703 43822]\n", + "12291: [39396 25626 51880 4483 27495]\n", + "52872: [49203 64566 19394 7702 59095]\n", + "49860: [20824 34252 58106 5423 24249]\n", + "5208: [30786 23582 12995 24081 60164]\n", + "28289: [27252 48009 59391 57678 21395]\n" ] } ], - "execution_count": 22 + "execution_count": 57 }, { "metadata": {}, @@ -221,8 +221,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.496968Z", - "start_time": "2025-03-16T12:51:50.494830Z" + "end_time": "2025-03-17T14:56:54.814781Z", + "start_time": "2025-03-17T14:56:54.812317Z" } }, "cell_type": "code", @@ -235,15 +235,15 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[10 4 22 16 28]\n", - " [11 5 23 17 29]\n", - " [ 9 3 21 15 27]\n", - " [ 8 2 20 14 26]\n", - " [ 7 1 19 13 25]]\n" + "[[24 7 2 3 29]\n", + " [12 13 26 9 11]\n", + " [ 6 1 8 15 23]\n", + " [ 0 25 20 21 5]\n", + " [18 19 14 27 17]]\n" ] } ], - "execution_count": 23 + "execution_count": 58 }, { "metadata": {}, @@ -261,8 +261,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.521411Z", - "start_time": "2025-03-16T12:51:50.518203Z" + "end_time": "2025-03-17T14:56:54.845027Z", + "start_time": "2025-03-17T14:56:54.840926Z" } }, "cell_type": "code", @@ -282,26 +282,27 @@ "name": "stdout", "output_type": "stream", "text": [ + "\n", "Keypad View\n", - "Key 0: [10 4 22 16 28]\n", - "Key 1: [11 5 23 17 29]\n", - "Key 2: [ 9 3 21 15 27]\n", - "Key 3: [ 8 2 20 14 26]\n", - "Key 4: [ 7 1 19 13 25]\n", - "User Passcode: [10 4 22 16]\n", + "Key 0: [24 7 2 3 29]\n", + "Key 1: [12 13 26 9 11]\n", + "Key 2: [ 6 1 8 15 23]\n", + "Key 3: [ 0 25 20 21 5]\n", + "Key 4: [18 19 14 27 17]\n", + "User Passcode: [24 7 2 3]\n", "Selected Keys\n", "[0, 0, 0, 0]\n", - "User Passcode Server-side properties: [25210, 19227, 21755, 11310]\n" + "User Passcode Server-side properties: [43822, 25626, 49203, 20824]\n" ] } ], - "execution_count": 24 + "execution_count": 59 }, { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.539870Z", - "start_time": "2025-03-16T12:51:50.536979Z" + "end_time": "2025-03-17T14:56:54.869735Z", + "start_time": "2025-03-17T14:56:54.866365Z" } }, "cell_type": "code", @@ -316,42 +317,35 @@ "name": "stdout", "output_type": "stream", "text": [ + "\n", "Keypad View\n", - "Key 0: [ 7 2 22 15 29]\n", - "Key 1: [ 9 4 23 14 25]\n", - "Key 2: [ 8 5 19 16 27]\n", - "Key 3: [10 1 21 17 26]\n", - "Key 4: [11 3 20 13 28]\n", + "Key 0: [24 13 20 15 17]\n", + "Key 1: [ 6 7 14 21 11]\n", + "Key 2: [ 0 1 26 27 29]\n", + "Key 3: [18 25 2 9 23]\n", + "Key 4: [12 19 8 3 5]\n", "Selected Keys\n", - "[3, 1, 0, 2]\n" + "[0, 1, 3, 4]\n" ] } ], - "execution_count": 25 + "execution_count": 60 }, { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.790192Z", - "start_time": "2025-03-16T12:51:50.552031Z" + "end_time": "2025-03-17T14:56:55.202903Z", + "start_time": "2025-03-17T14:56:54.894565Z" } }, "cell_type": "code", "source": [ "# the session is deleted after the nkode is confirmed. To rerun this cell, rerun the cells above starting with cell 8 where the username is created\n", "success = api.confirm_nkode(username, customer_id, selected_keys_confirm, session_id)\n", - "print(success)" + "assert success" ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n" - ] - } - ], - "execution_count": 26 + "outputs": [], + "execution_count": 61 }, { "metadata": {}, @@ -370,8 +364,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.801004Z", - "start_time": "2025-03-16T12:51:50.797001Z" + "end_time": "2025-03-17T14:56:55.227304Z", + "start_time": "2025-03-17T14:56:55.222844Z" } }, "cell_type": "code", @@ -405,12 +399,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Passcode Set Vals: [61988, 61988, 61988, 61988]\n", - "Passcode Prop Vals: [25210 19227 21755 11310]\n" + "Passcode Set Vals: [15749, 12291, 52872, 49860]\n", + "Passcode Prop Vals: [43822 25626 49203 20824]\n" ] } ], - "execution_count": 27 + "execution_count": 62 }, { "metadata": {}, @@ -431,8 +425,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:50.811181Z", - "start_time": "2025-03-16T12:51:50.808721Z" + "end_time": "2025-03-17T14:56:55.260751Z", + "start_time": "2025-03-17T14:56:55.258152Z" } }, "cell_type": "code", @@ -444,7 +438,7 @@ "encoded_mask = user_keys.encode_base64_str(mask)" ], "outputs": [], - "execution_count": 28 + "execution_count": 63 }, { "metadata": {}, @@ -461,14 +455,12 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:51.058527Z", - "start_time": "2025-03-16T12:51:50.823135Z" + "end_time": "2025-03-17T14:56:55.590495Z", + "start_time": "2025-03-17T14:56:55.285097Z" } }, "cell_type": "code", "source": [ - "import hashlib\n", - "import base64\n", "ciphered_customer_props = np.bitwise_xor(customer.cipher.prop_key, user_keys.prop_key)\n", "passcode_ciphered_props = [ciphered_customer_props[idx] for idx in user_passcode]\n", "pad_len = customer.nkode_policy.max_nkode_len - passcode_len\n", @@ -483,13 +475,13 @@ "code = hashed_data.decode(\"utf-8\")" ], "outputs": [], - "execution_count": 29 + "execution_count": 64 }, { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:51.063978Z", - "start_time": "2025-03-16T12:51:51.061965Z" + "end_time": "2025-03-17T14:56:55.595860Z", + "start_time": "2025-03-17T14:56:55.593975Z" } }, "cell_type": "code", @@ -502,7 +494,7 @@ ")" ], "outputs": [], - "execution_count": 30 + "execution_count": 65 }, { "metadata": {}, @@ -516,8 +508,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:51.305419Z", - "start_time": "2025-03-16T12:51:51.071190Z" + "end_time": "2025-03-17T14:56:55.910640Z", + "start_time": "2025-03-17T14:56:55.605472Z" } }, "cell_type": "code", @@ -525,27 +517,32 @@ "login_keypad = api.get_login_keypad(username, customer_id)\n", "keypad_view(login_keypad, keypad_size.props_per_key)\n", "selected_keys_login = select_keys_with_passcode_values(user_passcode, login_keypad, keypad_size.props_per_key)\n", - "print(f\"Selected Keys: {selected_keys_login}\")\n", + "print(f\"User Passcode: {user_passcode}\\n\")\n", + "print(f\"Selected Keys:\\n {selected_keys_login}\\n\")\n", "success = api.login(customer_id, username, selected_keys_login)\n", - "print(success)" + "assert success" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "\n", "Keypad View\n", - "Key 0: [ 6 7 8 9 10 11]\n", - "Key 1: [0 1 2 3 4 5]\n", - "Key 2: [18 19 20 21 22 23]\n", - "Key 3: [12 13 14 15 16 17]\n", - "Key 4: [24 25 26 27 28 29]\n", - "Selected Keys: [0, 1, 2, 3]\n", - "True\n" + "Key 0: [24 7 2 3 28 29]\n", + "Key 1: [12 13 26 9 16 11]\n", + "Key 2: [ 6 1 8 15 10 23]\n", + "Key 3: [ 0 25 20 21 22 5]\n", + "Key 4: [18 19 14 27 4 17]\n", + "User Passcode: [24 7 2 3]\n", + "\n", + "Selected Keys:\n", + " [0, 0, 0, 0]\n", + "\n" ] } ], - "execution_count": 31 + "execution_count": 66 }, { "metadata": {}, @@ -577,8 +574,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:51.315072Z", - "start_time": "2025-03-16T12:51:51.312249Z" + "end_time": "2025-03-17T14:56:55.922451Z", + "start_time": "2025-03-17T14:56:55.919172Z" } }, "cell_type": "code", @@ -598,11 +595,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "[61988, 61988, 61988, 61988]\n" + "[15749, 12291, 52872, 49860]\n" ] } ], - "execution_count": 32 + "execution_count": 67 }, { "metadata": {}, @@ -612,33 +609,29 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:51.324331Z", - "start_time": "2025-03-16T12:51:51.321676Z" + "end_time": "2025-03-17T14:56:55.943804Z", + "start_time": "2025-03-17T14:56:55.940721Z" } }, "cell_type": "code", "source": [ + "login_keypad = api.get_login_keypad(username, customer_id)\n", + "selected_keys_login = select_keys_with_passcode_values(user_passcode, login_keypad, keypad_size.props_per_key)\n", "set_vals_idx = [customer.cipher.get_set_index(set_val) for set_val in passcode_sets]\n", - "\n", - "presumed_selected_properties_idx = []\n", - "for idx in range(passcode_len):\n", - " key_numb = selected_keys_login[idx]\n", - " set_idx = set_vals_idx[idx]\n", - " selected_prop_idx = customer.users[username].user_keypad.get_prop_idx_by_keynumb_setidx(key_numb, set_idx)\n", - " presumed_selected_properties_idx.append(selected_prop_idx)\n", - "\n", - "print(user_passcode.tolist() == presumed_selected_properties_idx)" + "presumed_selected_properties_idx = customer.users[username].user_keypad.get_prop_idxs_by_keynumb_setidx(selected_keys_login, set_vals_idx)\n", + "assert user_passcode.tolist() == presumed_selected_properties_idx" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "True\n" + "[24, 7, 2, 3]\n", + "[24, 7, 2, 3]\n" ] } ], - "execution_count": 33 + "execution_count": 68 }, { "metadata": {}, @@ -648,25 +641,17 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:51.571291Z", - "start_time": "2025-03-16T12:51:51.338129Z" + "end_time": "2025-03-17T14:56:56.297835Z", + "start_time": "2025-03-17T14:56:55.992586Z" } }, "cell_type": "code", "source": [ "enciphered_nkode = user.cipher.compare_nkode(presumed_selected_properties_idx, customer.cipher, user.enciphered_passcode.code)\n", - "print(enciphered_nkode)\n" + "assert enciphered_nkode\n" ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n" - ] - } - ], - "execution_count": 34 + "outputs": [], + "execution_count": 69 }, { "metadata": {}, @@ -682,8 +667,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:52.048827Z", - "start_time": "2025-03-16T12:51:51.579003Z" + "end_time": "2025-03-17T14:56:56.923156Z", + "start_time": "2025-03-17T14:56:56.306667Z" } }, "cell_type": "code", @@ -700,7 +685,7 @@ "login_keypad = api.get_login_keypad(username, customer_id)\n", "selected_keys_login = select_keys_with_passcode_values(user_passcode, login_keypad, keypad_size.props_per_key)\n", "success = api.login(customer_id, username, selected_keys_login)\n", - "print(success)\n", + "assert success\n", "print_user_enciphered_code()" ], "outputs": [ @@ -708,14 +693,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "mask: 8T1ZD3B2c6v+ofoNRIzBbqxVYFw=, code: $2b$12$lAmbDegOx03xLmrB//ZCh.1dyrjtpEmAdv1TWNUO/XjjPofQItzVq\n", - "mask: 8T1ZD3B2c6v+ofoNRIzBbqxVYFw=, code: $2b$12$lAmbDegOx03xLmrB//ZCh.1dyrjtpEmAdv1TWNUO/XjjPofQItzVq\n", - "True\n", - "mask: rY763sxEo+aU8G2h7Avf9btV0h8=, code: $2b$12$ZB.x5hSFVjDg4niUAL7TsOtwkTG2uXedMsnFqXNjm0Y0SDf5fgOui\n" + "mask: h7xMhd4kK3faZ6C1Ofi+oVjSI4c=, code: $2b$12$/wwEjbTk90oCnD2Ny6KTWeNJ6YPEyc9yJgY00FGddkQ8cE4LNkSvK\n", + "mask: h7xMhd4kK3faZ6C1Ofi+oVjSI4c=, code: $2b$12$/wwEjbTk90oCnD2Ny6KTWeNJ6YPEyc9yJgY00FGddkQ8cE4LNkSvK\n", + "mask: nzxGInaKD4KfAP9Djc4tz6ROuko=, code: $2b$12$PZ6j.Ccq8/LEWpht4Bnw1.JLXS0dMrgpzBLsnPA33ND7BjsT3CqxW\n" ] } ], - "execution_count": 35 + "execution_count": 70 }, { "metadata": {}, @@ -729,8 +713,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:52.059119Z", - "start_time": "2025-03-16T12:51:52.055816Z" + "end_time": "2025-03-17T14:56:56.935444Z", + "start_time": "2025-03-17T14:56:56.931244Z" } }, "cell_type": "code", @@ -742,7 +726,7 @@ "new_sets = customer.cipher.set_key" ], "outputs": [], - "execution_count": 36 + "execution_count": 71 }, { "metadata": {}, @@ -755,8 +739,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:52.068302Z", - "start_time": "2025-03-16T12:51:52.065921Z" + "end_time": "2025-03-17T14:56:56.954373Z", + "start_time": "2025-03-17T14:56:56.952101Z" } }, "cell_type": "code", @@ -769,7 +753,7 @@ " user.cipher.prop_key = np.bitwise_xor(user.cipher.prop_key, props_xor)" ], "outputs": [], - "execution_count": 37 + "execution_count": 72 }, { "metadata": {}, @@ -779,8 +763,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-03-16T12:51:52.311112Z", - "start_time": "2025-03-16T12:51:52.074783Z" + "end_time": "2025-03-17T14:56:57.298001Z", + "start_time": "2025-03-17T14:56:56.988801Z" } }, "cell_type": "code", @@ -794,7 +778,7 @@ "user.renew = False" ], "outputs": [], - "execution_count": 38 + "execution_count": 73 } ], "metadata": { diff --git a/src/customer.py b/src/customer.py index cb65199..196d1fe 100644 --- a/src/customer.py +++ b/src/customer.py @@ -1,6 +1,5 @@ from dataclasses import dataclass -from uuid import UUID -import numpy as np +from uuid import UUID, uuid4 from src.customer_cipher import CustomerCipher from src.models import NKodePolicy from src.user import User @@ -12,7 +11,18 @@ class Customer: cipher: CustomerCipher users: dict[str, User] - # TODO: validate policy and keypad_list size don't conflict + @classmethod + def create(cls, nkode_policy: NKodePolicy, cipher: CustomerCipher) -> 'Customer': + if nkode_policy.distinct_sets > cipher.keypad_size.numb_of_keys: + raise ValueError("Distinct sets cannot be greater than the number of keys") + if nkode_policy.distinct_properties > cipher.keypad_size.total_props: + raise ValueError("Distinct properties cannot be greater than the total number of properties") + return Customer( + customer_id=uuid4(), + nkode_policy=nkode_policy, + cipher=cipher, + users={} + ) def add_new_user(self, user: User): if user.username in self.users: @@ -30,17 +40,13 @@ class Customer: passcode_set_vals = user.cipher.decipher_mask( user.enciphered_passcode.mask, self.cipher.set_key, passcode_len) set_vals_idx = [self.cipher.get_set_index(set_val) for set_val in passcode_set_vals] - presumed_property_idxs = [] - for idx in range(passcode_len): - key_numb = selected_keys[idx] - set_idx = set_vals_idx[idx] - selected_prop_idx = user.user_keypad.get_prop_idx_by_keynumb_setidx(key_numb, set_idx) - presumed_property_idxs.append(selected_prop_idx) + presumed_property_idxs = user.user_keypad.get_prop_idxs_by_keynumb_setidx(selected_keys, set_vals_idx) if not user.cipher.compare_nkode(presumed_property_idxs, self.cipher,user.enciphered_passcode.code): return False if user.renew: user.refresh_passcode(presumed_property_idxs, self.cipher) user.user_keypad.split_shuffle() + #self.users[username] = user return True def renew_keys(self) -> bool: diff --git a/src/models.py b/src/models.py index afef20e..b3143e4 100644 --- a/src/models.py +++ b/src/models.py @@ -12,9 +12,9 @@ class NKodePolicy: min_nkode_len: int = 4 distinct_sets: int = 0 distinct_properties: int = 4 - byte_len: int = 2 # Todo: this should change the total number of bytes an properities or set value can be + byte_len: int = 2 # Todo: this should change the total number of bytes an properties or set value can be lock_out: int = 5 - expiration: int = -1 # in seconds -1 means nkode never expires + expiration: int = -1 # in seconds -1 means nKode never expires @dataclass diff --git a/src/nkode_api.py b/src/nkode_api.py index 318b580..a9f74a9 100644 --- a/src/nkode_api.py +++ b/src/nkode_api.py @@ -16,10 +16,8 @@ class NKodeAPI: signup_sessions: dict[UUID, UserSignupSession] = field(default_factory=dict) def create_new_customer(self, keypad_size: KeypadSize, nkode_policy: NKodePolicy) -> UUID: - new_customer = Customer( - customer_id=uuid4(), + new_customer = Customer.create( cipher=CustomerCipher.create(keypad_size), - users={}, nkode_policy=nkode_policy ) self.customers[new_customer.customer_id] = new_customer @@ -97,7 +95,6 @@ class NKodeAPI: if username not in customer.users.keys(): raise ValueError("Username not found") user = customer.users[username] - # user.user_keypad.partial_keypad_shuffle() # TODO: implement split_keypad_shuffle() return user.user_keypad.keypad diff --git a/src/user_cipher.py b/src/user_cipher.py index 1136d22..da49c16 100644 --- a/src/user_cipher.py +++ b/src/user_cipher.py @@ -105,8 +105,7 @@ class UserCipher: customer_props = customer_cipher.prop_key[passcode_prop_idx] customer_sets = [customer_cipher.get_prop_set_val(prop) for prop in customer_props] padded_customer_sets = self.pad_user_mask(np.array(customer_sets), customer_cipher.set_key) - set_idx = np.array([customer_cipher.get_set_index(set_val) for set_val in padded_customer_sets], - dtype=np.uint16) + set_idx = [customer_cipher.get_set_index(set_val) for set_val in padded_customer_sets] ordered_set_key = self.combined_set_key[set_idx] mask = ordered_set_key ^ padded_customer_sets ^ self.mask_key encoded_mask = self.encode_base64_str(mask) diff --git a/src/user_keypad.py b/src/user_keypad.py index da0d750..65bc21e 100644 --- a/src/user_keypad.py +++ b/src/user_keypad.py @@ -23,11 +23,11 @@ class UserKeypad: self.random_keypad_shuffle() keypad_matrix = self.keypad_matrix() prop_set_view = keypad_matrix.T - prop_set_view = np.random.permutation(prop_set_view) - prop_set_view = prop_set_view[:self.keypad_size.numb_of_keys] - keypad_matrix = prop_set_view.reshape(-1) + random_sets = np.random.permutation(self.keypad_size.props_per_key)[: self.keypad_size.numb_of_keys] + random_sets.sort() + prop_set_view = prop_set_view[random_sets, :] return UserKeypad( - keypad=keypad_matrix.reshape(-1), + keypad=prop_set_view.T.reshape(-1), keypad_size=KeypadSize( numb_of_keys=self.keypad_size.numb_of_keys, props_per_key=self.keypad_size.numb_of_keys @@ -38,23 +38,20 @@ class UserKeypad: return self.keypad.reshape(-1,self.keypad_size.props_per_key) def random_keypad_shuffle(self): - rng = np.random.default_rng() keypad_view = self.keypad_matrix() - rng.shuffle(keypad_view, axis=0) + np.random.shuffle(keypad_view) set_view = keypad_view.T - set_view = rng.permutation(set_view, axis=1) - keypad_view = set_view.T - self.keypad = keypad_view.reshape(-1) + for prop_set in set_view: + np.random.shuffle(prop_set) + self.keypad = set_view.T.reshape(-1) def disperse_keypad(self): + # TODO: clean this up if not self.keypad_size.is_dispersable: raise ValueError("Keypad size is not dispersable") rng = np.random.default_rng() - #user_keypad_matrix = list_to_matrix(self.keypad, self.keypad_size.props_per_key) user_keypad_matrix = self.keypad_matrix() - #shuffled_keys = secure_fisher_yates_shuffle(user_keypad_matrix) shuffled_keys = rng.permutation(user_keypad_matrix, axis=0) - #prop_rotation = secure_fisher_yates_shuffle(list(range(self.keypad_size.numb_of_keys)))[:self.keypad_size.props_per_key] prop_rotation = rng.permutation(list(range(self.keypad_size.numb_of_keys)))[:self.keypad_size.props_per_key] dispersed_keypad = random_property_rotation( shuffled_keys, @@ -89,3 +86,13 @@ class UserKeypad: raise ValueError(f"set_idx must be between 0 and {self.keypad_size.props_per_key - 1}") keypad_prop_idx = self.keypad_matrix() return int(keypad_prop_idx[key_numb][set_idx]) + + def get_prop_idxs_by_keynumb_setidx(self, key_numb: list[int], set_idx: list[int]) -> list[int]: + if len(key_numb) != len(set_idx): + raise ValueError("key_numb and set_idx must be the same length") + if not all(0 <= kn < self.keypad_size.numb_of_keys for kn in key_numb): + raise ValueError(f"All key_numb must be between 0 and {self.keypad_size.numb_of_keys - 1}") + if not all(0 <= si < self.keypad_size.props_per_key for si in set_idx): + raise ValueError(f"All set_idx must be between 0 and {self.keypad_size.props_per_key - 1}") + keypad_matrix = self.keypad_matrix() + return keypad_matrix[key_numb, set_idx].reshape(-1).tolist() diff --git a/src/user_signup_session.py b/src/user_signup_session.py index 25cb835..887ec38 100644 --- a/src/user_signup_session.py +++ b/src/user_signup_session.py @@ -11,6 +11,7 @@ class UserSignupSession: customer_id: UUID login_keypad: UserKeypad keypad_size: KeypadSize + # TODO: revert back to list[int] set_keypad: Optional[np.ndarray] = None confirm_keypad: Optional[np.ndarray] = None set_key_entry: Optional[np.ndarray] = None diff --git a/test/test_nkode_api.py b/test/test_nkode_api.py index d2be679..63332fd 100644 --- a/test/test_nkode_api.py +++ b/test/test_nkode_api.py @@ -3,12 +3,10 @@ import pytest from src.nkode_api import NKodeAPI from src.models import NKodePolicy, KeypadSize - @pytest.fixture() def nkode_api() -> NKodeAPI: return NKodeAPI() - @pytest.mark.parametrize("keypad_size,passcode_len", [ (KeypadSize(numb_of_keys=10, props_per_key=11), 4), (KeypadSize(numb_of_keys=10, props_per_key=12), 5),