diff --git a/node/inference/ollama/.gitkeep b/node/inference/ollama/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/node/storage/hub/data_structures/auth.surql b/node/storage/hub/data_structures/auth.surql index 81adc2bd..42694fba 100644 --- a/node/storage/hub/data_structures/auth.surql +++ b/node/storage/hub/data_structures/auth.surql @@ -8,6 +8,7 @@ DEFINE SCOPE user SESSION 7d username: $username, password: crypto::argon2::generate($password), public_key: $public_key, + address: $address, id: $public_key } ) diff --git a/node/storage/hub/data_structures/user.surql b/node/storage/hub/data_structures/user.surql index f514e3bc..81326ecf 100644 --- a/node/storage/hub/data_structures/user.surql +++ b/node/storage/hub/data_structures/user.surql @@ -9,6 +9,7 @@ DEFINE FIELD password ON user TYPE string PERMISSIONS FOR select NONE PERMISSIONS FOR select, update, delete WHERE id = $auth.id; DEFINE FIELD public_key ON user TYPE string; +DEFINE FIELD address ON user TYPE string; DEFINE FIELD created ON user VALUE $before OR time::now() @@ -23,6 +24,7 @@ DEFINE FIELD updated ON user DEFINE INDEX unique_username ON user FIELDS username UNIQUE; DEFINE INDEX unique_public_key ON user FIELDS public_key UNIQUE; +DEFINE INDEX unique_address ON user FIELDS address UNIQUE; DEFINE EVENT removal ON user WHEN $event = "DELETE" THEN { DELETE job WHERE consumer_id = $before.id; diff --git a/node/storage/hub/hub.py b/node/storage/hub/hub.py index 0444d3a1..8c653b80 100644 --- a/node/storage/hub/hub.py +++ b/node/storage/hub/hub.py @@ -3,6 +3,7 @@ import logging from node.utils import AsyncMixin from node.schemas import Module, NodeConfig, NodeServer +from node.user import generate_address import os from surrealdb import Surreal import traceback @@ -65,6 +66,7 @@ async def signin( self.user_id = self._decode_token(user) self.token = user self.is_authenticated = True + await self.check_and_update_address(self.user_id) return True, user, self.user_id except Exception as e: logger.error(f"Sign in failed: {e}") @@ -83,12 +85,31 @@ async def signup( "username": username, "password": password, "public_key": public_key, + "address": generate_address(bytes.fromhex(public_key)) } ) if not user: return False, None, None self.user_id = self._decode_token(user) return True, user, self.user_id + + async def check_and_update_address(self, user_id: str) -> None: + user = await self.get_user(user_id) + + # Check if the address is empty or None + if not user.get("address"): + logger.info("User address not found") + logger.info("Updating address....") + + # Generate the address and update the record + user["address"] = generate_address(bytes.fromhex(user["public_key"])) + try: + await self.surrealdb.update(user.pop('id'), user) + logger.info("Address updated successfully") + except Exception as e: + logger.error(f"Failed to update address: {e}") + else: + logger.info("User address found, moving on.....") async def get_user(self, user_id: str) -> Optional[Dict]: return await self.surrealdb.select(user_id) diff --git a/node/user.py b/node/user.py index 5623bac8..f9507aec 100644 --- a/node/user.py +++ b/node/user.py @@ -6,6 +6,7 @@ file_path = Path(__file__).resolve() root_path = file_path.parent.parent +from eth_hash.auto import keccak logger = logging.getLogger(__name__) @@ -94,4 +95,13 @@ def verify_signature(consumer_id, signature_hex, public_key_hex): if public_key.verify(signature, consumer_id_bytes): return True except: - return False \ No newline at end of file + return False + +def generate_address(public_key: bytes) -> str: + if len(public_key) not in [64, 33]: + print(public_key) + raise ValueError("Public key must be either 33 or 64 bytes long.") + + hash = keccak(public_key) + address = hash[-20:] + return "0x" + address.hex() diff --git a/poetry.lock b/poetry.lock index 2ab7834a..cb4b5aa8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -979,6 +979,27 @@ six = ">=1.9.0" gmpy = ["gmpy"] gmpy2 = ["gmpy2"] +[[package]] +name = "eth-hash" +version = "0.7.0" +description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-hash-0.7.0.tar.gz", hash = "sha256:bacdc705bfd85dadd055ecd35fd1b4f846b671add101427e089a4ca2e8db310a"}, + {file = "eth_hash-0.7.0-py3-none-any.whl", hash = "sha256:b8d5a230a2b251f4a291e3164a23a14057c4a6de4b0aa4a16fa4dc9161b57e2f"}, +] + +[package.dependencies] +pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +pycryptodome = ["pycryptodome (>=3.6.6,<4)"] +pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + [[package]] name = "executing" version = "2.2.0" @@ -2464,6 +2485,47 @@ files = [ ] markers = {main = "sys_platform == \"linux\" and platform_python_implementation != \"PyPy\" or sys_platform == \"darwin\"", dev = "implementation_name == \"pypy\""} +[[package]] +name = "pycryptodome" +version = "3.21.0" +description = "Cryptographic library for Python" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pycryptodome-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ba4cc304eac4d4d458f508d4955a88ba25026890e8abff9b60404f76a62c55e"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb087b8612c8a1a14cf37dd754685be9a8d9869bed2ffaaceb04850a8aeef7e"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:26412b21df30b2861424a6c6d5b1d8ca8107612a4cfa4d0183e71c5d200fb34a"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-win32.whl", hash = "sha256:cc2269ab4bce40b027b49663d61d816903a4bd90ad88cb99ed561aadb3888dd3"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-win_amd64.whl", hash = "sha256:0fa0a05a6a697ccbf2a12cec3d6d2650b50881899b845fac6e87416f8cb7e87d"}, + {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6cce52e196a5f1d6797ff7946cdff2038d3b5f0aba4a43cb6bf46b575fd1b5bb"}, + {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a915597ffccabe902e7090e199a7bf7a381c5506a747d5e9d27ba55197a2c568"}, + {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e74c522d630766b03a836c15bff77cb657c5fdf098abf8b1ada2aebc7d0819"}, + {file = "pycryptodome-3.21.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:a3804675283f4764a02db05f5191eb8fec2bb6ca34d466167fc78a5f05bbe6b3"}, + {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4"}, + {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b"}, + {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e"}, + {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8"}, + {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1"}, + {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a"}, + {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2"}, + {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93"}, + {file = "pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764"}, + {file = "pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53"}, + {file = "pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca"}, + {file = "pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd"}, + {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8"}, + {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6"}, + {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0"}, + {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6"}, + {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:590ef0898a4b0a15485b05210b4a1c9de8806d3ad3d47f74ab1dc07c67a6827f"}, + {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b"}, + {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58"}, + {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8acd7d34af70ee63f9a849f957558e49a98f8f1634f86a59d2be62bb8e93f71c"}, + {file = "pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297"}, +] + [[package]] name = "pydantic" version = "2.10.6" diff --git a/pyproject.toml b/pyproject.toml index 1a10cae9..e29d9b89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,10 @@ alembic = "^1.13.3" aiohttp = "^3.11.9" psycopg2 = "^2.9.10" +[tool.poetry.dependencies.eth-hash] +extras = [ "pycryptodome",] +version = "^0.7.0" + [tool.poetry.group.dev.dependencies] ruff = "^0.1.11" ipykernel = "^6.29.2"