import os from datetime import datetime from hashlib import sha256 from base58 import b58encode from app.core.logger import make_log from app.core.models.keys import KnownKey # Auth v1 specs ## Private key (57 bytes) # 1. int8 token version # 2. int128 users.id # 3. int64 init_ts # 4. int256 of os.urandom ## Public key (72 bytes) # 1. int256 of sha256 of private key # 2. int256 of sha256 of users.id # 3. int64 init_ts class AuthenticationMixin: async def create_api_token_v1(self, db_session, token_type) -> dict: user_id = self.id randpart = os.urandom(32) assert type(user_id) == int, "User ID must be an integer" init_ts = int(datetime.now().timestamp()) new_seed = (bytes([1]) # token version + user_id.to_bytes(16, 'big') + init_ts.to_bytes(8, 'big') + randpart) assert len(new_seed) == 57, "Invalid seed length" new_seed_hash_bin = sha256(new_seed).digest() new_seed_hash = b58encode(new_seed_hash_bin).decode() user_id_hash_bin = sha256(user_id.to_bytes(16, 'big')).digest() public_key = ( new_seed_hash_bin + user_id_hash_bin + init_ts.to_bytes(8, 'big') ) assert len(public_key) == 72, "Invalid public key length" public_key_hash_bin = sha256(public_key).digest() public_key_hash = b58encode(public_key_hash_bin).decode() new_key = KnownKey( type=token_type, seed=b58encode(new_seed).decode(), seed_hash=new_seed_hash, public_key=b58encode(public_key).decode(), public_key_hash=public_key_hash, algo='CX_URANDOM_SHA256', meta={ 'I_user_id': user_id }, created=datetime.fromtimestamp(init_ts) ) db_session.add(new_key) db_session.commit() new_key = db_session.query(KnownKey).filter(KnownKey.seed_hash == new_key.seed_hash).first() assert new_key, "Key not created" make_log("auth", f"[new-K] User {user_id} created new {token_type} key {new_key.id}") return { "key": new_key, "auth_v1_token": new_key.seed }