diff --git a/config.py b/config.py index 896dfbb..b8dace4 100644 --- a/config.py +++ b/config.py @@ -2,4 +2,4 @@ import os import json file=os.environ.get('AUTH_CONFIG_FILE') if not file: raise Exception('AUTH_CONFIG_FILE not set. (It should point to a json file.) Exiting.') -config=json.load(open(file)) \ No newline at end of file +config=json.load(open(file)) diff --git a/main.py b/main.py deleted file mode 100644 index 917284c..0000000 --- a/main.py +++ /dev/null @@ -1,11 +0,0 @@ -from importlib import import_module -from . import utils, models -from .config import config - -globals()['backend']=import_module('.backends.'+config['backend']['type'],'auth') -backend.config=config['backend']['options'] -backend.utils=utils -backend.models=models -models.utils=utils -models.backend=backend -backend.init() \ No newline at end of file diff --git a/models.py b/models.py index d836701..d123dba 100644 --- a/models.py +++ b/models.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from pydantic.v1 import validate_arguments from datetime import datetime +from enum import Enum import uuid class AbstractUser(): @@ -29,9 +29,11 @@ class Token(): class InviteToken(Token): _uses: int=0 _max_uses: int=-1 - expires: datetime=None - @validate_arguments + expires: datetime|None=None def __init__(self,value,owner,uses:int,maxuses:int,expiry:datetime|None): + uses=int(uses); maxuses=int(maxuses); + if expiry!='None': expiry=datetime(expiry) + else: expiry=None self.uses,self.max_uses,self.expires=uses,maxuses,expiry return super().__init__(value,owner) @property @@ -62,6 +64,7 @@ class User(AbstractUser): salt: str _invited_by: AbstractUser|str # Root node will just reference itself email: str='' + state: str='pending' def _load_invite(self): if self._invited_by==self.username: return self # Sanity-check to prevent infinite recursion. return backend.load_user(self._invited_by) @@ -72,8 +75,11 @@ class User(AbstractUser): return self._invited_by @property def serialise(self): - return ','.join([self.username,self.password_hash,str(self.salt),self.invited_by.username,self.email or '']) + upstream=self.invited_by + upstream=upstream.username if upstream else 'None' + return ','.join([self.username,self.password_hash,str(self.salt),upstream,self.email or '',self.state]) def create_inv_token(self,*args,**kwargs): + """ All arguments are passed directly to InviteToken's constructor, with self added at the beginning """ tok=InviteToken(self,*args,**kwargs) backend.save_invite(tok) return tok @@ -97,12 +103,18 @@ class User(AbstractUser): return a raise Exception("Incorrect password") @classmethod - def register(cls,username:str,password:str,invite:InviteToken,email:str=''): + def register(cls,username:str,password:str,invite:InviteToken=None,email:str=''): if set([chr(n) for n in range(32)]+[','])&set(username): raise Exception('Invalid username') u=backend.load_user(username) if u is not None: raise Exception("User already exists") - u=User(username,*utils.phash(password),invite.owner,email) + if invite: + owner=invite.owner + else: + owner=None + u=User(username,*utils.phash(password),owner,email) + if invite: + user.state='approved' # Invited users don't need approval + invite.uses+=1 + backend.save_invite(invite) u.save() - invite.uses+=1 - backend.save_invite(invite) - return u \ No newline at end of file + return u