import random import string import uuid from datetime import datetime from hashlib import md5 from sqlalchemy import Boolean, Column, DateTime, Integer, Unicode, UniqueConstraint from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Session, relationship, synonym from sqlalchemy.schema import ForeignKey, Table from .meta import Base def encrypt(val): return md5(val.encode("utf-8") + "Salt".encode("utf-8")).hexdigest() class Client(Base): __tablename__ = "auth_clients" id = Column("client_id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) code = Column("code", Integer, unique=True, nullable=False) name = Column("name", Unicode(255), unique=True, nullable=False) enabled = Column("enabled", Boolean, nullable=False) otp = Column("otp", Integer) creation_date = Column("creation_date", DateTime(timezone=True), nullable=False) login_history = relationship("LoginHistory", backref="client") def __init__( self, code=None, name=None, enabled=False, otp=None, creation_date=None, id_=None, ): self.code = code self.name = name self.enabled = enabled self.otp = otp self.creation_date = ( datetime.utcnow() if creation_date is None else creation_date ) self.id = id_ @classmethod def create(cls, dbsession): client_code = random.randint(1000, 9999) otp = random.randint(1000, 9999) name = "".join( random.choice(string.ascii_uppercase + string.digits) for x in range(6) ) client = Client(client_code, name, False, otp) dbsession.add(client) return client user_role = Table( "user_roles", Base.metadata, Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4), Column("user_id", UUID(as_uuid=True), ForeignKey("auth_users.id")), Column("role_id", UUID(as_uuid=True), ForeignKey("auth_roles.id")), ) role_permission = Table( "role_permissions", Base.metadata, Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4), Column("permission_id", UUID(as_uuid=True), ForeignKey("auth_permissions.id")), Column("role_id", UUID(as_uuid=True), ForeignKey("auth_roles.id")), ) class User(Base): __tablename__ = "auth_users" id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("username", Unicode(255), unique=True) _password = Column("password", Unicode(60)) locked_out = Column("disabled", Boolean) roles = relationship("Role", secondary=user_role) login_history = relationship("LoginHistory", backref="user") def _get_password(self): return self._password def _set_password(self, password): self._password = encrypt(password) password = property(_get_password, _set_password) password = synonym("_password", descriptor=password) @property def __name__(self): return self.name def __init__(self, name=None, password=None, locked_out=None, id_=None): self.name = name self.password = password self.locked_out = locked_out self.id = id_ @classmethod def auth(cls, name, password, db) -> any: if password is None: return None user = db.query(User).filter(User.name.ilike(name)).first() if not user: return None if user.password != encrypt(password) or user.locked_out: return None else: return user class LoginHistory(Base): __tablename__ = "auth_login_history" __table_args__ = (UniqueConstraint("user_id", "client_id", "date"),) id = Column( "login_history_id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) user_id = Column( "user_id", UUID(as_uuid=True), ForeignKey("auth_users.id"), nullable=False ) client_id = Column( "client_id", UUID(as_uuid=True), ForeignKey("auth_clients.client_id"), nullable=False, ) date = Column("date", DateTime(timezone=True), nullable=False) def __init__(self, user_id=None, client_id=None, date=None, id_=None): self.user_id = user_id self.client_id = client_id self.date = datetime.utcnow() if date is None else date self.id = id_ class Role(Base): __tablename__ = "auth_roles" id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), unique=True) def __init__(self, name=None, id_=None): self.name = name self.id = id_ class Permission(Base): __tablename__ = "auth_permissions" id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), unique=True) roles = relationship("Role", secondary=role_permission, backref="permissions") def __init__(self, name=None, id_=None): self.name = name self.id = id_