import os from flask import Flask, request from typing import cast from itsdangerous import BadSignature, URLSafeSerializer from xkcdpass import xkcd_password from .models import Deck, Token, db def init_password_generator(): wordfile = xkcd_password.locate_wordfile() global words words = xkcd_password.generate_wordlist(wordfile=wordfile, min_length=3, max_length=6) def init_serializer(app: Flask): global serializer serializer = URLSafeSerializer(app.config['SECRET_KEY']) def get_available_decks(app: Flask): slides_dir = app.config['SLIDES_DIR'] deck_names = [name for name in os.listdir(slides_dir) if os.path.isdir(os.path.join(slides_dir, name))] deck_names.sort() return deck_names def generate_username() -> str: return cast(str, xkcd_password.generate_xkcdpassword(wordlist=words, numwords=3, delimiter="-")) def generate_password() -> str: return cast(str, xkcd_password.generate_xkcdpassword(wordlist=words, numwords=5, delimiter="-")) def generate_token() -> Token: max_tries = 100 for _ in range(max_tries): user_name = generate_username() if not db.session.execute(db.select(Token).where(Token.name == user_name)).scalar(): break else: raise RuntimeError(f"Unique username could not be generated after {max_tries} tries") token = Token(user_name) db.session.add(token) db.session.commit() return token def serialize_token(token: Token) -> str: return serializer.dumps(token.id) def get_token() -> (Token | None): token = request.cookies.get('access_token') if not token: return None try: id = serializer.loads(token) token = db.session.execute(db.select(Token).filter_by(id=id)).scalar_one_or_none() return token except BadSignature: return None def get_unlocked_decks(token: (Token|None)): if token is None: return [] decks = token.decks decks.sort(key=lambda deck: deck.deck) return decks def is_deck_unlocked(deck: str): token = get_token() if token: return token.is_unlocked(deck) else: return False def update_token(decks: list[Deck]): """ Adds the deck to the list of decks stored in the access token """ token = get_token() if token is None: raise ValueError("Invalid token is set") else: token.decks = list(set(decks + token.decks)) db.session.commit()