From 9d018e00be9de96570552390033477841cb3e980 Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Mon, 13 Apr 2020 08:31:44 +0200 Subject: [PATCH] initial commit --- .vscode/.ropeproject/config.py | 114 +++++++++ .vscode/.ropeproject/objectdb | Bin 0 -> 210 bytes Dockerfile | 15 ++ Dockerfile.dev | 20 ++ LICENCE | 7 + Makefile | 21 ++ README.md | 3 + cleanup.sh | 7 + csrf-test/index.html | 25 ++ dc.dev.yml | 28 +++ entrypoint.sh | 16 ++ max/__init__.py | 0 max/app.py | 83 +++++++ max/auth/__init__.py | 7 + max/auth/auth.py | 60 +++++ max/auth/middlewares.py | 35 +++ max/auth/routes.py | 50 ++++ max/cli.py | 31 +++ max/crypto.py | 20 ++ max/csrf.py | 58 +++++ max/db/__init__.py | 19 ++ max/db/aliases.py | 72 ++++++ max/db/common.py | 33 +++ max/db/connection.py | 107 +++++++++ max/db/schema.sql | 38 +++ max/db/users.py | 110 +++++++++ max/exceptions.py | 2 + max/middlewares.py | 70 ++++++ .../favicons/cat-face_1f431.png | Bin 0 -> 9584 bytes .../favicons/cat-with-tears-of-joy_1f639.png | Bin 0 -> 10171 bytes max/private_static/favicons/cat_1f408.png | Bin 0 -> 11367 bytes .../grinning-cat-with-smiling-eyes_1f638.png | Bin 0 -> 9614 bytes .../favicons/grinning-cat_1f63a.png | Bin 0 -> 9640 bytes .../favicons/kissing-cat_1f63d.png | Bin 0 -> 11221 bytes .../favicons/paw-prints_1f43e.png | Bin 0 -> 5454 bytes .../favicons/pouting-cat_1f63e.png | Bin 0 -> 8405 bytes .../smiling-cat-with-heart-eyes_1f63b.png | Bin 0 -> 11569 bytes .../favicons/weary-cat_1f640.png | Bin 0 -> 10468 bytes max/private_static/robots.txt | 2 + max/routes/__init__.py | 63 +++++ max/routes/alias/create.py | 57 +++++ max/routes/alias/delete.py | 14 ++ max/routes/alias/detail.py | 8 + max/routes/alias/edit_note.py | 24 ++ max/routes/alias/toggle_enabled.py | 12 + max/routes/base_alias_views.py | 31 +++ max/routes/base_user_views.py | 27 +++ max/routes/favicon.py | 28 +++ max/routes/robots.py | 8 + max/routes/user/change_password.py | 31 +++ max/routes/user/create.py | 71 ++++++ max/routes/user/delete.py | 23 ++ max/routes/user/detail.py | 20 ++ max/routes/user/edit_note.py | 24 ++ max/routes/user/list.py | 12 + max/routes/user/toggle_enabled.py | 12 + max/sessions.py | 131 ++++++++++ max/static/arrow.png | Bin 0 -> 662 bytes max/static/base.css | 223 ++++++++++++++++++ max/static/eyes-small.jpg | Bin 0 -> 7650 bytes max/static/eyes.jpg | Bin 0 -> 57943 bytes max/static/pure-min.css | 11 + max/templates/alerts.html | 3 + max/templates/alias/create.html | 30 +++ max/templates/alias/delete.html | 12 + max/templates/alias/detail.html | 22 ++ max/templates/alias/edit-note.html | 17 ++ max/templates/auth/login.html | 20 ++ max/templates/base.html | 62 +++++ max/templates/csrf.html | 1 + max/templates/user/change-password.html | 24 ++ max/templates/user/create.html | 40 ++++ max/templates/user/delete.html | 12 + max/templates/user/detail.html | 69 ++++++ max/templates/user/edit-note.html | 17 ++ max/templates/user/list.html | 50 ++++ max/utils.py | 0 max/views.py | 118 +++++++++ requirements-dev.txt | 3 + requirements.txt | 3 + setup.cfg | 13 + workspace.code-workspace | 8 + 82 files changed, 2407 insertions(+) create mode 100644 .vscode/.ropeproject/config.py create mode 100644 .vscode/.ropeproject/objectdb create mode 100644 Dockerfile create mode 100644 Dockerfile.dev create mode 100644 LICENCE create mode 100644 Makefile create mode 100644 README.md create mode 100755 cleanup.sh create mode 100644 csrf-test/index.html create mode 100644 dc.dev.yml create mode 100755 entrypoint.sh create mode 100644 max/__init__.py create mode 100644 max/app.py create mode 100644 max/auth/__init__.py create mode 100644 max/auth/auth.py create mode 100644 max/auth/middlewares.py create mode 100644 max/auth/routes.py create mode 100644 max/cli.py create mode 100644 max/crypto.py create mode 100644 max/csrf.py create mode 100644 max/db/__init__.py create mode 100644 max/db/aliases.py create mode 100644 max/db/common.py create mode 100644 max/db/connection.py create mode 100644 max/db/schema.sql create mode 100644 max/db/users.py create mode 100644 max/exceptions.py create mode 100644 max/middlewares.py create mode 100644 max/private_static/favicons/cat-face_1f431.png create mode 100644 max/private_static/favicons/cat-with-tears-of-joy_1f639.png create mode 100644 max/private_static/favicons/cat_1f408.png create mode 100644 max/private_static/favicons/grinning-cat-with-smiling-eyes_1f638.png create mode 100644 max/private_static/favicons/grinning-cat_1f63a.png create mode 100644 max/private_static/favicons/kissing-cat_1f63d.png create mode 100644 max/private_static/favicons/paw-prints_1f43e.png create mode 100644 max/private_static/favicons/pouting-cat_1f63e.png create mode 100644 max/private_static/favicons/smiling-cat-with-heart-eyes_1f63b.png create mode 100644 max/private_static/favicons/weary-cat_1f640.png create mode 100644 max/private_static/robots.txt create mode 100644 max/routes/__init__.py create mode 100644 max/routes/alias/create.py create mode 100644 max/routes/alias/delete.py create mode 100644 max/routes/alias/detail.py create mode 100644 max/routes/alias/edit_note.py create mode 100644 max/routes/alias/toggle_enabled.py create mode 100644 max/routes/base_alias_views.py create mode 100644 max/routes/base_user_views.py create mode 100644 max/routes/favicon.py create mode 100644 max/routes/robots.py create mode 100644 max/routes/user/change_password.py create mode 100644 max/routes/user/create.py create mode 100644 max/routes/user/delete.py create mode 100644 max/routes/user/detail.py create mode 100644 max/routes/user/edit_note.py create mode 100644 max/routes/user/list.py create mode 100644 max/routes/user/toggle_enabled.py create mode 100644 max/sessions.py create mode 100644 max/static/arrow.png create mode 100644 max/static/base.css create mode 100644 max/static/eyes-small.jpg create mode 100644 max/static/eyes.jpg create mode 100644 max/static/pure-min.css create mode 100644 max/templates/alerts.html create mode 100644 max/templates/alias/create.html create mode 100644 max/templates/alias/delete.html create mode 100644 max/templates/alias/detail.html create mode 100644 max/templates/alias/edit-note.html create mode 100644 max/templates/auth/login.html create mode 100644 max/templates/base.html create mode 100644 max/templates/csrf.html create mode 100644 max/templates/user/change-password.html create mode 100644 max/templates/user/create.html create mode 100644 max/templates/user/delete.html create mode 100644 max/templates/user/detail.html create mode 100644 max/templates/user/edit-note.html create mode 100644 max/templates/user/list.html create mode 100644 max/utils.py create mode 100644 max/views.py create mode 100644 requirements-dev.txt create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100644 workspace.code-workspace diff --git a/.vscode/.ropeproject/config.py b/.vscode/.ropeproject/config.py new file mode 100644 index 0000000..dee2d1a --- /dev/null +++ b/.vscode/.ropeproject/config.py @@ -0,0 +1,114 @@ +# The default ``config.py`` +# flake8: noqa + + +def set_prefs(prefs): + """This function is called before opening the project""" + + # Specify which files and folders to ignore in the project. + # Changes to ignored resources are not added to the history and + # VCSs. Also they are not returned in `Project.get_files()`. + # Note that ``?`` and ``*`` match all characters but slashes. + # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' + # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' + # '.svn': matches 'pkg/.svn' and all of its children + # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' + # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' + prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', + '.hg', '.svn', '_svn', '.git', '.tox'] + + # Specifies which files should be considered python files. It is + # useful when you have scripts inside your project. Only files + # ending with ``.py`` are considered to be python files by + # default. + # prefs['python_files'] = ['*.py'] + + # Custom source folders: By default rope searches the project + # for finding source folders (folders that should be searched + # for finding modules). You can add paths to that list. Note + # that rope guesses project source folders correctly most of the + # time; use this if you have any problems. + # The folders should be relative to project root and use '/' for + # separating folders regardless of the platform rope is running on. + # 'src/my_source_folder' for instance. + # prefs.add('source_folders', 'src') + + # You can extend python path for looking up modules + # prefs.add('python_path', '~/python/') + + # Should rope save object information or not. + prefs['save_objectdb'] = True + prefs['compress_objectdb'] = False + + # If `True`, rope analyzes each module when it is being saved. + prefs['automatic_soa'] = True + # The depth of calls to follow in static object analysis + prefs['soa_followed_calls'] = 0 + + # If `False` when running modules or unit tests "dynamic object + # analysis" is turned off. This makes them much faster. + prefs['perform_doa'] = True + + # Rope can check the validity of its object DB when running. + prefs['validate_objectdb'] = True + + # How many undos to hold? + prefs['max_history_items'] = 32 + + # Shows whether to save history across sessions. + prefs['save_history'] = True + prefs['compress_history'] = False + + # Set the number spaces used for indenting. According to + # :PEP:`8`, it is best to use 4 spaces. Since most of rope's + # unit-tests use 4 spaces it is more reliable, too. + prefs['indent_size'] = 4 + + # Builtin and c-extension modules that are allowed to be imported + # and inspected by rope. + prefs['extension_modules'] = [] + + # Add all standard c-extensions to extension_modules list. + prefs['import_dynload_stdmods'] = True + + # If `True` modules with syntax errors are considered to be empty. + # The default value is `False`; When `False` syntax errors raise + # `rope.base.exceptions.ModuleSyntaxError` exception. + prefs['ignore_syntax_errors'] = False + + # If `True`, rope ignores unresolvable imports. Otherwise, they + # appear in the importing namespace. + prefs['ignore_bad_imports'] = False + + # If `True`, rope will insert new module imports as + # `from import ` by default. + prefs['prefer_module_from_imports'] = False + + # If `True`, rope will transform a comma list of imports into + # multiple separate import statements when organizing + # imports. + prefs['split_imports'] = False + + # If `True`, rope will remove all top-level import statements and + # reinsert them at the top of the module when making changes. + prefs['pull_imports_to_top'] = True + + # If `True`, rope will sort imports alphabetically by module name instead + # of alphabetically by import statement, with from imports after normal + # imports. + prefs['sort_imports_alphabetically'] = False + + # Location of implementation of + # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general + # case, you don't have to change this value, unless you're an rope expert. + # Change this value to inject you own implementations of interfaces + # listed in module rope.base.oi.type_hinting.providers.interfaces + # For example, you can add you own providers for Django Models, or disable + # the search type-hinting in a class hierarchy, etc. + prefs['type_hinting_factory'] = ( + 'rope.base.oi.type_hinting.factory.default_type_hinting_factory') + + +def project_opened(project): + """This function is called after opening the project""" + # Do whatever you like here! diff --git a/.vscode/.ropeproject/objectdb b/.vscode/.ropeproject/objectdb new file mode 100644 index 0000000000000000000000000000000000000000..ce37a248a7b9b285ebd532f2ac13d292cd8bd7c8 GIT binary patch literal 210 zcmZvVIS#@w6hs4I31JCbfS$&jBQ=dX7ABkeJNVe$2go4$B$u#|DI Q**mOyWZYrhV^c7T56#*_K>z>% literal 0 HcmV?d00001 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..415bc18 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.8.1 + +RUN apt-get -y update && apt-get -y upgrade && \ + apt-get install --no-install-recommends -y wait-for-it postgresql-client + +WORKDIR /app +COPY requirements.txt . +RUN pip install -U -r requirements.txt +COPY entrypoint.sh . +RUN mkdir log + +ENV PYTHONPATH /app/ + +ENTRYPOINT ["./entrypoint.sh"] +CMD ["gunicorn", "-w", "1", "-b", "0.0.0.0:8000", "max.app:app"] diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..ba948f7 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,20 @@ +FROM python:3.8.1 + +RUN apt-get -y update && apt-get -y upgrade && \ + apt-get install --no-install-recommends -y wait-for-it postgresql-client + +WORKDIR /app +COPY requirements.txt . +COPY requirements-dev.txt . +RUN pip install -U -r requirements.txt -r requirements-dev.txt +COPY entrypoint.sh . +COPY cleanup.sh . +COPY setup.cfg . +RUN mkdir log +ENV PYTHONPATH /app/ + +ENV FLASK_APP=max.app +ENV FLASK_ENV=development + +ENTRYPOINT ["./entrypoint.sh"] +CMD ["flask", "run", "--host", "0.0.0.0", "--port", "8000"] diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..408aa87 --- /dev/null +++ b/LICENCE @@ -0,0 +1,7 @@ +Copyright 2020 Finn Stutzenstein + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4ab226f --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +# DEVELOPMENT SERVER + +build-dev: + docker build -t max-dev -f Dockerfile.dev . + +run-dev: | build-dev + bash -c "trap 'docker-compose -f dc.dev.yml down' EXIT; MAX_COMMAND=\"flask run --host 0.0.0.0 --port 8000\" docker-compose -f dc.dev.yml up --build" + +run-dev-interactive: | build-dev + MAX_COMMAND="sleep infinity" docker-compose -f dc.dev.yml up -d + docker-compose -f dc.dev.yml exec max "./entrypoint.sh" + docker-compose -f dc.dev.yml exec max bash || true + docker-compose -f dc.dev.yml down + +run-cleanup: | build-dev + docker run -ti -v `pwd`/max:/app/max max-dev ./cleanup.sh + +# PROD + +build-prod: + docker build -t max . \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1b742c3 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# MAX + +A small little program to manage emails. \ No newline at end of file diff --git a/cleanup.sh b/cleanup.sh new file mode 100755 index 0000000..97bbdf4 --- /dev/null +++ b/cleanup.sh @@ -0,0 +1,7 @@ +#!/bin/bash +printf "Black:\n" +black max/ +printf "\nIsort:\n" +isort -rc max/ +printf "\nFlake8:\n" +flake8 max/ \ No newline at end of file diff --git a/csrf-test/index.html b/csrf-test/index.html new file mode 100644 index 0000000..d81b742 --- /dev/null +++ b/csrf-test/index.html @@ -0,0 +1,25 @@ + + + + + +

Hi

+ + + + + +
+ +
+ + diff --git a/dc.dev.yml b/dc.dev.yml new file mode 100644 index 0000000..5b6c94f --- /dev/null +++ b/dc.dev.yml @@ -0,0 +1,28 @@ +version: '3' +services: + max: + image: max-dev + volumes: + - ./max:/app/max + depends_on: + - postgresql + command: $MAX_COMMAND + ports: + - 8000:8000/tcp + environment: + - PGSQL_HOST=postgresql + - PGSQL_USER=max + - PGSQL_PASSWORD=max + - PGSQL_NAME=max + networks: + - postgresql + postgresql: + image: sameersbn/postgresql:10 + environment: + - DB_USER=max + - DB_PASS=max + - DB_NAME=max + networks: + - postgresql +networks: + postgresql: diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..788a268 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +if [ -z "$PGSQL_HOST" ] +then + echo "Note: Postgresql not set!!" +else + export PGSQL_PORT="${PGSQL_PORT:-5432}" + + wait-for-it --timeout=15 "$PGSQL_HOST:$PGSQL_PORT" + + # Create schema in postgresql + export PGPASSWORD="$PGSQL_PASSWORD" + psql -1 -h "$PGSQL_HOST" -p "$PGSQL_PORT" -U "$PGSQL_USER" -d "$PGSQL_NAME" -f max/db/schema.sql +fi + +exec "$@" diff --git a/max/__init__.py b/max/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/max/app.py b/max/app.py new file mode 100644 index 0000000..a9457e4 --- /dev/null +++ b/max/app.py @@ -0,0 +1,83 @@ +import base64 +import logging +import os +import sys +from logging.config import dictConfig + +from flask import Flask +from werkzeug.routing import Rule as WerkzeugRule + +from .auth import AuthMiddleware, init as init_auth +from .cli import register_cli +from .csrf import CsrfMiddleware +from .db import database +from .middlewares import LoggingMiddleware, add_middleware_stack +from .routes import init_routes +from .sessions import SessionInterface + + +class Rule(WerkzeugRule): + def __init__(self, *args, methods=None, **kwargs): + super().__init__(*args, **kwargs) # do not set methods + + +def init_logging(name): + dictConfig( + { + "version": 1, + "formatters": { + "default": {"format": "[%(asctime)s] [%(levelname)s]: %(message)s"} + }, + "handlers": { + "wsgi": { + "class": "logging.StreamHandler", + "stream": "ext://flask.logging.wsgi_errors_stream", + "formatter": "default", + }, + "stdout": { + "class": "logging.StreamHandler", + "stream": sys.stdout, + "formatter": "default", + }, + "file": { + "class": "logging.handlers.RotatingFileHandler", + "filename": "/app/log/max.log", + "formatter": "default", + "maxBytes": 1024 * 1024, + "backupCount": 5, + }, + }, + "root": {"level": "INFO", "handlers": ["stdout", "file"]}, + "gunicorn": {"level": "INFO", "handlers": ["stdout", "file"]}, + + } + ) + logger = logging.getLogger(name) + logger.setLevel(logging.DEBUG) + + +def main(): + app = Flask(__name__) + init_logging(app.name) + app.logger.info("Hello there!") + app.logger.debug("If you see this, debug is activated!!") + app.url_rule_class = Rule + app.config.update( + SECRET_KEY="123456" + if app.debug + else base64.b64encode(os.urandom(64)).decode("utf-8"), + SESSION_COOKIE_SECURE=not app.debug, + SESSION_COOKIE_SAMESITE=False, + ) + if not app.debug: + app.config.update(SESSION_COOKIE_DOMAIN="finn.st",) + add_middleware_stack(app, LoggingMiddleware, AuthMiddleware, CsrfMiddleware) + database.init(app) + app.session_interface = SessionInterface() + register_cli(app) + init_auth(app) + init_routes(app) + return app + + +app = main() diff --git a/max/auth/__init__.py b/max/auth/__init__.py new file mode 100644 index 0000000..27525f0 --- /dev/null +++ b/max/auth/__init__.py @@ -0,0 +1,7 @@ +from .auth import change_password, check_password, hash_password # noqa +from .middlewares import AuthMiddleware, no_authentication_required # noqa +from .routes import init_routes + + +def init(app): + init_routes(app) diff --git a/max/auth/auth.py b/max/auth/auth.py new file mode 100644 index 0000000..bfdb6cf --- /dev/null +++ b/max/auth/auth.py @@ -0,0 +1,60 @@ +import base64 +import hashlib +import os + +from flask import session + +from max.crypto import constant_time_compare, force_bytes +from max.db import get_user_by_email, update_user + + +SSHA512_PREFIX = "{SSHA512}" + + +def login(email, password): + user = get_user_by_email(email) + if user is None: + return False + + if not check_password(password, user.passwordhash): + return False + session["user_id"] = user.id + session["user_email"] = user.email + return True + + +def logout(): + session.clear() + + +def change_password(user, password): + hash = hash_password(password) + user.passwordhash = hash + update_user(user) + session.set_new_id() + + +def hash_password(password: str, salt: bytes = None): + if salt is None: + salt = os.urandom(32) + + sha = hashlib.sha512() + sha.update(force_bytes(password)) + sha.update(salt) + sha_and_salt = base64.b64encode(sha.digest() + salt) + return SSHA512_PREFIX + sha_and_salt.decode() + + +def get_salt(hash: str): + if not hash.startswith(SSHA512_PREFIX): + raise RuntimeError(f"The hash does not start with '{SSHA512_PREFIX}''") + + sha_and_salt = base64.b64decode(hash[len(SSHA512_PREFIX) :]) # noqa + return sha_and_salt[64:] + + +def check_password(password: str, hash: str): + salt = get_salt(hash) + hash_from_password = hash_password(password, salt=salt) + + return constant_time_compare(hash, hash_from_password) diff --git a/max/auth/middlewares.py b/max/auth/middlewares.py new file mode 100644 index 0000000..e0ad978 --- /dev/null +++ b/max/auth/middlewares.py @@ -0,0 +1,35 @@ +from functools import wraps + +from flask import session, url_for + +from max.csrf import CSRF_TOKEN_LENGTH +from max.middlewares import BaseMiddleware +from max.views import redirect + + +class AuthMiddleware(BaseMiddleware): + def __call__(self, *args, **kwargs): + if self.app.debug and False: + session["user_id"] = 1 + session["user_email"] = "a@finn.st" + session["csrf_token"] = "a" * CSRF_TOKEN_LENGTH + else: + if not getattr(self.handler, "no_auth", False): + user_id = session.get("user_id") + if not user_id: + # No usage of flash here to not create a session... + return redirect(url_for("login", a=1)) + + return self.handler(*args, **kwargs) + + +def no_authentication_required(handler): + # We could just do handler.no_auth=True, but decorators + # are nicer if they don't have side-effects, so we return a new + # function. + @wraps(handler) + def wrapped_handler(*args, **kwargs): + return handler(*args, **kwargs) + + wrapped_handler.no_auth = True + return wrapped_handler diff --git a/max/auth/routes.py b/max/auth/routes.py new file mode 100644 index 0000000..d57103a --- /dev/null +++ b/max/auth/routes.py @@ -0,0 +1,50 @@ +from flask import flash, session, url_for + +from max.csrf import no_csrf +from max.views import BaseTemplateGetView, BaseView + +from .auth import login, logout +from .middlewares import no_authentication_required + + +def init_routes(app): + app.add_url_rule( + "/login", "login", no_csrf(no_authentication_required(Login.as_view())) + ) + app.add_url_rule("/logout", "logout", Logout.as_view()) + + +class Login(BaseTemplateGetView): + template_name = "auth/login.html" + webpagetitle = "Login" + + def get(self): + if session.get("user_id") is not None: + return self.redirect("/") + return super().get() + + def get_context(self): + context = super().get_context() + context["alert"] = bool(self.request.args.get("a", False)) + return context + + def post(self): + email = self.request.form.get("email") + password = self.request.form.get("password") + + if login(email, password): + flash("Login was sucessfull!", category="success") + return self.redirect("/") + else: + self.app.logger.info( + "Failed login attempt from %s", self.request.real_remote_addr + ) + flash("Email or password was wrong!", category="error") + self.context["email"] = email + + +class Logout(BaseView): + def post(self): + logout() + flash("Logout was sucessfull!", category="success") + return self.redirect(url_for("login")) diff --git a/max/cli.py b/max/cli.py new file mode 100644 index 0000000..2c938f5 --- /dev/null +++ b/max/cli.py @@ -0,0 +1,31 @@ +import click + +from .auth import check_password as auth_check_password, hash_password +from .db import reset_or_create_user + + +def register_cli(app): + app.cli.command("reset-admin")(reset_admin) + app.cli.command("make-hash")(make_hash) + app.cli.command("check-password")(check_password) + + +@click.argument("email") +@click.argument("password") +def reset_admin(email, password): + """ Resets or create a user given by the email """ + hash = hash_password(password) + reset_or_create_user(email, hash) + + +@click.argument("password") +def make_hash(password): + """ Creates a salted hash from the password """ + print(hash_password(password)) + + +@click.argument("password") +@click.argument("hash") +def check_password(password, hash): + """ Checks if the hash is valid for the password """ + print(auth_check_password(password, hash)) diff --git a/max/crypto.py b/max/crypto.py new file mode 100644 index 0000000..97a77a5 --- /dev/null +++ b/max/crypto.py @@ -0,0 +1,20 @@ +import secrets + + +def force_bytes(s): + if isinstance(s, bytes): + return s + if isinstance(s, memoryview): + return bytes(s) + return str(s).encode("utf-8", "strict") + + +def constant_time_compare(val1, val2): + return secrets.compare_digest(force_bytes(val1), force_bytes(val2)) + + +def get_random_string( + length, + allowed_chars=("abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"), +): + return "".join(secrets.choice(allowed_chars) for i in range(length)) diff --git a/max/csrf.py b/max/csrf.py new file mode 100644 index 0000000..9864dad --- /dev/null +++ b/max/csrf.py @@ -0,0 +1,58 @@ +from functools import wraps + +from flask import request, session + +from max.crypto import constant_time_compare, get_random_string +from max.middlewares import BaseMiddleware + + +CSRF_TOKEN_KEY = "csrf_token" +CSRF_TOKEN_LENGTH = 32 + + +class CsrfMiddleware(BaseMiddleware): + def __call__(self, *args, **kwargs): + error = self.process_request() + if error is not None: + # clear csrf from session + if CSRF_TOKEN_KEY in session: + del session[CSRF_TOKEN_KEY] + return error, 400 + + return self.handler(*args, **kwargs) + + def process_request(self): + """ If a string is returned, it mist be used as a 400er error """ + if getattr(self.handler, "no_csrf", False): + return + + session_has_csrf_token = CSRF_TOKEN_KEY in session + method_is_unsafe = request.method.lower() != "get" + + if not session_has_csrf_token and method_is_unsafe: + return "CSRF token is missing" + + elif not session_has_csrf_token and not method_is_unsafe: + session[CSRF_TOKEN_KEY] = get_random_string(CSRF_TOKEN_LENGTH) + + elif session_has_csrf_token and method_is_unsafe: + return self.check_token(session[CSRF_TOKEN_KEY], request.form) + + def check_token(self, session_token, formdata): + if CSRF_TOKEN_KEY not in formdata: + return "No CSRF token" + + request_token = formdata[CSRF_TOKEN_KEY] + if len(request_token) != CSRF_TOKEN_LENGTH: + return "Wrong CSRF token" + elif not constant_time_compare(request_token, session_token): + return "Wrong CSRF token" + + +def no_csrf(handler): + @wraps(handler) + def wrapped_handler(*args, **kwargs): + return handler(*args, **kwargs) + + wrapped_handler.no_csrf = True + return wrapped_handler diff --git a/max/db/__init__.py b/max/db/__init__.py new file mode 100644 index 0000000..681d1ea --- /dev/null +++ b/max/db/__init__.py @@ -0,0 +1,19 @@ +from .aliases import ( # noqa + create_alias, + delete_alias, + get_alias_with_user_by_id, + get_aliases, + update_alias, +) +from .common import EmailAlreadyExists # noqa +from .connection import database # noqa +from .users import ( # noqa + create_user, + delete_user, + get_user, + get_user_by_email, + get_user_by_user_id, + get_users, + reset_or_create_user, + update_user, +) diff --git a/max/db/aliases.py b/max/db/aliases.py new file mode 100644 index 0000000..3bbeb1f --- /dev/null +++ b/max/db/aliases.py @@ -0,0 +1,72 @@ +from dataclasses import dataclass + +from .common import create_email +from .connection import with_cursor +from .users import User + + +@dataclass +class Alias: + id: int + source_email_id: int + email: str + destination_user_id: int + enabled: bool + note: str + + +@with_cursor +def get_aliases(cur, user_id): + cur.execute( + """\ + SELECT a.id, a.source_email_id, e.email, a.destination_user_id, a.enabled, a.note + FROM aliases a INNER JOIN emails e ON a.source_email_id=e.id + WHERE a.destination_user_id=%s""", + [user_id], + ) + return [Alias(*row) for row in cur.fetchall()] + + +@with_cursor +def get_alias_with_user_by_id(cur, alias_id): + cur.execute( + """\ + SELECT a.id, a.source_email_id, ea.email, a.destination_user_id, a.enabled, a.note, + u.id, u.email_id, eu.email, u.passwordhash, u.enabled, u.note + FROM aliases a + INNER JOIN emails ea ON a.source_email_id=ea.id + INNER JOIN users u ON a.destination_user_id=u.id + INNER JOIN emails eu ON u.email_id=eu.id + WHERE a.id=%s""", + [alias_id], + ) + row = cur.fetchone() + if not row: + return None + return Alias(*row[:6]), User(*row[6:]) + + +@with_cursor +def create_alias(cur, email, user, enabled, note): + email_id = create_email(cur, email) + cur.execute( + """ + INSERT INTO aliases (source_email_id, destination_user_id, enabled, note) + VALUES (%s, %s, %s, %s)""", + [email_id, user.id, enabled, note], + ) + + +@with_cursor +def update_alias(cur, alias): + """ updates enabled and note """ + cur.execute( + "UPDATE aliases SET enabled=%s, note=%s WHERE id=%s", + [alias.enabled, alias.note, alias.id], + ) + + +@with_cursor +def delete_alias(cur, alias): + cur.execute("DELETE FROM aliases WHERE id=%s", [alias.id]) + cur.execute("DELETE FROM emails WHERE id=%s", [alias.source_email_id]) diff --git a/max/db/common.py b/max/db/common.py new file mode 100644 index 0000000..392435b --- /dev/null +++ b/max/db/common.py @@ -0,0 +1,33 @@ +class EmailAlreadyExists(Exception): + def __init__(self, msg): + self.msg = msg + + +def create_email(cur, email): + cur.execute("SELECT EXISTS (SELECT 1 FROM emails WHERE email=%s)", [email]) + email_exists = cur.fetchone()[0] + + if email_exists: + cur.execute("SELECT id FROM emails WHERE email=%s", [email]) + email_id = cur.fetchone()[0] + + # Get user? + cur.execute( + """ + SELECT e.email FROM aliases a + INNER JOIN users u ON a.destination_user_id=u.id + INNER JOIN emails e ON u.email_id=e.id + WHERE a.source_email_id=%s""", + [email_id], + ) + alias_user_email = cur.fetchone() + if alias_user_email: + msg = f"Used as an alias by {alias_user_email[0]}." + else: + msg = "Used as an user." + raise EmailAlreadyExists(msg) + + else: + cur.execute("INSERT INTO emails (email) VALUES (%s) RETURNING id", [email]) + email_id = cur.fetchone()[0] + return email_id diff --git a/max/db/connection.py b/max/db/connection.py new file mode 100644 index 0000000..ef422cc --- /dev/null +++ b/max/db/connection.py @@ -0,0 +1,107 @@ +import os +from functools import wraps + +import psycopg2 + + +class DatabaseError(Exception): + pass + + +class ProxyCursor(object): + def __init__(self, cur): + self.cur = cur + + original_execute = object.__getattribute__(self, "cur").execute + + @wraps(original_execute) + def execute(query, args=None): + database.add_query(query, args) + return original_execute(query, args) + + self.execute = execute + + def __getattribute__(self, name): + __dict__ = object.__getattribute__(self, "__dict__") + if name in __dict__ and name != "cur": + return object.__getattribute__(self, name) + else: + return getattr(object.__getattribute__(self, "cur"), name) + + +def get_env(name, default=None): + return os.environ.get(name, default) + + +def ensure_connection(fn): + @wraps(fn) + def wrapper(*args, **kwargs): + while True: + try: + result = fn(*args, **kwargs) + except psycopg2.InterfaceError: + continue + return result + + return wrapper + + +def with_cursor(fn): + @wraps(fn) + @ensure_connection + def wrapper(*args, **kwargs): + conn = database.get_connection() + with conn: + with conn.cursor() as cur: + cur = ProxyCursor(cur) + return fn(cur, *args, **kwargs) + + return wrapper + + +class Database: + app = None + + def __init__(self): + self.connection = None + self.query_count = 0 + + def init(self, app): + self.app = app + + def get_connection(self): + if not self.app: + raise RuntimeError() + if not self.connection: + self.connection = self.create_connection() + return self.connection + + def create_connection(self): + try: + return psycopg2.connect( + host=get_env("PGSQL_HOST"), + port=int(get_env("PGSQL_PORT", 5432)), + database=get_env("PGSQL_NAME"), + user=get_env("PGSQL_USER"), + password=get_env("PGSQL_PASSWORD"), + ) + except psycopg2.Error as e: + raise DatabaseError(f"Database connect error {e.pgcode}: {e.pgerror}") + + def add_query(self, query, args=None): + if args is None: + args = [] + self.app.logger.debug('query="%s", args="%s"', query, str(args)) + self.query_count += 1 + + def collect_query_count(self): + val = self.query_count + self.query_count = 0 + return val + + def shutdown(self): + if self.connection: + self.connection.close() + + +database = Database() diff --git a/max/db/schema.sql b/max/db/schema.sql new file mode 100644 index 0000000..045fdd0 --- /dev/null +++ b/max/db/schema.sql @@ -0,0 +1,38 @@ +CREATE TABLE IF NOT EXISTS domains ( + name varchar PRIMARY KEY +); + +CREATE TABLE IF NOT EXISTS emails ( + id serial PRIMARY KEY, + email varchar(255) NOT NULL UNIQUE +); + +CREATE TABLE IF NOT EXISTS users ( + id serial PRIMARY KEY, + email_id integer REFERENCES emails(id) ON DELETE RESTRICT NOT NULL UNIQUE, + passwordhash varchar(255) NOT NULL, + enabled boolean NOT NULL DEFAULT TRUE, + note text NOT NULL DEFAULT '' +); + +CREATE TABLE IF NOT EXISTS aliases ( + id serial PRIMARY KEY, + source_email_id integer REFERENCES emails(id) ON DELETE RESTRICT NOT NULL, + destination_user_id integer REFERENCES users(id) ON DELETE RESTRICT NOT NULL, + enabled boolean NOT NULL DEFAULT TRUE, + note text, + UNIQUE(source_email_id, destination_user_id) +); + +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM domains) THEN + INSERT INTO domains (name) VALUES ('finn.st'); + END IF; +END$$; + +--INSERT INTO users (email, passwordhash) VALUES ('me@finn.st', '{SSHA512}dhnq/FPGDsaWp4FL+MKR8IlDetl9G7qeNTImbotgNkKcQ5rIcew1fRb50xWLt0JRJs9wrq3sP3Wcir2uqw/GZX8no1bkFmjL5Z/RVKGkhxI='); +--INSERT INTO aliases (source, destination_id) VALUES ('alias@finn.st', 1), ('postmaster@finn.st', 1); + +INSERT INTO emails (email) VALUES ('a@finn.st'); +INSERT INTO users (email_id, passwordhash) VALUES (1, '{SSHA512}kYrSSW/1sHuJg8j4o3us13z4MyTR8RkOQ8UkywpgeoB0VuP2klLAX/junFRSxzUZyfthAJRWqfpSUS4aqFK+7QeZTu73JasrHmIafCIiWc0='); diff --git a/max/db/users.py b/max/db/users.py new file mode 100644 index 0000000..8ca612b --- /dev/null +++ b/max/db/users.py @@ -0,0 +1,110 @@ +from dataclasses import dataclass + +from .common import create_email +from .connection import with_cursor + + +@dataclass +class User: + id: int + email_id: int + email: str + passwordhash: str + enabled: bool + note: str + + +@with_cursor +def get_user_by_email(cur, email): + return get_user( + cur, + """\ + SELECT u.id, u.email_id, e.email, u.passwordhash, u.enabled, u.note + FROM users u INNER JOIN emails e ON u.email_id=e.id + WHERE e.email=%s""", + email, + ) + + +@with_cursor +def get_user_by_user_id(cur, user_id): + return get_user( + cur, + """\ + SELECT u.id, u.email_id, e.email, u.passwordhash, u.enabled, u.note + FROM users u INNER JOIN emails e ON u.email_id=e.id + WHERE u.id=%s""", + user_id, + ) + + +def get_user(cur, query, param): + cur.execute(query, [param]) + row = cur.fetchone() + if not row: + return None + return User(*row) + + +@with_cursor +def get_users(cur): + cur.execute( + """\ + SELECT u.id, u.email_id, e.email, u.passwordhash, u.enabled, u.note + FROM users u INNER JOIN emails e ON u.email_id=e.id""" + ) + return [User(*row) for row in cur.fetchall()] + + +@with_cursor +def update_user(cur, user): + """ only pwhash, enabled, note """ + cur.execute( + "UPDATE users SET passwordhash=%s, enabled=%s, note=%s WHERE id=%s", + [user.passwordhash, user.enabled, user.note, user.id], + ) + + +@with_cursor +def create_user(cur, email, passwordhash, enabled, note): + email_id = create_email(cur, email) + cur.execute( + """\ + INSERT INTO users (email_id, passwordhash, enabled, note) + VALUES (%s, %s, %s, %s)""", + [email_id, passwordhash, enabled, note], + ) + + +@with_cursor +def delete_user(cur, user): + cur.execute("DELETE FROM users WHERE id=%s", [user.id]) + cur.execute("DELETE FROM emails WHERE id=%s", [user.email_id]) + + +@with_cursor +def reset_or_create_user(cur, email, hash): + # does the email exists? + cur.execute("SELECT id FROM emails WHERE email=%s", [email]) + email_id = cur.fetchone() + if email_id is not None: + email_id = email_id[0] + # alias or user? + cur.execute("SELECT id FROM users WHERE email_id=%s", [email_id]) + user_id = cur.fetchone() + if user_id is not None: + user_id = user_id[0] + # update User + cur.execute("UPDATE users SET passwordhash=%s WHERE id=%s", [hash, user_id]) + print(f"reset password for {email}") + else: + print(f"{email} is used as an alias. Please specify another one.") + else: + # user des not exists. create him. + cur.execute("INSERT INTO emails (email) VALUES (%s) RETURNING id", [email]) + email_id = cur.fetchone()[0] + cur.execute( + "INSERT INTO users (email_id, passwordhash, enabled, note) VALUES (%s, %s, %s, %s)", + [email_id, hash, False, "Created by commandline"], + ) + print(f"Created {email}") diff --git a/max/exceptions.py b/max/exceptions.py new file mode 100644 index 0000000..c47bebb --- /dev/null +++ b/max/exceptions.py @@ -0,0 +1,2 @@ +class ImproperlyConfigured(Exception): + pass diff --git a/max/middlewares.py b/max/middlewares.py new file mode 100644 index 0000000..e76aefa --- /dev/null +++ b/max/middlewares.py @@ -0,0 +1,70 @@ +import time + +from flask import Response, request, session + +from max.db import database + + +class BaseMiddleware: + def __init__(self, app, handler): + self.app = app + self.handler = handler + for attr in ("no_auth", "no_csrf"): + if hasattr(handler, attr): + setattr(self, attr, True) + + def __call__(self, *args, **kwargs): + raise NotImplementedError() + + +class LoggingMiddleware(BaseMiddleware): + def __call__(self, *args, **kwargs): + real_ip = request.headers.get("X-RealIp", None) + if real_ip is None and self.app.debug: + real_ip = request.remote_addr + setattr(request, "real_remote_addr", real_ip) + + start = time.time() + + result = self.handler(*args, **kwargs) + response: Response = self.app.make_response(result) + + end = time.time() + time_in_ms = f"{(end-start)*1000:.2f}" + + self.app.logger.info( + '%s %s %s user_agent="%s" referrer="%s" db_queries=%s %s ' + + "%s user_id=%s session=%s %sms", + request.method, + request.url, + request.real_remote_addr, + request.user_agent, + request.referrer, + database.collect_query_count(), + response.status_code, + response.content_length, + session.get("user_id"), + session.id, + time_in_ms, + ) + return result + + +def add_middleware_stack(app, *middlewares): + original_add_url_rule = app.add_url_rule + + def url_rule_with_middlewares( + rule, endpoint=None, view_func=None, provide_automatic_options=None, **options + ): + if view_func: + for middleware in middlewares[::-1]: + view_func = middleware(app, view_func) + return original_add_url_rule( + rule, + endpoint=endpoint, + view_func=view_func, + provide_automatic_options=provide_automatic_options, + **options, + ) + + app.add_url_rule = url_rule_with_middlewares diff --git a/max/private_static/favicons/cat-face_1f431.png b/max/private_static/favicons/cat-face_1f431.png new file mode 100644 index 0000000000000000000000000000000000000000..095c14478659c5a7014f9e20a0f91435777ec7fb GIT binary patch literal 9584 zcmYj%1yEeU((VQb4#AxeAh-nx9-QDV0fIwtSQcFz7J@Gj+?_>2a9do1ySuwvaCzMO z-uvsXsWV+?=G2*)p09ekzn(BvWf?4VGIRg{fF&m@rT!}2|MQ?Czt#djcqd*3lBKwk zH~>%?jqzym_VxXPnXI}J0N_av0Qmm|0PbI#{PzF=*G~YzfiVCem<#|AgVGz-zPxrI zn<~gi0bc%7vRew{0DzDCa#G@&?hD5TDDDK)3(5fNfNYvvWa=LpsF0r@e-iL2Fy_eO z=P!t>G3DOsooIC<8mo{WqP39LS3US^!er#L#7EZfvCl)C+IF&w04laBk3^gR?1#tYTk_H|S|b~9*b z({ci?t#&b;Xc0Sfl8nr?%UbBiz}xwU=X#O{-J`~{)(7E1YK7lin(oSI8!i*{MHm{E z=^I+JH$-)9xb$s)G>tJk3X|HB%#y?l4q`eIs0Q(G4MH;C`i| zEt{OJli00^c%#8b$+TK^mPM&VlupVcCYAP#34C(ZnW}>L+GZwmb{nbv%R`NYqsDkL z2d!H!X~9kYP1+uSbV-}-@we%TZ?O^4ANlrUOTs0%>eop01D!$du(IENRTv9Zvg zC*vX_$5Y4x<8RxygvdvssP4~Z6klO(x_ltKJk1Skb+J!k*tTy-yRvo28~Pi`WDgXk zI}Z=YtMM6>HNLX={7_QA%Iq+wxRCxq0RBx}bq8|^A_+oM?qK6bo?X)ijgpCBSRvSJ zQg9?LXr<)%VhStE?;>GbyQ|IfQER%fOWl12w2cNOZrWA!NsX^xyBtT<#aBOL59m8_ z!-k9XfU*s94bVWSCCtllA*f_&MX8FdDPsNaUf;hX>(S-A0NSk1_i`*Z-W)j zZzd+i^%0(=tOvh4MyNL_*}5@pqVx!1is~)bGnd!P#RPwPj^>Q6)M{*f;biAhC)JGw z@KkO25pP#oz3_5d3<7pVg4^sEj{CJKtp|lB>eOA8-lD7_r2CVDevG6E`%C{0uhzdX z<#D#6YQ?VwKPzc^*91z2eaE9HgYEsw>cd%5wP|kpZdD^L%DrM*!&CnCH`yC;T9P4tm^oT@%v2$WIAet2=l;-6&1xPjp5_yqig)|q~ zx@j9Eg+GQ_xWQn;_BZl95_F%$1?Ni~U`IT7x2?Y$K+(C`THp9L6q}V&UFsdU8%s7q z3%EvCe+LEG%aYf1T9{SuNGRvv+QoY){dd&wHH6-uLUD-2y#V~{(tpAtvvWY@eE2Kr z{Y8271j|1op*QAir6lncpBNiRG01dq=M0dTdLGjPFIC~AX%lz{I$x+Z5ce++61>PY zI@WjIaTfH8Sc^AQxc*eCz~XI;<=(8-bQ5Dqsn;*g(Skgn<mydGU{txWd&##Xk5w zw8%G|C;VOpg^hJ+R%quu$CHLt_zC;m@LLNJalF)2JEnC$$NUZ>D1m#ou&cTDlGnsvv?n^Q$( zt}*-F$8i()jpiqK0S9#`1tl!kp0}h}_8q${5?zQQ2C3fx6Z!sBmC@EcWm5JzZe1X$t6Wj_|HR(8}1-J{Uye%T4m8lPi`i6>j$Ph9tAPDdTrBLRte5$zOLc zHTen&$2_7=cL5_xidApj|ehd zcBA>BezcT%&dUw9@^kg~aQU6NSP!35$x* zXRa-A8rOmA6PeY+la)GH)m-r|lW^vKW%;ZeXvJRBDA;Jj+EJ@Vg}6-VXm$?hx65fN zkW7iIzaH0ZG*7d~rnF;`EFPD(+`HCmt2Ej6R*_pK9xX9KDox)G+E9X~7h!I^rQLqL zWhr^x$fn2YwfLR;CcMnU0eX^rSS8}j_;c&d<=`CQH8V~ltu@LtqT`Yo3&I6Y$8oyf zKpH3_a>u|}*1V_X(zDuhm67F0%L)#yL0yENl`C5!A*9m(fkDrPgGQ7S0z&K;n*!>f zTI%31($AD%Hq2HZYI?JZ=_33{D|zk*b@`VfY`)KkwojoRcxfJvbTt3Az_Iyz(B{ic z<6Hf#6*F6`=Q)s3f-tx{vZO}T?oSJZCp^9l6NG|#6B$`z%zXM1<-A1?!lH#u)ZK7L zlWBOp{BE}yX0~w%pBl(XONe8ROs}l@r(cRX>-saoi(x~=_z;0Xz(u2lpdsY18XFM_ z;#MtWN&Wg<)ug0) ze~Se9$G}_Vng-h+l5E%9(o;vw-OfVkE~C43KgSO>8ppFAT&7yQz~M7Yd-HihkscpX ziH4#1B`A`%HGO@HK?VkUPujUwX8_85{+9)-;6(fN(Ycjn>jC`lg3Sdi3F)pQN}DGN z32D!2A}WJ-A#;5ZHAEPVTe-)047rvh_jkDM06IoIEIE+ zWz`!`+N@VfuNJZ0@8;j+c-tmz(H@kWR*yc~=C*uVhKHXKq#~WU-UEWJ3(BMGp8&^eG^qpk_^ntV}Tvpk#p4A;-`neJni0q9pJ(-~3ahX=p-I)$fxGj*S)W7p)jQ~t$YuP}Ae z#SfwHG#N_tSjWaS1x_kb1?WG)wT1CnqH#CTAu{0t zG7Qoc#zO<|(ur?FC=Gz{_Wtw`$P*yhg7rWq2-D=3bj#7X=YX{l@Q}yq9%! zh$R`->F!#m8?MiL3|Jx6wBS~O<47!+*0$S<=mJ1|7#bm+)Bb98(NMe)_b{rFnIV>N zi8b9GIb;T+z^)I_UO_T(hQ;ycRK?l(aA!BE35wz9_ZDqwC*yfSKB*)p?i6Z{K=*Hv zc>Kp8MkO-aHZQ&Vvg15aS%&C`!8X6~Am2q3a*$nShR;!SLxser49eOYm}R5dH7CRU z1&^+=q@MS6+$Y?8O}Z-Os7J-LiAb*K1?li)q}$I>ysYrt{lJ>f_Wt(mmHa5X3#r%} zZxr##niaJ+OlRb-5JnnYTxEvw=EO$!u}lW6ekofUxmvK3{=7Pv&#-7FF~3az6g5tT z1{2uKwX#wC{A8r^;O`7#FEg?AEQ-8bf#&=A#22e@4qIEuVEXxG26C~Yf&_!%$_Rd2 z@(`>oV|1LjchOPdM2I&aFb<)QqGIf+4vDfyp&i)r3|kb44I}oH8Qa=J_55Z@1;QTr z%X4IX$T{e0XQ1u5c?ay|7C#cP8~yc05ckd@ol=}sM!))ZS3o;egTxv*Ju~+bmNbUP0p0DZ_)!VYZxRMpZk?R)3j$vyH>q>Ro({K z7PDSi7rH{V@7Z7(&aL&P>`Y>lK#uD6Ix`PW=fBe`nhJ<2W0Vf4#iEK<&3Fd2UG1TD6 zhT1ng-}OOk{FW#GO49IajFrk-{)L`mz6K!q799Wew1#APNPWV_6EKg-)p*Y#V)DsH zDi4Xl<3Slm%uy_p+Tm-MinN)<0%Doh!xj&@;&Vk}GM0Lcy zGeylM?r(e7$kI;@7QViEcp1Q!Ob`sjuGA%*L-8VO2Vk@v*F+W|Q{xBESRj zQjS^e@8oH+0tg-0!3js+U0cZxOz21$RF^D4m^Fi1QkdzR$CF4WuwqFA_S#lNRb}Gd z&#HIU$SyP#vCugjO5D@xK(g`D+LFF;|FSsWH~xO_M1Ii*qpmI0PEw0TNaf3|E%*B7 ze51lK&b2;OmLpFKSWcC(RjtvoW%w$zZXov(%iau?@fj*z-L{*L}Ea* z`P&m3)Z(>koXgf{K7y%dMTr}Rk@=%>aEB&B9{un~t$zsC7L@1(<4*{EtDA-gAO~{K zvsUGJpWB{o6n%eu5Moq2AwMFR=q=CL;F2Vwm80Kk-zDpXU9lQNaY~bxV=0<4`O;Er z+Bj%J+hIj9t9dNeLg_$kG-^8BRZiGTXH>OjDH;t3Rc_&B3THpI;Cm)q5!Lr$G~3f1 zVxS7=ZRGRrZLOM|PA9ITr0~Z8;nBX0EX(ioHv>H#%>h5#=8D=|VCh6uy^L7#XU?#Y z3Dm;=HZ?fPmYMHOHk>B3JQ58EkVr8t!XtGkq%R9)#+)}B9m#Q(guN0mY?->qHyiQ9 z*EG;ynF{su@hD9v8r6BQAe^F5unEZ=^GTfOR@|JOtQ~yB;;crtbH^@#n?L8;9M|ty zK}n&riQ<76vWE8>5`i$woUxJAXC~<5aTywAQ=ny-Nz08++IO~=hZ^VNel+YcKf$Y+ z=(){Z8T*}eI16q07<4VT${JaF(p@Mr5tZ9k35U-#oQmlh14#OdG19 zz(4$*bELq8+Al*VR#o>9yp*=1r|@<`4-N8Gvn(7m{(?{~r~Ej06#Tsr@vMxX?7Mv$ zpDn~Y@z!6WTNH}}jX zowj2%UuIAy*XeSu{w}e{ zSEU3-ck#3TisCpCGxPKui)C=gx#T`jl{V!bSbbsLK6)>sOYWuKgYGA<(ipeQzcOYp z8!vV#VO;(pihxAH+W9~Gg@5<8)!8i)_9)4rYN3vC4>|rW_)J7bxG5e&>Rwup-qcnFMm_1M~TcxBeCPXhSap5n~R}C^fY|?@oYqqc(;XI+w)$GaG zteCKWry=7@+Fkqq!j{Ut;N+2{WJ-t+`$b?CI&}&mc?HpG6LY(@?NLGXKQkep$v6(E zR#G>p+TvoPeH3BlQkvgn&F{2}K0XOCH@f?ykN7FxS>o~U-J%ftGcbA`KE>DO2$`3m z6+pK|;#>OyCy1BCtuNEK*OlPIwz9=&|KbC1jS4B~RrWNFdmX*MjNtEHx`KrD{{viI za+mZIoEVV{$m0j2uf#VI-ZX7}d>1d1vqDzaa4##dpC}&HK8+x%dsk-}X5lG0z^j#W z%)%q$|0MIjEcw&%q}aXiJ}<)VkPoNr8HmhQe3ybigJ%vRez-_t2$i*W8LH?-3F&Tm zfU9&wZ<>Y*J3QasYEXgwzR(t@Ck8gwbONhNs6}EiO#Ia4U!TGb9XSAbkWH!4n z>PTYzakhX0C9e!@DiK9bA8g%~#1NVk#^x;8~(MJ!^Un8+W!RdaOfHfLMU8w z+cGYFJ)=k6hZs(CASS2QuAE)jVN*N2#ai2e6wD@GpLRIw21&zLN#;rLy3UeG`qd*t z4p^h~k}PL_t@j4oGMNjbkUk(3K_i!i7PAl@dA49C5YpoXkC?(j2G@hBFli`>_~p)U zUbW?@IuOV{-Hr8XJ$FX4RA^ZW#Vi>JR7XLy;Ljg$4N%)s&S*jeIYhy0Njb zHgafmg-ft+*x>ZlJ^A+5os8Q8+DCN}_DHj8BeYOy;8VNe;z)~7pgo2F~@id*#-$U243wz~)P6qmZZy~^-&Au%)4ezjyB;wwq=JREt z=6@{@9-q09+}jHnaq;Cr(Mc1G_0^TdUjZTtwyL^%tSs?9E!B(^ z&u~-lM&YgcIlD&F8y<%LKgo{mT^P_irZzWwc8NzVIiIHq{WY)b%oeuvTQ^O z_9Jqo6Wgr?TEp}_3Dx+mP$FosO|uJ#hM0Xd%uw zLiAV#HTPZSp*)M>JD8@M?$--A-m_nCQ|r{Y5!1OAu4QR(z5U`hZ_})-EULH2$m%*e zB-XXx50;zw{vFOnBV&|DFpDSvpn3`0GbYh9fYnAyYs~OgAf!nZOw#T%HA}k3zIl zFj{TiaQ)TWE6V1^FU4qt!0Uo$mB+oS=BTS34TEC8KLp?EaF=U1KikTa5CYfBx-8y) zeS9jUYyB*1nO0KP?@x@rUz8(!dart3xXp`DL0T7xD4C7^|8hNLAPu2`H4Bw#2fws+ zL;H=?u%pr2H;te1K3)?W4pWvMT02@sGjX|Z@!C6J1)KBpj2ycs zoJuqrlCwEE3q9H(*0WSEWeNV1j?2C2@tj-}iJ^ZIkQ4vA78$qWj+Xj_Tn3_*R#eU|yee>3(-|4A9`4Z#t>YdHFu-g#lq7k>l;<5nB{BeB0# z!>#(v;4!-*sT|-GJmi02%wq}Q&d3x>PB8_H%y$J;__}koWDsu_cu$`}Y0g`G9)htI zkC;VjKwLYRLraPKWmMO3-L>a>cC1{^Zd34(cSivm073w^$H>8O9{-N{&jA}+yrlfP zeTR4@yk`~f3MWGZbh zt3TxZ?gR!rx9`x~pA{ZOqZZG`WIbE8F~3&M1(N|4Qdb@YtSf@qhw4@I@x8R`U{DXG zz3wae&v6apIOIXpCeFaYkGrp-?2)S{rV6*I>T)mKre=} zE~q8ls=v9;Wk5X57p?@4!zzUt?FYKzuQ#NKqW=1r|L(pVaByxmbsJL9V0;QXciB$K zsqxFE5+-yhgtsQ?mIlEqamg00swUF)opqM#;#1rs?l5?JCbWSkF$?dLDZ^uy4%p5N zS$RlVc&ZGn65u(|7AOq{+7`En*_GvIu5{WaWxhf3xQKYDvyufka^j$2Cwa%GSBGDQmUq~28-Vyduwj4q$O!Z-CAPN$w5o^aq7qc)7f&3za_ z*~l9*PuKY1Ruxe547#Is4bO}|T8sA&?wQtN9;=T6&x%gKGQ^ts-aXUmzTZNa+In!~ zH)ih;FJqKg4K%}-q(ltc8M)+HFrAAsObN=)bB*v@te%muB4_GgJTZJ4PVe~Si8g+Z zNd~lGRNjBirFvMF5M2h7W6T9~WId&Yb^fBz%ktgZHuP1FzBpWKgg-Zi_DpdUVF?SX zNKg241bss?1b$P;=6)Z`vd6;4 zroL4GeMj;Z+00ny>ak!>8gN#aU88-nHcEYt(LEHYgiS`ZM$p^;DnD8qJk z-Ega6Z4`!z*&r`Tf=H9dK5@NMIOF&U=S8B^uZxalm%9eN{m#AME3=nI36eZnVLLG> zl8qe|Sf11q-@v;H4W{fMcYk-|^!NcI@inx-jBVM&mRI=X!EpAqM-tjt7o}NTV@=I7 zPsfAqR6|)-4m8Wq(Rd2g$6~aUIbb}#2 zNz!nz01f2=r-ays)~a{0nNI(Ev#KXZ)4CiK4A{(l(Dd| zY-GZVzy$vwl_R&8e4u~}_@dD8L+Gb85-GKV-5@V+ssZ0py04>x)~AAE(%kTla9$dR zy?a;+$De5Dhd^A8#qT$52^HULoF%1M&06}?l(#>~-5;e%VU0VB6@(fr^XSn|NG+hE z#}IF!d2r)j$3i(Jj`p7)GrEC{dG^h^m&6_n245?8`Erhe*rYzuBJoAJ+NKj2x<1P@ zF*X_H2YoIL{my!tk;&vRR-(=F$G&V)8+-jYhE{~oVfe=^>cl!dZZ_I@LooH6_zS*d zo+&29+jfLAs;G`ieg?~agZP%BAUIK3n5`bD?PH)Me4P#2yEQ1ZY#Zb{S* zCeNp1`g9@&rbZ9oxe_0r9Z6pNHD2_8e-i%dBw^WA=VQx&MNc(Uxk_g38_S==?w&DA zuO2ID3NwyP%lUG4=XJJxm=hjA?Ti@e#~IAkj9Cwy3I8sfXXajRsyE;3oqkSa)oq8V+*f6(G6~~={{zQxm$d)@ literal 0 HcmV?d00001 diff --git a/max/private_static/favicons/cat-with-tears-of-joy_1f639.png b/max/private_static/favicons/cat-with-tears-of-joy_1f639.png new file mode 100644 index 0000000000000000000000000000000000000000..95b23a11ad4f7036b09bab7876f6ae22c501a490 GIT binary patch literal 10171 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 literal 0 HcmV?d00001 diff --git a/max/private_static/favicons/cat_1f408.png b/max/private_static/favicons/cat_1f408.png new file mode 100644 index 0000000000000000000000000000000000000000..d3c507dbd130782b795545556c5fd58ef56532d3 GIT binary patch literal 11367 zcmV-tESS@YP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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 literal 0 HcmV?d00001 diff --git a/max/private_static/favicons/grinning-cat-with-smiling-eyes_1f638.png b/max/private_static/favicons/grinning-cat-with-smiling-eyes_1f638.png new file mode 100644 index 0000000000000000000000000000000000000000..ed79c23d39df87a6c223ae8fe4413981740e0205 GIT binary patch literal 9614 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 literal 0 HcmV?d00001 diff --git a/max/private_static/favicons/kissing-cat_1f63d.png b/max/private_static/favicons/kissing-cat_1f63d.png new file mode 100644 index 0000000000000000000000000000000000000000..0b55cbd316de583100cadd813bbacff9bf46e117 GIT binary patch literal 11221 zcmZX4Ra9KT5-kLGNEqA+?(UM{65QQg26qT<0|X~H4DRmklHl$x!C`QF+0H_=y-%V${FU&X!VAn+i$$SiYbtk|xIEKM$yOnMCynqf5g2(dWDQ1aEQP zX?f8&v0<6xGS164-(_RiSiPcoR(_}cT;})RDGNeZl@z{m+!Zf4WPwkk#Dyh?`o$7ACkkp`J$9d&uLR`QwN?K=2OI-xvab1I(viX_RT->$fY!;9dC zL650htMa~0qXLczRto%ee2jN>ur8nwLynn(isv|?{Q5h4^A?_7unQ0aEf;l>&>(0#mgWm!ZzV$gXNEe7&)!Vw2&Gi#! z3U;N0*MPaP-c|`W3|*kmB^WL|2TYjbITfQQl;i<(`CgoD-m=3CqUB#sxW*9t!Iwc& z@CR_Oq;pDa9-9=IHU1EBRVU9fudrR#;89F8PGT%LY&Cvq^1#Y3^Dr`bxnA$QD(P%U zgRpW9f?QD^*CXL>!4m~C0O8Mj$XhtK7e3#=pxe(#h(_)n7r1lBv<1hTuzvLzrYu6J zLPV9k+APFfYe8tj>}0Z?f2W(aCs-~7IpVqCG0~@YsW%CeN&Fl1OvV~sqEg+|1m)l@ z;%g^BanY5^z1dqbrobuiNHXv#Xbe^H&!qCrG^@B31i=8I6?)Kk*$*q(e@d41 z$i#POaiQ<_r&4(DUKH%a>1viL%LP$3VrN;Aqkbo7BRQ+UAuye~2Wf+f|AM6fSeSDe zSD#I}c0ccWNXCcePdYo9bZc?u{<=cht&k6(4OtnLZZ^wFZ178g?1$C*-2sIAJ%CWm zW%MO{%~OavG8x@T1Ui7Fn0RfLtiD|4t>F8mY6UA&P-(3qR{rTZx;BUh9&3jT596mz0hX-^*oszgCJCuK zZnOkUjXfK}1cGCi9ml020?@J#@H)zT6{G1q(l`jlzs!otbk2fNP9@Q7W?W5k2WaMV){;4nDJUIU?PFmH$_3dKRa&kFdLV{mEi3m* z>kD2{*^6_t5TopajlieCWzS!6N;|ebgbIQkswTOTRB)64gUrxF1m3zY{lL6?- zF?!6maHAI1tftm}W6Reb-%2X;3n0|Uc20)cQn^n|d(!jvR(cwHjP!&)Zl(7qPK*j{ zXIFi1L8?Fo@kT>T0woHrilQD1vs@ZV^N4JQ1K=Go9shiS>j^0>p^y5!#YXnh90y(&md*;i)-y;;(zacXT9(~at| zg7>R;F(JwWY$44YN6b<|`@lnx)8x+Hn>+TBUFJa4mzm~PM=cBSzebHWH*Z_0YxtDh zWwJF4z;1dJI~A)nvC!f4cmxANBwJ#-mEQ(|W?(b{QFE*HHZdX3`&eyC!d- zyfqazt$Hg!noPIcUu#?Y@oRND-C<(=M&4~{y~GbqcwqDD#NhKL;;ym`xW>iN!bv>{NzIr*DF|iQMs!Uiv?q*i?l{vc^S-FF8MLpxJzL!ujv2MU$j zD~qP;y9N*+pv}tA&0fP;0)x3oyg3N9-^&7QGc?<32!3^!)zWqS!l0;E4 z1Sl`XQm#=po4>2BxAwh!(L@^y4;L7q8Gj_PPoqHQyW=DmIBo(g#W+ZMT90E$9aS?i zJf*B6T32oLbJQsoT9<5vEioy566i;R0RZsskL)T&@bf!f71!(L?9OI>(=V%L`8jIz zHr~`mNnT3!`>7|lQaUvJeXL>g)^{ZQ{-)MLOeQFgR~=L<^iHgwoY9lP`ey2Ky5Ha~ zaQh%a32ZFNI(m(pE0g76pjoNNbaW!WK8!O_WD~%;ht|dAt(E1Omy3sCsQR7ED#0fFRVhzYO2X)oi3X+! z9Z)?W)|@5?M;w65cT#Dnx}9J!%ZzH4`HXgFPiGXJcik1^_+2!GMm zTU{lLUt1^4>%%vnnVcIn>Gl|o&~Iu>PliqSP5t2)OR1-`W5fxu4I+z>Ka0`x3e)s~ zsrW;NAh`Jee$X{KMatjXJlya{v*hhaRTGXdRz!wVqd1%$8tR zxg~vOlW<>392E!MAD|3}Y84}0e2+GtS5>XK9I80*!!d-xg4#-0o{?bKu8ga^?JKk$ zhaMY5RFi8KqGM*_@k#kV);PXs@p;9xI(eqJ}{bYH)he0y`XOU6ysYmF&lvKznR zGT`*C>8_bpT)|j{DR_nNev-1XQU&qsXWdsANSRMKDW+brp(`tdmkAJ&mt}u_U;Xp-)Ktj` ziYa?R=D~nC-U*}eANEe_Jaa=qkNx16Z6Lm!bH9y{0Lmw(fW`1njpkUoSVp=9-LEpl zj@E6GtKk~11yxyGfPa}b&yA-y>0F1v92i5n-!LJ}wTXiTC+>Yr{2W;ATrsDodhKR}2Vuc3$M~!0oNLwi19Nw8Y zc9AOYvY{VvDn=)9wj~8UUr<%Qu6@!;{)8fQCmofF=TR;jOOC9R=igZzd`oMz<1ex! zo4VLgfIpx1A>{o8eijb+ey3WgstEqJ7tU~|Dh`%^4C5AZBAe*L1@TiVd0 zDOmdO-6#D<(Xf3wn$s>$)UN)?&oLU7oW82URzj7Mq-Z*eVAd*UXsn%S#J&dOt`S?? zioq?uS$|dhwxX7FaF*s-W%}_hC}Rv6r0b-9GObEXeks@w&ERJIY@YqDf0<8c*?HUy zlVznP@*Fz4B@8`RU2Gr!ZR+HUZ|S9pmlKDuGuZl-BrorbG#88bU4zbu^fcNuEn3fY zG~{0y6_Iru8iSgydX+-sV9ZlG2)p3J?ULX zb7`(<>^f>)g{SzSeC&j#|6^WdvT7kzOkF6TF6FIRUCyu?BUf`+YZJ$GYbnp)i}pHf>^}nE_&lOA9=@WTD0v0eDy|jKwC=X( z60O!=7jb2D_j4~jcsbY9;5VU=HigVK?g7);d6(w=>419$N;4cZaI5X?Qdw}C6nL@L zu;C_F?K@r>h`tgT()y zxBII&Eib{zpYc~sNKb8RM-mu-R~&w{9pzySbp#~KiVSv)YjDQxD68AS{`QXBv$&^( zzNqGg(|m0qR@Mh4tWSm}EWMFiVSaF$TNS@r84j$N`HssA>|Ej<6MEvCU~%G6oR(|) zV0!bV4jfM;AA#=ru*aJ9o};hQ-6l}_aipTf7Poo!)wlWJ*{3O%+Q~%!Wzn%8-r3HY z5Y49Dvu`SIMI>r1orJF)!l2ke`02bsXvi&&S`M*Ywye1KtFfZ4cl~`o;6nf--BVNB zf1lz}Cf#x;d7fsnOQ4=usU!Sl(aZ^3DIJkDL-fH9$c9^q!q#N3W5U^K)8TjWF}d~i z&r05XP`wgWy_yHot~Li1Mw*treGdKuX&=Pd&o}9qSJ}3 zmJ}4B_2URi3Ok}>GI;WQPGZueJV_9_Fr>W!bgK1)yq%lOkZ&decGZf<4Ea#QbVkGR zZ?YnYpCyo@cp7XSH(m#e79g^V-K*I6o5qB8wjKsi+R#HIaWAD1;IA4aVkPmj6+~kf z<`7+OrK?cC&s~Elk0_e}Lxj{vW^so?U z*0~Fgp?T2*IEL20WU^z}mI7Ib&dYc^+M1=6DQtG(873ra!6?hU_fo10FKpB!*&;f= z=$~tdn}+>cBY}ERf0ToQ3V@CgR@HlEG;Ev^5OcJ;IuU|Zkip#LoD38Dd(7lzmbb1g zE2@|T={0Kui}+Fyxpc%hcT_A9hG95;*Y~M=DWuJ@$9AKJt?v&69P*J?;y1{2b+uyQ z^u$jg#)5a4Yhp0-vI|SHNPh+~fC#((L+gWA3JUli$1(%Xk{!^29E2x@F*`xB?=)0y z-i!*p2Y5r&;KD;n=A>Q9e+PPaO0lejz>%_s0_e!*S7Yu^}PZlb8*;1g+j^W?(} z|2?E{H=>zI)t>A!(alU4CrRS3q(i&${w3+|D+(2`%i(M37{FF7GOPTX7^v0@zeMpb z+KjI1bcDiW8G-zuorShb#*ibXD^}fCpG=@p$80%o+N+1I1yGtEP6b5w8TjG_wAX7; zb&_mQz1V@xTU}S-u(DKL^9C*ArQ(r3JlP&jkZkyF(9~ZrKODdE7wCG3;PRe}2 z(m#oo7nCz)R;l>V?<&ne74i@cm`h<>E{`s=s2u#cLbi}s+OUkl%|SWz64-vAz#qK| z9=L*(qaKfA4nng>t*!zPO-~TU1(bNY-RGKBRiR&ECI?z2u$6#3nZLl#z`UYhUU_W zLaHLSIA`OA^8)vYaD=q@)7k9vgFN=0A(6eXt6zdcu8)FE;h+6&K5U#!slkcJJ%Sex`?GPOX^bV zHr?OUlY==bER&Yl8}+!w;f8ODUyR?) zAq!fR`Hd6{AP{8~b)B9Gc_YW>YhpNi(sX<>8zO7t_9(z}bgds&<@P=km|5mAEP|Bw zm|exb4<25OY{X!5D@N{|(&7)&wj}VmRrdFZYSJ$Sb5`cab9 zeEhHzTSKDuhook!awEkWJPKCqed>EG?!15DF*N{g%Lx+Al){asbB30YY&K;eOl%K; z7seyrv>l1Lm#&5DvI1vLKJIhrymhI*zRzwA$F9NhmoPRQ7ygGLO+4nt>0ddLx?SJA z(*G!e5jQ9~BZhAO$=`(E<=gKfOb=>G&Nh}ZZe@H(@RM##;GKmiKv%}}H-|YkxGk2m zfSEDG$l;IatOX-th|+c*RCd#4<^z$x$LKo!k+Zl0^FT?pmdcyCBn-X_DXrbDFEi5hcV^@6&>pkjaa&*M9d=v4xEy)30)%G#^@(f zv%ol?8$F`gG;P+cqS1PG;04oKsr$=$Ns0;Gws>?PKjuPB6D-99o|8B3cxqaJzyb0HNcP5k&q6 z3)sO}wBk`e0o9y|UTmTgE=l&8$tK*ey2P*suI2Ah*|`N);*gRq4 zdRMi#UIpPv_t_peQG6%55kle5EE*ya8$7N4ToXH-M z0y+{?eGZ+y#)3I2=Am9sbnkjr~v(DzfxwDGVrMrh@b>P_ieoYGmH)q7mlT<*A&fL>@Nn$hF zDS}4PaL)jzJ&zWK)TD>G&pUPHac{#F_?!5ymHi@hwfF9)P@UQ4D(E+5{Ex%b_xCQQT2IXuw9{}jBIfin ziPS~k_6{$f952IHXK#bi-HR0md3FpG0VkW8@X`B%1l6j2rKehkeIhq-WdE7rQE@!Y zxl`Ajp{c<1y@1!7Pur>1;ILrHQEr?SM*v4$zb)Sn8kcm745JKY?}!h_N(lB0lih1p zf0H%rh2x!e+GqOEOJy-Qk1b5Se9A!G-m3}p%D#?N0%b-GqI7AvzFCy*qs6{ zPoB{7Gy|KMI60GjZA{V6%+c*eArYwhr~*WBF6C=r)ta|)A#arXBYl7QHr&L?&?y<* zXj8_qPMo zbp7lC)D4qP_aM3jiK-T$*?|VyV#03bj^HXPK^c*%+d{>iM#y#trp~)J-XI7A+#D7* z9o;E*^ytt#C-hYb8;i_Q{GRp6gdQcFGt5BPCG#4c-J+W;0&8bt_%{s>PrB-B0`waA z85lRDOE4s9@#ivMbJ#V%bl2BvMVvJK$%H1I zz3xlQ>4ns`KIc%z`kZRgp0%v-+L=h8#Dim zZETE8*d6oP2xm?TC}7(6-I8rZeKp2y>sn0ilD3yBx2z}ae2Jl;j2gzcDy)EE9(tYD z*cK*9XnMZJ#Gw&sACkI_$(@tW^=|=MCeo9LZILbZL8%UpmVMdrC-zBN3*j$(FQl!y`ipY3zox z$ao84TsT9VjlE%Nyo`b&U1>voe@XK&je2|;Z_&V~_k5oy5IB^1wWo8OceK{T8R=bV zUdtvj30kApcP35qcmT%fL-_zwYgOYURtTd5baZsLTx?U`jH!J@Y;&IJ6$v&@1)C)B zJ^KyPZC_QH&O|S+M%z-<{l>jN*(-Wp4uM<3#Sw}0nOPG zoF(oz7hkcZHKGQ#fZiHA{*G0a|SA=ld03NX&tB#Qt}tScdDuG)MQ{tJp#P zXgXxY@utU1t)tOhmM{J-KMIw6Te$X})o^^LQe@*AaA*%E16Gf}GZeY8ZfL+5!b?0% zH`=dZ3ESzrqdL?B<7ig5{x&_JWI*VQ`-X_fogJGxSr*Y?LRgx7Uwth^djFGF`tl6- z@kZ!JjG?=+s$VXomH(&s=)+cLN0ghCck%f&Rp4uf(2sv7vK&(F({+n}R>O>j{H>y5 zh6AuO0lVMnnDQ8oKljOyPSW8_BOZdE87L&7CmAjt7>h`ypvqKmQko}!3^bt3+tBV; zZYQ;D}ZfJiBCAwHp=FNYys~&%lr~j0Jpuvh>kB6y2#mWsGkIe*uE!j>ua+S#F^dou?hk zjT_wL{if818{Xn)98p9#FN9x!j3)f2GKgi$N15dmb49nC`*KP=bQ#;E(%g}_vIqOFdi1D-z5r_+ZL2EBSMVW%HCLw$keKm zOoe>jJOqZ1{5Yk*>wkNi*HQSZ*SXWOsBMtF$2`b$>S ztsMxM{+lzw?Dl0fRRDcuL_S$hs-PBd}g=apHL@Cx$p*wn!@{53cca~jlhbmQH#0pQOzcqS;W@t!cK+K z%RQeD%mxnRueM~tu}Z@^YZwP!r84h-i)CguYw}cjgJ;Q}a5V|$O3L{xjUP$w>ZybH zm-Neb21E2h+v!ua?;h?d6oIO1D&nHJ%sOcWfL?h#56lhH;od9YT2PjBy!`b>%8P+l z(y6VCz=m71cK~)6F{AgXe$OmLgK;VGl{Q0DA(Q6Kd1e{F@V5N*BbL>F=;`XA+0KA` z5$?ZFW(h@RMpr}uto@_}CJ%EYyr2;S44d1P7OtPiNr>^!8rW$jN)7H3oNrZNN|jwo zwZS$yzDkvLq4*?DX-zH6lhHXA{YzJW^_(0a1*h{HuGjh^>HLg8QPS#M(&Img zqkKEGJ+Qc{dhRY@U;BT(`u|h9;;+Y~&&VGY{p~qYUT7Yg&0AbOfP)>&2W6wRRFSs3 zy#n!tqklG!K@))8ntgRF@Q@We5T@2rNq5ZCoPWc1&S?r_aYJLPME6^+4c+zJ=}L&y z>b+nPMJ#SLGo%hj(it>eB@l;0X%8G-T}wf33i@+^{*8Opop~WtWdo9{&Eh>hg=m;K zEVCuVDJ}NA;Renp2Jlj^!V`YPN)x)X-yX<(0~IgrLm|n2VHaI*MfGSv*s6(PPgV~> zSUay+_8r0!mYA%+z$!MUzv2#q57a^{k^XUIVz{`%5*G@W`Ii%K)O`dL=4zxO8)1|# zfG_bog+JdXbl0;-ueLbnV~4pksX<`VFDUK5W!7f?7>_K^1*saj(620juDN-@IVw6c zDaU74Mi_>PUYFy+ezcU05^!;=dP~R|H!Awrq+8=QirX2&5?5RS$*CWBqJ)nP5pAMp zJ@hed`XV~hNfvV_yY^XEn&(79MnQpQv+M%0N^$6PXvxW#E>cE!i+aPR{b_Eb8{rmG zxEJ6x6Bj9{P;EaB+fvf=UTyBY(3tK{^yEK;+#m!R~htp8#koPv^WvNL0 zJnl(y!J~eiR+A+F?~5h;`w@Aw7rF(ChJd5$BU*+{J+$DQd#x)`m~^yUKNcsQuW7*> zX%rl}A*$q4{B7bL;zmD}^rJ6k=CM8>{P-9*)$#HuK0yPlc|nhRw~ zt>umH$;*p_;7<1j6W6%X252pnR8CI4bt#`hFAMtpn*IyU4nmfKLgV_l=|?i;fdpWThyw;?Cdab%Fw`dmPker^Y8&SJXz z50^Z1A|cgqALUI4|02sI-h`pM8?5Jp#gMG>oFY(5n5(5=$>n*^SoT#Cts}az{cy)qMv>PkEtY1k>`7;cQGu zx#wWkk#lS*0}>@*Ud&kv?UYmWC*+;uJupVub$WDpm<7`^ydgn13(hCHkQ!Vd3Bc8% zs-oFN1dn`&@dB-bszB|i&m*O?Lf1ok6obH6Glj*YN-q3f6QzyMBa|Y1_gRn* z9^&-*6lYJpuH{ng?tj*%d$LD+lo?KE89Kr3Ux(YN4iEfAGr*ub0FJg>__huT0;3U; z#g?y`m>fbf1y52OE^8EM19{knK1gxWQKGZ`X%uB>TtRn7j}dmzgXQi%Zv-jZ)zyLU z$xmXIKxVv^PVqX;r@6I7mGSj0NcJc!;ig{&#zlW&rK5f-s)x=(X#cBeL`Tqug=0Jg zk4eWQEh{g~u(N7*30C|q=;oq1U!1wf#PAxk)MNd`p~0sO#ZR!C%ddalg&;c09z}a8 zowmeTLs<5>_I7^9g4LkzewTng?;@EXlXJX+E*XFaG_^A(GU*`0ZDhziQD1c0wzgY_ zFP_0&q+Guaw`EM2r{$FYz4!jerH%_kOUQzd6%MAoP+uy7$Uy@1Z7PK`MYVH#zvf0N z%XWc6w|KfSwq@a?<g9sf#oxns)c$fzu-IoaQh%Nefey3}<{Kj72}pWTXD z4419tBjx8}JRZ>WpJRHzyN>}qxR82-gY-^%P z(=QyqaIZQ4o+;i__e2qCPLV+^GM}b@;VdUA8hxEfi7#n-WY*4v(JSIhY4z7^5=&_U ze*y$QcPrf??>YvQCFvpMDSz`GCtR)j5ppmW!&$8R_Nxrf*4Zb59)}_ObCdBu1l_+O zugO?U!#aoENi`bztCNQGMhk39{j*wosRsou9jtNgzi1)E~bLE4n76N8B zv?GE{&|H-MG;*YH8m+0LKcIh9oFt?z>-_a zOo)tqSq|rU>>^aPlg1LEN`f$0H%uWGf|f0A^%`^O+Qj`A^ukPsX_WZ&cyuaBE}(Mf zNC@uGg~fw}3gT7Yje`CUF>%|r literal 0 HcmV?d00001 diff --git a/max/private_static/favicons/paw-prints_1f43e.png b/max/private_static/favicons/paw-prints_1f43e.png new file mode 100644 index 0000000000000000000000000000000000000000..99750855f5c35a32ef2b2943e4781b423c49d0bc GIT binary patch literal 5454 zcmV-U6|w4xP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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 Ef<0hB;{X5v literal 0 HcmV?d00001 diff --git a/max/private_static/favicons/pouting-cat_1f63e.png b/max/private_static/favicons/pouting-cat_1f63e.png new file mode 100644 index 0000000000000000000000000000000000000000..4add1ecaa076d3639f8a6c5864c23f971af3f677 GIT binary patch literal 8405 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 WLp<<35yujdkQCpk$yQ36hWtN@h*`P- literal 0 HcmV?d00001 diff --git a/max/private_static/robots.txt b/max/private_static/robots.txt new file mode 100644 index 0000000..77470cb --- /dev/null +++ b/max/private_static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file diff --git a/max/routes/__init__.py b/max/routes/__init__.py new file mode 100644 index 0000000..9df9292 --- /dev/null +++ b/max/routes/__init__.py @@ -0,0 +1,63 @@ +from max.auth import no_authentication_required +from max.csrf import no_csrf + +from .alias.create import AliasCreate +from .alias.delete import AliasDelete +from .alias.detail import AliasDetail +from .alias.edit_note import AliasEditNote +from .alias.toggle_enabled import AliasToggleEnabled +from .favicon import Favicon +from .robots import RobotsTXT +from .user.change_password import UserChangePassword +from .user.create import UserCreate +from .user.delete import UserDelete +from .user.detail import UserDetail +from .user.edit_note import UserEditNote +from .user.list import UserList +from .user.toggle_enabled import UserToggleEnabled + + +def init_routes(app): + app.add_url_rule("/", "user-list", UserList.as_view()) + app.add_url_rule("/user/create", "user-create", UserCreate.as_view()) + app.add_url_rule( + "/user//change-password", + "user-change-password", + UserChangePassword.as_view(), + ) + app.add_url_rule( + "/user//edit-note", "user-edit-note", UserEditNote.as_view() + ) + app.add_url_rule( + "/user//toggle-enabled", + "user-toggle-enabled", + UserToggleEnabled.as_view(), + ) + app.add_url_rule("/user//delete", "user-delete", UserDelete.as_view()) + app.add_url_rule("/user/", "user-detail", UserDetail.as_view()) + app.add_url_rule( + "/user//aliases/create", "alias-create", AliasCreate.as_view() + ) + app.add_url_rule("/alias/", "alias-detail", AliasDetail.as_view()) + app.add_url_rule( + "/alias//delete", "alias-delete", AliasDelete.as_view() + ) + app.add_url_rule( + "/alias//edit-note", "alias-edit-note", AliasEditNote.as_view() + ) + app.add_url_rule( + "/alias//toggle-enabled", + "alias-toggle-enabled", + AliasToggleEnabled.as_view(), + ) + + app.add_url_rule( + "/robots.txt", + "robots", + no_csrf(no_authentication_required(RobotsTXT.as_view())), + ) + app.add_url_rule( + "/favicon.png", + "favicon", + no_csrf(no_authentication_required(Favicon.as_view())), + ) diff --git a/max/routes/alias/create.py b/max/routes/alias/create.py new file mode 100644 index 0000000..3f57b8e --- /dev/null +++ b/max/routes/alias/create.py @@ -0,0 +1,57 @@ +from flask import flash + +from max.db import EmailAlreadyExists, create_alias + +from ..base_alias_views import BackToAliasesMixin +from ..base_user_views import FetchUserTemplateGetView + + +class AliasCreate(BackToAliasesMixin, FetchUserTemplateGetView): + template_name = "alias/create.html" + + def get_webpagetitle(self): + return f"Create new alias for {self.user.email}" + + def post(self): + error = False + email = self.request.form.get("email") + if not isinstance(email, str) or not email: + flash("Email must be given", category="error") + error = True + else: + self.email = email + + enabled = self.request.form.get("enabled") + if enabled == "on": + self.enabled = True + elif enabled is None: + self.enabled = False + else: + flash("Enabled is not set", category="error") + error = True + + note = self.request.form.get("note", "") + if not isinstance(note, str): + flash("Not emust be a string", category="error") + error = True + else: + self.note = note + + if error: + return # force re-rendering + + try: + create_alias(self.email, self.user, self.enabled, self.note) + except EmailAlreadyExists as e: + flash(f"Email already exists: {e.msg}", category="error") + return + + flash(f"Creation of alias {email} was successful!", category="success") + return self.redirect() + + def get_context(self): + context = super().get_context() + for key in ("email", "enabled", "note"): + if hasattr(self, key): + context[key] = getattr(self, key) + return context diff --git a/max/routes/alias/delete.py b/max/routes/alias/delete.py new file mode 100644 index 0000000..1554cde --- /dev/null +++ b/max/routes/alias/delete.py @@ -0,0 +1,14 @@ +from flask import flash, url_for + +from max.db import delete_alias + +from ..base_alias_views import BackToAliasesMixin, FetchAliasTemplateGetView + + +class AliasDelete(BackToAliasesMixin, FetchAliasTemplateGetView): + template_name = "alias/delete.html" + + def post(self): + delete_alias(self.alias) + flash(f"{self.alias.email} was deleted successfully", category="success") + return self.redirect(url_for("user-detail", user_id=self.user.id)) diff --git a/max/routes/alias/detail.py b/max/routes/alias/detail.py new file mode 100644 index 0000000..ae2d066 --- /dev/null +++ b/max/routes/alias/detail.py @@ -0,0 +1,8 @@ +from ..base_alias_views import BackToAliasesMixin, FetchAliasTemplateGetView + + +class AliasDetail(BackToAliasesMixin, FetchAliasTemplateGetView): + template_name = "alias/detail.html" + + def get_webpagetitle(self): + return self.alias.email diff --git a/max/routes/alias/edit_note.py b/max/routes/alias/edit_note.py new file mode 100644 index 0000000..dd745da --- /dev/null +++ b/max/routes/alias/edit_note.py @@ -0,0 +1,24 @@ +from flask import flash + +from max.db import update_alias + +from ..base_alias_views import BackToAliasesMixin, FetchAliasTemplateGetView + + +class AliasEditNote(BackToAliasesMixin, FetchAliasTemplateGetView): + template_name = "alias/edit-note.html" + + def get_webpagetitle(self): + return "Edit note for " + self.alias.email + + def post(self): + note = self.request.form.get("note", "") + if not isinstance(note, str): + flash("invalid data", category="error") + return + + self.alias.note = note + update_alias(self.alias) + + flash("Note changed successfully!", category="success") + return self.redirect() diff --git a/max/routes/alias/toggle_enabled.py b/max/routes/alias/toggle_enabled.py new file mode 100644 index 0000000..387fa32 --- /dev/null +++ b/max/routes/alias/toggle_enabled.py @@ -0,0 +1,12 @@ +from max.db import update_alias +from max.views import BaseView + +from ..base_alias_views import BackToAliasesMixin, FetchAliasMixin + + +class AliasToggleEnabled(FetchAliasMixin, BackToAliasesMixin, BaseView): + def post(self): + self.alias.enabled = not self.alias.enabled + update_alias(self.alias) + _, back_url = self.get_back_text_and_url() + return self.redirect(back_url) diff --git a/max/routes/base_alias_views.py b/max/routes/base_alias_views.py new file mode 100644 index 0000000..10be038 --- /dev/null +++ b/max/routes/base_alias_views.py @@ -0,0 +1,31 @@ +from flask import flash, url_for + +from max.db import get_alias_with_user_by_id +from max.views import BaseTemplateGetView + + +class FetchAliasMixin: + def before_handler(self): + result = get_alias_with_user_by_id(self.alias_id) + if result is None: + flash( + f"The alias with id {self.alias_id} does not exist.", category="error" + ) + return self.redirect() + self.alias, self.user = result + + +class FetchAliasTemplateGetView(FetchAliasMixin, BaseTemplateGetView): + def get_context(self): + context = super().get_context() + context["alias"] = self.alias + context["user"] = self.user + return context + + +class BackToAliasesMixin: + def get_back_text_and_url(self): + if self.request.args.get("return") == "detail": + return self.user.email, url_for("alias-detail", alias_id=self.alias.id) + else: + return self.user.email, url_for("user-detail", user_id=self.user.id) diff --git a/max/routes/base_user_views.py b/max/routes/base_user_views.py new file mode 100644 index 0000000..c3be0ed --- /dev/null +++ b/max/routes/base_user_views.py @@ -0,0 +1,27 @@ +from flask import flash, url_for + +from max.db import get_user_by_user_id +from max.views import BaseTemplateGetView + + +class FetchUserMixin: + def before_handler(self): + self.user = get_user_by_user_id(self.user_id) + if self.user is None: + flash(f"The user with id {self.user_id} does not exist.", category="error") + return self.redirect() + + +class FetchUserTemplateGetView(FetchUserMixin, BaseTemplateGetView): + def get_context(self): + context = super().get_context() + context["user"] = self.user + return context + + +class BackToUsersMixin: + def get_back_text_and_url(self): + if self.request.args.get("return") == "detail": + return self.user.email, url_for("user-detail", user_id=self.user.id) + else: + return "User list", url_for("user-list") diff --git a/max/routes/favicon.py b/max/routes/favicon.py new file mode 100644 index 0000000..e8f071e --- /dev/null +++ b/max/routes/favicon.py @@ -0,0 +1,28 @@ +import os +import random + +from flask import current_app, send_from_directory + +from max.views import BaseView + + +FAVICON_FOLDER = "private_static/favicons" +STATE_FAVICON_ATTR = "available_favicons" + + +class Favicon(BaseView): + _state = {} + + def get(self): + random_favicon = self.get_random_favicon_filename() + return send_from_directory(FAVICON_FOLDER, random_favicon, add_etags=False) + + def ensure_favicons(self): + if STATE_FAVICON_ATTR not in self._state: + directory = os.fspath(FAVICON_FOLDER) + directory = os.path.join(current_app.root_path, directory) + self._state[STATE_FAVICON_ATTR] = [a for a in os.listdir(directory)] + + def get_random_favicon_filename(self): + self.ensure_favicons() + return random.choice(self._state[STATE_FAVICON_ATTR]) diff --git a/max/routes/robots.py b/max/routes/robots.py new file mode 100644 index 0000000..01c7be5 --- /dev/null +++ b/max/routes/robots.py @@ -0,0 +1,8 @@ +from flask import send_from_directory + +from max.views import BaseView + + +class RobotsTXT(BaseView): + def get(self): + return send_from_directory("private_static", "robots.txt") diff --git a/max/routes/user/change_password.py b/max/routes/user/change_password.py new file mode 100644 index 0000000..16c86cd --- /dev/null +++ b/max/routes/user/change_password.py @@ -0,0 +1,31 @@ +from flask import flash, session + +from max.auth import change_password +from max.sessions import session_storage + +from ..base_user_views import BackToUsersMixin, FetchUserTemplateGetView + + +class UserChangePassword(BackToUsersMixin, FetchUserTemplateGetView): + template_name = "user/change-password.html" + + def get_webpagetitle(self): + return "Change password for " + self.user.email + + def post(self): + pw1 = self.request.form.get("password1") + pw2 = self.request.form.get("password2") + if not pw1 or not pw2: + flash("Both passwords must be given", category="error") + return + if not isinstance(pw1, str) or not isinstance(pw2, str): + flash("Invalid data") + return + if pw1 != pw2: + flash("Both password must be the same", category="error") + return + + change_password(self.user, pw1) + session_storage.remove_user_sessions(self.user.id, except_id=session["user_id"]) + flash("Password changed successfully!", category="success") + return self.redirect() diff --git a/max/routes/user/create.py b/max/routes/user/create.py new file mode 100644 index 0000000..7168038 --- /dev/null +++ b/max/routes/user/create.py @@ -0,0 +1,71 @@ +from flask import flash + +from max.auth import hash_password +from max.db import EmailAlreadyExists, create_user +from max.views import BaseTemplateGetView + +from ..base_user_views import BackToUsersMixin + + +class UserCreate(BackToUsersMixin, BaseTemplateGetView): + template_name = "user/create.html" + webpagetitle = "Create new user" + + def post(self): + error = False + email = self.request.form.get("email") + if not isinstance(email, str) or not email: + flash("Email must be given", category="error") + error = True + else: + self.email = email + + pw1 = self.request.form.get("password1") + pw2 = self.request.form.get("password2") + if not pw1 or not pw2: + flash("Both password must be given", category="error") + error = True + elif not isinstance(pw1, str) or not isinstance(pw2, str): + flash("Invalid data") + error = True + elif pw1 != pw2: + flash("Both password must be the same", category="error") + error = True + else: + self.password = pw1 + + enabled = self.request.form.get("enabled") + if enabled == "on": + self.enabled = True + elif enabled is None: + self.enabled = False + else: + flash("Enabled is not set", category="error") + error = True + + note = self.request.form.get("note", "") + if not isinstance(note, str): + flash("Not emust be a string", category="error") + error = True + else: + self.note = note + + if error: + return # force re-rendering + + passwordhash = hash_password(self.password) + try: + create_user(self.email, passwordhash, self.enabled, self.note) + except EmailAlreadyExists as e: + flash(f"Email already exists: {e.msg}", category="error") + return + + flash(f"Creation of {email} was successful!", category="success") + return self.redirect() + + def get_context(self): + context = super().get_context() + for key in ("email", "password", "enabled", "note"): + if hasattr(self, key): + context[key] = getattr(self, key) + return context diff --git a/max/routes/user/delete.py b/max/routes/user/delete.py new file mode 100644 index 0000000..e266236 --- /dev/null +++ b/max/routes/user/delete.py @@ -0,0 +1,23 @@ +from flask import flash, session, url_for + +from max.db import delete_user +from max.sessions import session_storage + +from ..base_user_views import BackToUsersMixin, FetchUserTemplateGetView + + +class UserDelete(BackToUsersMixin, FetchUserTemplateGetView): + template_name = "user/delete.html" + + def get_webpagetitle(self): + return f"Delete {self.user.email}" + + def post(self): + if self.user.id == session["user_id"]: + flash("You cannot delete yourself", category="error") + return self.redirect() + + delete_user(self.user) + session_storage.remove_user_sessions(self.user.id) + flash(f"{self.user.email} was deleted successfully", category="success") + return self.redirect(url_for("user-list")) diff --git a/max/routes/user/detail.py b/max/routes/user/detail.py new file mode 100644 index 0000000..9b48460 --- /dev/null +++ b/max/routes/user/detail.py @@ -0,0 +1,20 @@ +from flask import url_for + +from max.db import get_aliases + +from ..base_user_views import FetchUserTemplateGetView + + +class UserDetail(FetchUserTemplateGetView): + template_name = "user/detail.html" + + def get_webpagetitle(self): + return self.user.email + + def get_back_text_and_url(self): + return "User list", url_for("user-list") + + def get_context(self): + context = super().get_context() + context["aliases"] = get_aliases(self.user_id) + return context diff --git a/max/routes/user/edit_note.py b/max/routes/user/edit_note.py new file mode 100644 index 0000000..1dbb6d7 --- /dev/null +++ b/max/routes/user/edit_note.py @@ -0,0 +1,24 @@ +from flask import flash + +from max.db import update_user + +from ..base_user_views import BackToUsersMixin, FetchUserTemplateGetView + + +class UserEditNote(BackToUsersMixin, FetchUserTemplateGetView): + template_name = "user/edit-note.html" + + def get_webpagetitle(self): + return "Edit note for " + self.user.email + + def post(self): + note = self.request.form.get("note", "") + if not isinstance(note, str): + flash("invalid data", category="error") + return + + self.user.note = note + update_user(self.user) + + flash("Note changed successfully!", category="success") + return self.redirect() diff --git a/max/routes/user/list.py b/max/routes/user/list.py new file mode 100644 index 0000000..eedc704 --- /dev/null +++ b/max/routes/user/list.py @@ -0,0 +1,12 @@ +from max.db import get_users +from max.views import BaseTemplateGetView + + +class UserList(BaseTemplateGetView): + template_name = "user/list.html" + webpagetitle = "Main" + + def get_context(self): + context = super().get_context() + context["users"] = get_users() + return context diff --git a/max/routes/user/toggle_enabled.py b/max/routes/user/toggle_enabled.py new file mode 100644 index 0000000..10aa322 --- /dev/null +++ b/max/routes/user/toggle_enabled.py @@ -0,0 +1,12 @@ +from max.db import update_user +from max.views import BaseView + +from ..base_user_views import BackToUsersMixin, FetchUserMixin + + +class UserToggleEnabled(FetchUserMixin, BackToUsersMixin, BaseView): + def post(self): + self.user.enabled = not self.user.enabled + update_user(self.user) + _, back_url = self.get_back_text_and_url() + return self.redirect(back_url) diff --git a/max/sessions.py b/max/sessions.py new file mode 100644 index 0000000..af6e2b2 --- /dev/null +++ b/max/sessions.py @@ -0,0 +1,131 @@ +from flask.sessions import SessionInterface as FlaskSessionInterface, SessionMixin +from itsdangerous import BadSignature, Signer, want_bytes +from werkzeug.datastructures import CallbackDict + +from max.crypto import get_random_string + + +class SessionStorage: + def __init__(self, maxcap=100): + self.maxcap = maxcap + self.lru_ids = [] # newest ids are on the end (so do append to add a fresh id) + self.data = {} + + def __getitem__(self, id): + if id not in self.data: + return None + + self._refresh_id(id) + return self.data[id] + + def __delitem__(self, id): + if id in self.data: + del self.data[id] + self._remove_id(id) + + def __setitem__(self, id, data): + self._refresh_id(id) + self.data[id] = data + + while len(self.lru_ids) > self.maxcap: + removed_id = self.lru_ids.pop(0) # remove first element + del self.data[removed_id] + + def _remove_id(self, id): + self.lru_ids = [_id for _id in self.lru_ids if _id != id] + + def _refresh_id(self, id): + self._remove_id(id) + self.lru_ids.append(id) + + def remove_user_sessions(self, user_id, except_id=None): + ids_to_remove = [] + for id, data in self.data.items(): + if data.get("user_id", None) == user_id and id != except_id: + ids_to_remove.append(id) + + for id in ids_to_remove: + del self.data[id] + self._remove_id(id) + + +session_storage = SessionStorage() + + +class Session(CallbackDict, SessionMixin): + def __init__(self, id=None, data=None): + def on_update(self): + self.modified = True + if not self.id: + self.set_new_id() + + self.id = id + self.modified = False + CallbackDict.__init__(self, data, on_update) + + def is_empty(self): + return len(self) == 0 + + def clear(self): + self.id = None + super().clear() + + def set_new_id(self): + self.id = get_random_string(32) + + +class SessionInterface(FlaskSessionInterface): + def _get_signer(self, app): + if not app.secret_key: + return None + return Signer(app.secret_key, salt="flask-session", key_derivation="hmac") + + def get_cookie_name(self, app): + return app.session_cookie_name + + def make_session_object(self, session_id=None, data=None): + return Session(session_id, data=data) + + def open_session(self, app, request): + session_id = request.cookies.get(self.get_cookie_name(app)) + if not session_id: + return self.make_session_object() + + signer = self._get_signer(app) + if signer is None: + return None + try: + sid_as_bytes = signer.unsign(session_id) + session_id = sid_as_bytes.decode() + except BadSignature: + return self.make_session_object() + + if not isinstance(session_id, str): + session_id = session_id.decode("utf-8", "strict") + + data = session_storage[session_id] + return self.make_session_object(session_id, data=data) + + def save_session(self, app, session, response): + domain = self.get_cookie_domain(app) + path = self.get_cookie_path(app) + cookie_name = self.get_cookie_name(app) + if session.is_empty(): + if session.modified: + del session_storage[session.id] + response.delete_cookie(cookie_name, domain=domain, path=path) + else: + httponly = self.get_cookie_httponly(app) + secure = self.get_cookie_secure(app) + expires = self.get_expiration_time(app, session) + session_storage[session.id] = dict(session) + session_id = self._get_signer(app).sign(want_bytes(session.id)) + response.set_cookie( + cookie_name, + session_id, + expires=expires, + httponly=httponly, + domain=domain, + path=path, + secure=secure, + ) diff --git a/max/static/arrow.png b/max/static/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..3867a5cb55660c7acdfebf5c71818a20fabb2d02 GIT binary patch literal 662 zcmeAS@N?(olHy`uVBq!ia0vp^20*OA!2%?O`ZoRoQY`6?zK#qG8~eHcB(ehe3dtTp zz6=aiY77hwEes4GB@Hha7)pT}UnMXwSj}Ky5HFasE6@fg!Ib3f?!xfDz5mR9Adj=a zBeIx*fm;}a85w5HkpK#^mw5WRvOi&#<&!qwf85oQfq^l_)5S5w~wxGDX|G&Ih~R!6n`*j;+5Y^rg~V<;=NRn|Iv7b^_O|uF8-c# zu=v{S`|sye`^^(y>8uc>6R_+A593_B|Je#vkq<>1*wcDNJ49CR`79l}?B&OHb`9f% z&iL#@hixP0S6D2%&$a*Ef$0+FJ5pS__6XZ|CUFbY?)xZxMd`<*{Ri`{J_?8Z(4GHd zOa7m2%=Lep-`8zDe&4{=Vbg0-g((hR*^$LwZhT>Zu7ySEzN~M%dy2oCeLOhN<`LsO z;gG4FzddfX#@1$O-Uz*`{Qu&6)$2Di|M~=amT#V@K;_8fX)VuYi*WAE2;6Qc z690?G{I-&?sDzP+C~vFv^mzt36W%zru9li(^eDQ}?OM=7t(nhzZfPyDJ=(ff>3ztP zHzM!$y_;lsze~Hw?X%gl|Hr~JG65sy4 zB3TC*1(GGM5hc#~xw)x%B@E6*sfi`2DGKG8B^e6tp1uL$jeO!jMXDf0DL^T!WUvYb zBLgD?T?1oXBg+s&BP%0wD^pW#10yQ~gTVcX{U{o8^HVa@DsgL2cy!YksDZ)L)z4*} HQ$iB}eD(aJ literal 0 HcmV?d00001 diff --git a/max/static/base.css b/max/static/base.css new file mode 100644 index 0000000..e36de73 --- /dev/null +++ b/max/static/base.css @@ -0,0 +1,223 @@ +body { + font-size: 16px; +} +table { + width: 100%; + margin-bottom: 20px; + white-space: nowrap; +} +a:link, a:visited, a:hover, a:active { + color: black; + text-decoration: none; +} +a:hover { + color: black; + text-decoration: underline; +} +form { + margin-bottom: 20px; +} +.margin-top { + margin-top: 1em; +} +.pure-form-aligned .pure-controls.checkbox { + margin: .6em 0 .5em 11em; +} + +.header { + width: 100%; + white-space: nowrap; + position: fixed; + left: 0; + top: 0; + + text-align: center; + box-shadow: 0 1px 1px rgba(0,0,0, 0.10); + font-size: 20px; + line-height: 1em; + + background: #363537; + color: white; + + border-bottom: none; + z-index: 4; +} + +.header .heading, .header .side { + padding: 1em; + text-decoration: none; + white-space: nowrap; +} + +.header .side.left img { + height: 1em; + margin-right: .5em; +} + +.header .side div, .header .main div { + display: inline-block; + vertical-align: top; +} + +.header a, .header a:link, .header a:visited, .header a:hover, .header a:active { + color: white; +} + +.header .main .title { + font-weight: bold; + text-transform: uppercase; + background-color: black; + padding: 1em 0; + height: 1em; + width: 5em; +} + +.header .main .right, .header .main .left { + height: 3em; + width: 6em; +} + +.header .main .left { + background: rgb(54,53,55); + background: linear-gradient(90deg, rgba(54,53,55,1) 0%, rgba(0,0,0,1) 100%); +} + +.header .main .right { + background: rgb(54,53,55); + background: linear-gradient(90deg, rgba(0,0,0,1) 0%, rgba(54,53,55,1) 100%); +} + +.header .main img { + height: 3em; +} + +.content-wrapper { + width: 100%; + min-height: 100%; + position: absolute; + top: 0; + background-color: #EEEEEE; +} +.content { + width: 60%; + margin: 70px auto 20px auto; + padding: 5px 15px; + background-color: #FFFFFF; + border: 1px solid #CCCCCC; +} + +.top-row-button { + margin: 1.1em 0; + float: right; +} + +.inline-form { + display: inline-block; + margin: 0; + margin-left: 0.5em; +} +.logout-form { + font-size: 12px; + margin-left: 2em; +} +.logout-form > button { + padding: 4px .75em; + line-height: 1em; +} +.pure-form-stacked label { + margin-top: 1em; +} + +.no-aliases { + margin-bottom: 20px; + text-align: center; + color: gray; +} + +.detail { + margin-bottom: 20px; +} +.detail > div { + margin-bottom: 8px; +} +.detail b { + width: 4.5em; + display: inline-block; +} +.detail form { + margin: 0; +} + +@media (max-width: 1200px) { + body { + font-size: 13px; + } + + table { + white-space: normal; + } + + .header { + font-size: 16px; + } + + .header .main .title { + background-color: inherit; + } + + .header .main .right, .header .main .left, .header .main .logo { + display: none; + } + + .content { + width: calc(100% - 72px); + margin: 60px 20px 20px 20px; + } +} + +@media (max-width: 960px) { + .optional { + display: none; + } +} + +.msg-success, +.msg-error, +.msg-warning, +.msg-message { + color: white; + border-radius: 4px; + padding: 15px 0 20px 30px; + margin: 15px 0; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +} +.msg-success { + background: rgb(28, 184, 65); +} +.msg-error { + background: rgb(202, 60, 60); +} +.msg-warning { + background: rgb(223, 117, 20); +} +.msg-message { + background: rgb(66, 184, 221); +} + +.button-error { + background: rgb(202, 60, 60); +} +.button-success { + background: rgb(28, 184, 65); +} +.button-warning { + background: rgb(223, 117, 20); +} +.button-secondary { + background: rgb(66, 184, 221); +} +.button-success, .button-error, .button-warning, .button-secondary { + color: white; + border-radius: 4px; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +} \ No newline at end of file diff --git a/max/static/eyes-small.jpg b/max/static/eyes-small.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83ac46e1e4b0721f0758d96242d601605b0a15d5 GIT binary patch literal 7650 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 literal 0 HcmV?d00001 diff --git a/max/static/eyes.jpg b/max/static/eyes.jpg new file mode 100644 index 0000000000000000000000000000000000000000..395e3940352de7f0c2bdd5caf8327d0d71f6efe9 GIT binary patch literal 57943 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.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;-webkit-overflow-scrolling:touch;padding:.5em 0}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-disabled,.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected>.pure-menu-link,.pure-menu-selected>.pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0} \ No newline at end of file diff --git a/max/templates/alerts.html b/max/templates/alerts.html new file mode 100644 index 0000000..190d8f0 --- /dev/null +++ b/max/templates/alerts.html @@ -0,0 +1,3 @@ +{% for category, message in get_flashed_messages(with_categories=true) %} +

{{ message }}
+{% endfor %} \ No newline at end of file diff --git a/max/templates/alias/create.html b/max/templates/alias/create.html new file mode 100644 index 0000000..3b506bf --- /dev/null +++ b/max/templates/alias/create.html @@ -0,0 +1,30 @@ +{% extends "base.html" %} +{% block content %} +

Create new alias for {{ user.email }}

+ + {% include "alerts.html" %} + +
+
+ + +
+ +
+ +
+ +
+ + +
+ +
+ {% include "csrf.html" %} +
+{% endblock %} \ No newline at end of file diff --git a/max/templates/alias/delete.html b/max/templates/alias/delete.html new file mode 100644 index 0000000..f0a8074 --- /dev/null +++ b/max/templates/alias/delete.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% block content %} +

Delete alias {{ alias.email }}?

+ + {% include "alerts.html" %} + +
+ + Cancel + {% include "csrf.html" %} +
+{% endblock %} \ No newline at end of file diff --git a/max/templates/alias/detail.html b/max/templates/alias/detail.html new file mode 100644 index 0000000..5498dc1 --- /dev/null +++ b/max/templates/alias/detail.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} +{% block content %} +

Alias {{ alias.email }} for {{ user.email }}

+ + {% include "alerts.html" %} + +
+
+ Enabled: +
+ {{ alias.enabled }} + + {% include "csrf.html" %} +
+
+ Note:{% if alias.note %}{{ alias.note }}{% else %}–{% endif %} + Edit +
+ Delete +
+
+{% endblock %} \ No newline at end of file diff --git a/max/templates/alias/edit-note.html b/max/templates/alias/edit-note.html new file mode 100644 index 0000000..38b493e --- /dev/null +++ b/max/templates/alias/edit-note.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% block content %} +

Edit note for {{ alias.email }}

+ + {% include "alerts.html" %} + +
+ + + +
+ + Cancel +
+ {% include "csrf.html" %} +
+{% endblock %} \ No newline at end of file diff --git a/max/templates/auth/login.html b/max/templates/auth/login.html new file mode 100644 index 0000000..a1011be --- /dev/null +++ b/max/templates/auth/login.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} +{% block content %} +

Login

+ + {% for category, message in get_flashed_messages(with_categories=true) %} +
{{ message }}
+ {% endfor %} + {% if alert %} +
Please login to visit the requested url
+ {% endif %} + +
+
+ + + + +
+
+{% endblock %} \ No newline at end of file diff --git a/max/templates/base.html b/max/templates/base.html new file mode 100644 index 0000000..6d8edb2 --- /dev/null +++ b/max/templates/base.html @@ -0,0 +1,62 @@ + + + + {{ webpagetitle }} – MAX + + + + + + + +
+
+
+ {% if back_text is defined %} +
+
+ +
+ {{ back_text }} +
+
+ {% endif %} +
+ +
+
+ {% if session['user_id'] %} +
+ Hi {{ session['user_email'] }}! +
+
+ + {% include "csrf.html" %} +
+
+ {% else %} + You are not logged in + {% endif %} +
+
+ +
+
+ +
+
+ {% block content %}{% endblock %} +
+
+ + \ No newline at end of file diff --git a/max/templates/csrf.html b/max/templates/csrf.html new file mode 100644 index 0000000..8f2a465 --- /dev/null +++ b/max/templates/csrf.html @@ -0,0 +1 @@ +{% if session['csrf_token'] %}{% endif %} \ No newline at end of file diff --git a/max/templates/user/change-password.html b/max/templates/user/change-password.html new file mode 100644 index 0000000..8166543 --- /dev/null +++ b/max/templates/user/change-password.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{% block content %} +

Change password for {{ user.email }}

+ + {% include "alerts.html" %} + +
+
+ + +
+ +
+ + +
+ +
+ + Cancel +
+ {% include "csrf.html" %} +
+{% endblock %} \ No newline at end of file diff --git a/max/templates/user/create.html b/max/templates/user/create.html new file mode 100644 index 0000000..542f096 --- /dev/null +++ b/max/templates/user/create.html @@ -0,0 +1,40 @@ +{% extends "base.html" %} +{% block content %} +

Create new user

+ + {% include "alerts.html" %} + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ + +
+ +
+ + Cancel +
+ {% include "csrf.html" %} +
+{% endblock %} \ No newline at end of file diff --git a/max/templates/user/delete.html b/max/templates/user/delete.html new file mode 100644 index 0000000..6346c30 --- /dev/null +++ b/max/templates/user/delete.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% block content %} +

Delete {{ user.email }}?

+ + {% include "alerts.html" %} + +
+ + Cancel + {% include "csrf.html" %} +
+{% endblock %} \ No newline at end of file diff --git a/max/templates/user/detail.html b/max/templates/user/detail.html new file mode 100644 index 0000000..49a4d69 --- /dev/null +++ b/max/templates/user/detail.html @@ -0,0 +1,69 @@ +{% extends "base.html" %} +{% block content %} +
+
+

{{ user.email }}

+
+ +
+ + {% include "alerts.html" %} + +
+
+ Enabled: +
+ {{ user.enabled }} + + {% include "csrf.html" %} +
+
+ Note:{% if user.note %}{{ user.note }}{% else %}–{% endif %} + Edit +
+
+ + {% if aliases|length > 0 %} + + + + + + + + + + + + {% for alias in aliases %} + + + + + + + {% endfor %} + +
EmailEnabledNoteActions
+ {{ alias.email }} + + {{ alias.enabled }} +
+ + {% include "csrf.html" %} +
+
+ {{ alias.note }} + Edit + + Delete +
+ {% else %} +
No aliases yet
+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/max/templates/user/edit-note.html b/max/templates/user/edit-note.html new file mode 100644 index 0000000..9ce6ede --- /dev/null +++ b/max/templates/user/edit-note.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% block content %} +

Edit note for {{ user.email }}

+ + {% include "alerts.html" %} + +
+ + + +
+ + Cancel +
+ {% include "csrf.html" %} +
+{% endblock %} \ No newline at end of file diff --git a/max/templates/user/list.html b/max/templates/user/list.html new file mode 100644 index 0000000..46ff979 --- /dev/null +++ b/max/templates/user/list.html @@ -0,0 +1,50 @@ +{% extends "base.html" %} +{% block content %} + +
+
+

Users

+
+ +
+ + {% include "alerts.html" %} + + + + + + + + + + + + + {% for user in users %} + + + + + + + {% endfor %} + +
EmailEnabledNoteActions
+ {{ user.email }} + + {{ user.enabled }} +
+ + {% include "csrf.html" %} +
+
+ {% if user.note %}{{ user.note }}{% else %}–{% endif %} + Edit + + Change password + Delete +
+{% endblock %} \ No newline at end of file diff --git a/max/utils.py b/max/utils.py new file mode 100644 index 0000000..e69de29 diff --git a/max/views.py b/max/views.py new file mode 100644 index 0000000..8963198 --- /dev/null +++ b/max/views.py @@ -0,0 +1,118 @@ +from functools import update_wrapper + +from flask import current_app, redirect as flask_redirect, render_template, request +from werkzeug.exceptions import MethodNotAllowed + +from max.exceptions import ImproperlyConfigured + + +def redirect(url): + return flask_redirect(url, code=302) + + +class BaseView: + url = None + http_method_names = [ + "get", + "post", + "put", + "patch", + "delete", + "head", + "options", + "trace", + ] + + def __init__(self, *args, **kwargs): + self.request = request + self.app = current_app + for key, value in kwargs.items(): + setattr(self, key, value) + + @classmethod + def as_view(cls): + def view(*args, **kwargs): + self = cls(*args, **kwargs) + return self.dispatch() + + # take name and docstring from class + update_wrapper(view, cls, updated=()) + + # and possible attributes set by decorators + # like csrf_exempt from dispatch + update_wrapper(view, cls.dispatch, assigned=()) + return view + + def dispatch(self): + method = request.method.lower() + + handler = ( + getattr(self, method, None) if method in self.http_method_names else None + ) + if not handler: + return self.method_not_allowed_handler() + + before_handler_result = self.before_handler() + if before_handler_result is not None: + return before_handler_result + + return handler() + + def before_handler(self): + """ if something is returned, it is returned as response. """ + pass + + def method_not_allowed_handler(self): + raise MethodNotAllowed() + + def redirect(self, url): + return redirect(url) + + +class BaseTemplateView(BaseView): + template_name = None + webpagetitle = "" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if self.template_name is None: + raise ImproperlyConfigured() + self.context = {} + + def get_context(self): + self.context["webpagetitle"] = self.get_webpagetitle() + back_text_and_url = self.get_back_text_and_url() + if back_text_and_url is not None: + self.context["back_text"] = back_text_and_url[0] + self.context["back_url"] = back_text_and_url[1] + return self.context + + def get_webpagetitle(self): + return self.webpagetitle + + def get_back_text_and_url(self): + """ Return None to hide. Return (str, str) for display name and url """ + return None + + def redirect(self, url=None): + if not url: + ret = self.get_back_text_and_url() + if ret is None: + raise ImproperlyConfigured() + _, url = ret + return super().redirect(url) + + def render(self): + context = self.get_context() + return render_template(self.template_name, **context) + + def dispatch(self): + result = super().dispatch() + if result is None: + return self.render() + return result + + +class BaseTemplateGetView(BaseTemplateView): + def get(self): + pass diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..0ccc4d5 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +black +isort +flake8 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..726c3e5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +flask +psycopg2 +gunicorn diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..a65e7a3 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,13 @@ +[flake8] +max_line_length = 96 + +[isort] +include_trailing_comma = true +multi_line_output = 3 +lines_after_imports = 2 +combine_as_imports = true +force_grid_wrap = 0 +use_parentheses = true +line_length = 88 +known_first_party = max +known_third_party = flask diff --git a/workspace.code-workspace b/workspace.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/workspace.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file