Locazia: v1 auth (not tested yet)
This commit is contained in:
1 parent
9638f5a31b
commit
e1edae9b29
15 files changed
+419
-4
No files matched your search
@@ -7,6 +7,9 @@ load_dotenv(dotenv_path='.env')
|
||||
|
||||
PROJECT_HOST = os.getenv('PROJECT_HOST', 'http://127.0.0.1:8080')
|
||||
SANIC_PORT = int(os.getenv('SANIC_PORT', '8080'))
|
||||
UPLOADS_DIR = os.getenv('UPLOADS_DIR', '/app/data')
|
||||
if not os.path.exists(UPLOADS_DIR):
|
||||
os.makedirs(UPLOADS_DIR)
|
||||
|
||||
TELEGRAM_API_KEY = os.environ.get('TELEGRAM_API_KEY')
|
||||
assert TELEGRAM_API_KEY, "Telegram API_KEY required"
|
||||
@@ -21,3 +24,7 @@ if not os.path.exists(LOG_DIR):
|
||||
|
||||
_now_str = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
||||
LOG_FILEPATH = f"{LOG_DIR}/{_now_str}.log"
|
||||
|
||||
WEB_APP_URLS = {
|
||||
'uploadContent': f"https://web2-client.vercel.app/uploadContent"
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
from app.core.models.keys import KnownKey
|
||||
from datetime import datetime
|
||||
from base58 import b58encode, b58decode
|
||||
from hashlib import sha256
|
||||
import os
|
||||
|
||||
|
||||
# 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"
|
||||
return {
|
||||
"key": new_key,
|
||||
"auth_v1_token": new_key.seed
|
||||
}
|
||||
@@ -3,4 +3,6 @@ from app.core.models.memory import Memory
|
||||
from app.core.models.transaction import UserBalance, InternalTransaction
|
||||
from app.core.models.user import User
|
||||
from app.core.models.wallet_connection import WalletConnection
|
||||
from app.core.models.keys import KnownKey
|
||||
from app.core.models.node_storage import StoredContent
|
||||
from app.core.models.base import AlchemyBase
|
||||
@@ -0,0 +1,22 @@
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, JSON, Boolean
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .base import AlchemyBase
|
||||
|
||||
|
||||
class KnownKey(AlchemyBase):
|
||||
__tablename__ = 'known_keys'
|
||||
|
||||
id = Column(Integer, autoincrement=True, primary_key=True)
|
||||
type = Column(String(32), nullable=False, default="NOT_SPECIFIED")
|
||||
seed = Column(String(6144), nullable=True, default=None)
|
||||
seed_hash = Column(String(64), nullable=True, default=None) # base58
|
||||
public_key = Column(String(6144), nullable=False, unique=True)
|
||||
public_key_hash = Column(String(64), nullable=False, unique=True) # base58
|
||||
|
||||
algo = Column(String(32), nullable=True, default=None)
|
||||
meta = Column(JSON, nullable=False, default={})
|
||||
|
||||
created = Column(DateTime, nullable=False, default=0)
|
||||
|
||||
# stored_content = relationship('StoredContent', back_populates='key')
|
||||
@@ -0,0 +1,49 @@
|
||||
from sqlalchemy import Column, BigInteger, Integer, String, ForeignKey, DateTime, JSON, Boolean
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .base import AlchemyBase
|
||||
from hashlib import sha256
|
||||
from base58 import b58encode, b58decode
|
||||
|
||||
|
||||
# DMY CID v1 specs
|
||||
# 1. int8 cid version
|
||||
# 2. int256 sha256 of content
|
||||
# 3. int128 onchain content index
|
||||
|
||||
|
||||
class StoredContent(AlchemyBase):
|
||||
__tablename__ = 'node_storage'
|
||||
|
||||
id = Column(Integer, autoincrement=True, primary_key=True)
|
||||
hash = Column(String(64), nullable=False, unique=True) # base58
|
||||
onchain_index = Column(BigInteger, nullable=True, default=None)
|
||||
|
||||
filename = Column(String(1024), nullable=False)
|
||||
meta = Column(JSON, nullable=False, default={})
|
||||
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
|
||||
storj_cid = Column(String(1024), nullable=False, unique=True)
|
||||
ipfs_cid = Column(String(1024), nullable=False, unique=True)
|
||||
telegram_cid = Column(String(1024), nullable=False, unique=True)
|
||||
|
||||
created = Column(DateTime, nullable=False, default=0)
|
||||
disabled = Column(DateTime, nullable=False, default=0)
|
||||
disabled_by = Column(Integer, ForeignKey('users.id'), nullable=True, default=None)
|
||||
|
||||
key_id = Column(Integer, ForeignKey('known_keys.id'), nullable=True, default=None)
|
||||
|
||||
user = relationship('User', uselist=False, foreign_keys=[user_id])
|
||||
key = relationship('KnownKey', uselist=False, foreign_keys=[key_id])
|
||||
|
||||
def make_dmy_cid_v1(self) -> str:
|
||||
vhash = sha256(
|
||||
(1).to_bytes(1, 'big') # cid version
|
||||
+ b58decode(hash)
|
||||
+ (self.onchain_index or 0).to_bytes(16, 'big')
|
||||
).digest()
|
||||
return b58encode(vhash).decode()
|
||||
|
||||
def make_deeplink(self):
|
||||
return f"dmy://storage?cid={self.make_dmy_cid_v1()}"
|
||||
@@ -2,10 +2,12 @@ from sqlalchemy import Column, Integer, String, BigInteger, DateTime, JSON
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from app.core.translation import TranslationCore
|
||||
from app.core.auth_v1 import AuthenticationMixin as AuthenticationMixin_V1
|
||||
from app.core.models.user.display_mixin import DisplayMixin
|
||||
from ..base import AlchemyBase
|
||||
|
||||
|
||||
class User(AlchemyBase, TranslationCore):
|
||||
class User(AlchemyBase, DisplayMixin, TranslationCore, AuthenticationMixin_V1):
|
||||
LOCALE_DOMAIN = 'sanic_telegram_bot'
|
||||
|
||||
__tablename__ = 'users'
|
||||
@@ -22,6 +24,7 @@ class User(AlchemyBase, TranslationCore):
|
||||
balances = relationship('UserBalance', back_populates='user')
|
||||
internal_transactions = relationship('InternalTransaction', back_populates='user')
|
||||
wallet_connections = relationship('WalletConnection', back_populates='user')
|
||||
# stored_content = relationship('StoredContent', back_populates='user')
|
||||
|
||||
def __str__(self):
|
||||
return f"User, {self.id}_{self.telegram_id} | Username: {self.username} " + '\\'
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
class DisplayMixin:
|
||||
def json_format(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"telegram_id": self.telegram_id,
|
||||
"username": self.username,
|
||||
"lang_code": self.lang_code,
|
||||
"meta": self.meta,
|
||||
"last_use": self.last_use,
|
||||
"created": self.created
|
||||
}
|
||||
Reference in new issue
Block a user