From 782c08d5ee3e88c524c6cf1e564cf24d01b431a8 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Tue, 2 Apr 2019 19:51:38 +0200 Subject: [PATCH] For now, log all incoming POST We want to be able to debug any issue during a command. Hint: DO MORE TESTS! --- copanier/__init__.py | 77 ++++++++++++++++---------------------------- copanier/config.py | 1 + copanier/emails.py | 2 +- copanier/utils.py | 21 +++++++++++- remote/__main__.py | 1 + tests/conftest.py | 2 +- 6 files changed, 51 insertions(+), 53 deletions(-) diff --git a/copanier/__init__.py b/copanier/__init__.py index f9b720b..038e527 100644 --- a/copanier/__init__.py +++ b/copanier/__init__.py @@ -1,16 +1,14 @@ import csv -from datetime import timedelta from pathlib import Path from time import perf_counter -import jwt import ujson as json import minicli from jinja2 import Environment, PackageLoader, select_autoescape from roll import Roll, Response from roll.extensions import cors, options, traceback, simple_server, static -from . import config, reports, session, utils, emails +from . import config, reports, session, utils, emails, loggers from .models import Delivery, Order, Person, Product, ProductOrder @@ -72,46 +70,38 @@ cors(app, methods="*", headers="*") options(app) -def auth_required(view): - async def redirect(request, response, *a, **k): - # FIXME do not return a view when Roll allows it. - response.redirect = f"/sésame?next={request.path}" - - def wrapper(request, response, *args, **kwargs): +@app.listen("request") +async def auth_required(request, response): + if not request.route.payload.get("genuine"): token = request.cookies.get("token") email = None if token: - decoded = read_token(token) + decoded = utils.read_token(token) email = decoded.get("sub") if not email: - return redirect(request, response, *args, **kwargs) - user = Person(email=email) - request["user"] = user - session.user.set(user) - return view(request, response, *args, **kwargs) - - return wrapper - - -def create_token(email): - return jwt.encode( - {"sub": str(email), "exp": utils.utcnow() + timedelta(days=7)}, - config.SECRET, - config.JWT_ALGORITHM, - ) - - -def read_token(token): - try: - return jwt.decode(token, config.SECRET, algorithms=[config.JWT_ALGORITHM]) - except (jwt.DecodeError, jwt.ExpiredSignatureError): - return {} + response.redirect = f"/sésame?next={request.path}" + return response + user = Person(email=email) + request["user"] = user + session.user.set(user) @app.listen("request") async def attach_request(request, response): response.request = request +@app.listen("request") +async def log_request(request, response): + if request.method == "POST": + message = { + "date": utils.utcnow().isoformat(), + "data": request.form, + "user": request.get("user"), + } + loggers.request_logger.info( + json.dumps(message, sort_keys=True, ensure_ascii=False) + ) + @app.listen("startup") async def on_startup(): @@ -119,15 +109,15 @@ async def on_startup(): Delivery.init_fs() -@app.route("/sésame", methods=["GET"]) +@app.route("/sésame", methods=["GET"], genuine=True) async def sesame(request, response): response.html("sesame.html") @app.route("/sésame", methods=["POST"]) -async def send_sesame(request, response): +async def send_sesame(request, response, genuine=True): email = request.form.get("email") - token = create_token(email) + token = utils.create_token(email) emails.send( email, "Sésame Copanier", @@ -137,9 +127,9 @@ async def send_sesame(request, response): response.redirect = "/" -@app.route("/sésame/{token}", methods=["GET"]) +@app.route("/sésame/{token}", methods=["GET"], genuine=True) async def set_sesame(request, response, token): - decoded = read_token(token) + decoded = utils.read_token(token) if not decoded: response.message("Sésame invalide :(", status="error") else: @@ -151,19 +141,16 @@ async def set_sesame(request, response, token): @app.route("/", methods=["GET"]) -@auth_required async def home(request, response): response.html("home.html", incoming=Delivery.incoming(), former=Delivery.former()) @app.route("/livraison", methods=["GET"]) -@auth_required async def new_delivery(request, response): response.html("edit_delivery.html", delivery={}) @app.route("/livraison", methods=["POST"]) -@auth_required async def create_delivery(request, response): form = request.form data = {} @@ -179,7 +166,6 @@ async def create_delivery(request, response): @app.route("/livraison/{id}/importer/produits", methods=["POST"]) -@auth_required async def import_products(request, response, id): delivery = Delivery.load(id) delivery.products = [] @@ -194,14 +180,12 @@ async def import_products(request, response, id): @app.route("/livraison/{id}/edit", methods=["GET"]) -@auth_required async def edit_delivery(request, response, id): delivery = Delivery.load(id) response.html("edit_delivery.html", {"delivery": delivery}) @app.route("/livraison/{id}/edit", methods=["POST"]) -@auth_required async def post_delivery(request, response, id): delivery = Delivery.load(id) form = request.form @@ -216,14 +200,12 @@ async def post_delivery(request, response, id): @app.route("/livraison/{id}", methods=["GET"]) -@auth_required async def view_delivery(request, response, id): delivery = Delivery.load(id) response.html("delivery.html", {"delivery": delivery}) @app.route("/livraison/{id}/commander", methods=["POST", "GET"]) -@auth_required async def place_order(request, response, id): delivery = Delivery.load(id) email = request.query.get("email", None) @@ -269,7 +251,6 @@ async def place_order(request, response, id): @app.route("/livraison/{id}/courriel", methods=["GET"]) -@auth_required async def send_order(request, response, id): delivery = Delivery.load(id) email = request.query.get("email") @@ -285,14 +266,12 @@ async def send_order(request, response, id): @app.route("/livraison/{id}/émargement", methods=["GET"]) -@auth_required async def signing_sheet(request, response, id): delivery = Delivery.load(id) response.html("signing_sheet.html", {"delivery": delivery}) @app.route("/livraison/{id}/importer/commande", methods=["POST"]) -@auth_required async def import_commande(request, response, id): email = request.form.get("email") order = Order() @@ -311,7 +290,6 @@ async def import_commande(request, response, id): @app.route("/livraison/{id}/rapport.xlsx", methods=["GET"]) -@auth_required async def xls_report(request, response, id): delivery = Delivery.load(id) response.body = reports.summary(delivery) @@ -321,7 +299,6 @@ async def xls_report(request, response, id): @app.route("/livraison/{id}/rapport-complet.xlsx", methods=["GET"]) -@auth_required async def xls_full_report(request, response, id): delivery = Delivery.load(id) response.body = reports.full(delivery) diff --git a/copanier/config.py b/copanier/config.py index 11c6dd8..b60c7ab 100644 --- a/copanier/config.py +++ b/copanier/config.py @@ -2,6 +2,7 @@ import os from pathlib import Path DATA_ROOT = Path(__file__).parent.parent / "db" +LOG_ROOT = Path("/tmp") SECRET = "sikretfordevonly" JWT_ALGORITHM = "HS256" SEND_EMAILS = False diff --git a/copanier/emails.py b/copanier/emails.py index 402983c..45b01d9 100644 --- a/copanier/emails.py +++ b/copanier/emails.py @@ -43,7 +43,7 @@ def send_order(env, person, delivery, order): ) send( person.email, - f"Copanier: résumé de la commande {delivery.producer}", + f"Copanier: résumé de votre commande {delivery.producer}", body=txt, html=html, ) diff --git a/copanier/utils.py b/copanier/utils.py index bb88ffb..8c8b5d3 100644 --- a/copanier/utils.py +++ b/copanier/utils.py @@ -1,5 +1,24 @@ -from datetime import datetime, timezone +from datetime import datetime, timezone, timedelta + +import jwt + +from . import config def utcnow(): return datetime.now(timezone.utc) + + +def create_token(email): + return jwt.encode( + {"sub": str(email), "exp": utcnow() + timedelta(days=7)}, + config.SECRET, + config.JWT_ALGORITHM, + ) + + +def read_token(token): + try: + return jwt.decode(token, config.SECRET, algorithms=[config.JWT_ALGORITHM]) + except (jwt.DecodeError, jwt.ExpiredSignatureError): + return {} diff --git a/remote/__main__.py b/remote/__main__.py index a065920..f9e2001 100644 --- a/remote/__main__.py +++ b/remote/__main__.py @@ -173,6 +173,7 @@ def upload_env(): """ vars_ = { "COPANIER_DATA_ROOT": "/srv/copanier/data", + "COPANIER_LOG_ROOT": "/srv/copanier/log", "COPANIER_SEND_EMAILS": "1", "COPANIER_SMTP_PASSWORD": None, "COPANIER_SMTP_LOGIN": None, diff --git a/tests/conftest.py b/tests/conftest.py index 8ce4e56..8df7edd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,7 +7,7 @@ from roll.testing import Client as BaseClient from copanier import app as copanier_app from copanier import config as kconfig -from copanier import create_token +from copanier.utils import create_token from copanier.models import Delivery, Person, Product