1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 19:44:20 +00:00

Add basic login token creation

This commit is contained in:
Steffo 2020-02-06 18:15:12 +01:00
parent 353b94f1ba
commit 741b9f50db
11 changed files with 99 additions and 13 deletions

View file

@ -1,10 +1,12 @@
# Imports go here! # Imports go here!
from .api_royalnet_version import ApiRoyalnetVersionStar from .api_royalnet_version import ApiRoyalnetVersionStar
from .api_royalnet_login import ApiRoyalnetLoginStar
# Enter the PageStars of your Pack here! # Enter the PageStars of your Pack here!
available_page_stars = [ available_page_stars = [
ApiRoyalnetVersionStar, ApiRoyalnetVersionStar,
ApiRoyalnetLoginStar,
] ]
# Don't change this, it should automatically generate __all__ # Don't change this, it should automatically generate __all__

View file

@ -0,0 +1,32 @@
import datetime
import royalnet.utils as ru
from royalnet.constellation.api import *
from ..tables.users import User
from ..tables.aliases import Alias
from ..tables.tokens import Token
class ApiRoyalnetLoginStar(ApiStar):
path = "/api/royalnet/login/v1"
async def api(self, data: ApiDataDict) -> dict:
TokenT = self.alchemy.get(Token)
UserT = self.alchemy.get(User)
AliasT = self.alchemy.get(Alias)
username = data["username"]
password = data["password"]
async with self.session_acm() as session:
user: User = await ru.asyncify(session.query(UserT).filter_by(username=username).one_or_none)
if user is None:
raise NotFoundException("User not found")
pswd_check = user.test_password(password)
if not pswd_check:
raise ApiError("Invalid password")
token: Token = TokenT.generate(user=user, expiration_delta=datetime.timedelta(days=7))
session.add(token)
await ru.asyncify(session.commit)
response = token.json()
return response

View file

@ -1,11 +1,11 @@
import royalnet.version as rv import royalnet.version as rv
from royalnet.constellation import ApiStar from royalnet.constellation.api import *
class ApiRoyalnetVersionStar(ApiStar): class ApiRoyalnetVersionStar(ApiStar):
path = "/api/royalnet/version" path = "/api/royalnet/version/v1"
async def api(self, data: dict) -> dict: async def api(self, data: ApiDataDict) -> dict:
return { return {
"semantic": rv.semantic "semantic": rv.semantic
} }

View file

@ -4,6 +4,7 @@ from .telegram import Telegram
from .discord import Discord from .discord import Discord
from .matrix import Matrix from .matrix import Matrix
from .aliases import Alias from .aliases import Alias
from .tokens import Token
# Enter the tables of your Pack here! # Enter the tables of your Pack here!
available_tables = { available_tables = {
@ -11,7 +12,8 @@ available_tables = {
Telegram, Telegram,
Discord, Discord,
Matrix, Matrix,
Alias Alias,
Token,
} }
# Don't change this, it should automatically generate __all__ # Don't change this, it should automatically generate __all__

View file

@ -1,4 +1,5 @@
import datetime import datetime
import secrets
from sqlalchemy import * from sqlalchemy import *
from sqlalchemy.orm import * from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.declarative import declared_attr
@ -26,3 +27,16 @@ class Token:
@property @property
def expired(self): def expired(self):
return datetime.datetime.now() > self.expiration return datetime.datetime.now() > self.expiration
@classmethod
def generate(cls, user, expiration_delta: datetime.timedelta):
# noinspection PyArgumentList
token = cls(user=user, expiration=datetime.datetime.now() + expiration_delta, token=secrets.token_urlsafe())
return token
def json(self) -> dict:
return {
"user": self.user.json(),
"token": self.token,
"expiration": self.expiration.isoformat()
}

View file

@ -17,15 +17,9 @@ You can install them with: ::
from .constellation import Constellation from .constellation import Constellation
from .star import Star from .star import Star
from .pagestar import PageStar from .pagestar import PageStar
from .apistar import ApiStar
from .jsonapi import api_response, api_success, api_error
__all__ = [ __all__ = [
"Constellation", "Constellation",
"Star", "Star",
"PageStar", "PageStar",
"ApiStar",
"api_response",
"api_success",
"api_error",
] ]

View file

@ -0,0 +1,16 @@
from .apistar import ApiStar
from .jsonapi import api_response, api_success, api_error
from .apidatadict import ApiDataDict
from .apierrors import ApiError, MissingParameterException, NotFoundException, UnauthorizedException
__all__ = [
"ApiStar",
"api_response",
"api_success",
"api_error",
"ApiDataDict",
"ApiError",
"MissingParameterException",
"NotFoundException",
]

View file

@ -0,0 +1,6 @@
from .apierrors import MissingParameterException
class ApiDataDict(dict):
def __missing__(self, key):
raise MissingParameterException(f"Missing '{key}'")

View file

@ -0,0 +1,14 @@
class ApiError(Exception):
pass
class NotFoundException(ApiError):
pass
class UnauthorizedException(ApiError):
pass
class MissingParameterException(ApiError):
pass

View file

@ -3,8 +3,10 @@ from json import JSONDecodeError
from abc import * from abc import *
from starlette.requests import Request from starlette.requests import Request
from starlette.responses import JSONResponse from starlette.responses import JSONResponse
from .pagestar import PageStar from ..pagestar import PageStar
from .jsonapi import api_error, api_success from .jsonapi import api_error, api_success
from .apidatadict import ApiDataDict
from .apierrors import ApiError, NotFoundException
class ApiStar(PageStar, ABC): class ApiStar(PageStar, ABC):
@ -17,9 +19,13 @@ class ApiStar(PageStar, ABC):
except JSONDecodeError: except JSONDecodeError:
data = {} data = {}
try: try:
response = await self.api(data) response = await self.api(ApiDataDict(data))
except NotFoundException as e:
return api_error(e, code=404)
except ApiError as e:
return api_error(e, code=400)
except Exception as e: except Exception as e:
return api_error(e) return api_error(e, code=500)
return api_success(response) return api_success(response)
async def api(self, data: dict) -> dict: async def api(self, data: dict) -> dict: