From c7aefe142d6034d98d4c2b555c3b7d9d28036573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannik=20R=C3=B6del?= Date: Thu, 17 Mar 2022 13:45:08 +0100 Subject: [PATCH] Add attachment support for forms --- .gitignore | 1 + cgi-bin/form.py | 35 +++++++++++++------- flake.nix | 4 +-- httpd.conf | 2 +- src/content/computer-beantragen/privat.md | 2 +- src/content/hardware-spenden/organisation.md | 4 ++- 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 69d0f2d..eaefc8c 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ _site/ # Private environments in the HTTP playground folder /playground/*.private.env.json +/httpd.dev.conf diff --git a/cgi-bin/form.py b/cgi-bin/form.py index 0569a69..293e3d5 100755 --- a/cgi-bin/form.py +++ b/cgi-bin/form.py @@ -1,12 +1,14 @@ #!/usr/bin/env python +import base64 import io import cgi import collections import hmac +import mimetypes import os import secrets -from typing import Any, Optional, overload +from typing import Any, Optional, overload, IO import itsdangerous import requests @@ -90,7 +92,7 @@ def get_form_value(name: str, default: Optional[str], cast: type[str] = str) -> @overload def get_form_value(name: str, default: Optional[int], cast: type[int]) -> int:... @overload -def get_form_value(name: str, default: None = ..., cast: type[io.BytesIO] = ...) -> io.BytesIO:... +def get_form_value(name: str, default: None = ..., cast: type[bytes] = ...) -> tuple[str, bytes]:... def get_form_value( name: str, default: Any = None, @@ -102,11 +104,14 @@ def get_form_value( else: return default - if cast is io.BytesIO: + if cast is bytes: value_object = form[name] - if isinstance(value_object, list) or not value_object.file: + if ( + isinstance(value_object, list) + or not value_object.file + ): fail("400 Bad Request", f"Invalid value for field: {name}") - return io.BytesIO(value_object.file) + return (value_object.filename or "upload"), value_object.file.read() else: try: return cast(form.getfirst(name)) @@ -126,6 +131,7 @@ if not hmac.compare_digest(csrf_token, given_csrf_token): contact_name = get_form_value("contactname") contact_email = get_form_value("contactemail") message = get_form_value("message") +attachment: Optional[tuple[str, bytes]] = None ticket_details = collections.OrderedDict() ticket_details["Kontaktperson"] = contact_name @@ -159,7 +165,7 @@ match request_uri: ticket_details["Adresse"] = get_form_value("addressline") ticket_details["PLZ"] = get_form_value("postalcode") ticket_details["Stadt"] = get_form_value("city") - #document = get_form_value("document") + attachment = get_form_value("document") # Note: the actual form contains a checkbox for whether the user has # read the guidelines, but we don't actually bother checking that here. @@ -167,7 +173,7 @@ match request_uri: case "/hardware-spenden/organisation": form_name = "Hardwarespende (Organisation)" ticket_details["Organisation"] = get_form_value("organization") - #inventory = get_form_value("inventory") + attachment = get_form_value("inventory", cast=bytes) case "/hardware-spenden/privat/laptop": form_name = "Laptopspende (privat)" @@ -199,9 +205,14 @@ try: type="web", content_type="text/plain", subject=f"Kontaktformular-Anfrage {contact_name}", - body=message - ) - ) + body=message, + attachments=[] if attachment is None else [{ + "filename": attachment[0], + "data": base64.b64encode(attachment[1]).decode(), + "mime-type": mimetypes.guess_type(attachment[0])[0] or "text/plain", + }], + ), + ), ) response.raise_for_status() ticket_id = response.json()["id"] @@ -238,6 +249,6 @@ try: print("Content-Type: text/html") print("Location: /kontakt/fertig") print("") -except: - fail("500 Internal Server Error", "Backend error") +except Exception as e: + fail("500 Internal Server Error", str(e)) diff --git a/flake.nix b/flake.nix index 0dd2603..2b03389 100644 --- a/flake.nix +++ b/flake.nix @@ -53,7 +53,6 @@ config = { Env = [ - "SITE_DIRECTORY=${packages.site}" # We need to provide these default variables because otherwise # lighttpd doesn't even parse its configuration file: "ZAMMAD_URL=https://ticket.z31.it" @@ -78,6 +77,7 @@ buildInputs = [ pkgs.makeWrapper ]; paths = [ + pkgs.lighttpd nodejs nodeDependencies python @@ -91,7 +91,7 @@ shellHook = '' export NODE_PATH=${nodeDependencies}/lib/node_modules - export PATH="${nodeDependencies}/bin:${nodejs}/bin:${pkgs.nodePackages.npm-check-updates}/bin:${python}/bin:$PATH" + export PATH="${pkgs.lighttpd}/bin:${nodeDependencies}/bin:${nodejs}/bin:${pkgs.nodePackages.npm-check-updates}/bin:${python}/bin:$PATH" echo "" echo " To start editing content, run:" diff --git a/httpd.conf b/httpd.conf index 4ac6bd4..3a6c058 100644 --- a/httpd.conf +++ b/httpd.conf @@ -32,7 +32,7 @@ $HTTP["url"] =~ "^/cgi-bin/" { cgi.x-sendfile-docroot = ( "@site@" ) setenv.set-environment = ( - "SITE_DIRECTORY" => env.SITE_DIRECTORY, + "SITE_DIRECTORY" => "@site@", "ZAMMAD_URL" => env.ZAMMAD_URL, "ZAMMAD_TOKEN" => env.ZAMMAD_TOKEN, "ZAMMAD_GROUP" => env.ZAMMAD_GROUP diff --git a/src/content/computer-beantragen/privat.md b/src/content/computer-beantragen/privat.md index 560ba5b..72c6c0a 100644 --- a/src/content/computer-beantragen/privat.md +++ b/src/content/computer-beantragen/privat.md @@ -5,7 +5,7 @@ useForms: true # Privat einen Computer beantragen -
+ Auf dieser Seite kannst du einen Antrag einreichen, um einen Computer von uns zu erhalten. Bitte teile uns zunächst deine Kontaktdaten mit. diff --git a/src/content/hardware-spenden/organisation.md b/src/content/hardware-spenden/organisation.md index 0a18351..2b2fb6b 100644 --- a/src/content/hardware-spenden/organisation.md +++ b/src/content/hardware-spenden/organisation.md @@ -5,7 +5,7 @@ useForms: true # Hardware als Organisation spenden - + Vielen Dank, dass du uns deine gebrauchte Hardware überlassen möchtest! Um die Übergabe möglichst reibungslos zu gestalten, benötigen wir zunächst ein paar @@ -59,11 +59,13 @@ _SSD_-Festplatten werden in einem standardisierten Vorgehen über den Terminal g Das Bundesamt für Sicherheit in der Informationstechnik (BSI) empfiehlt für die Datenlöschung ebenfalls **DBAN** oder vergleichbare Software. Weitere Informationen zum Thema findest du auf der Website des [BSI](https://www.bsi-fuer-buerger.de/BSIFB/DE/Empfehlungen/RichtigLoeschen/richtigloeschen_node.html). Es gibt vier gängige Lösungen, die Datenschutzanforderungen deines Unternehmens mit einer Spende an Angestöpselt in Einklang zu bringen: + - Löschung im Unternehmen (gut für uns): Ihr übernehmt die Löschung bzw. das Überschreiben der Daten. Das installieren von Windows ist nicht notwendig. Im Verein installieren wir dann Ubuntu. - Löschung im Verein (gängigste Variante): Ihr überlasst uns Computer + Festplatten auf Vertrauensbasis. Wir überschreiben alle Inhalte nach obiger Methode und installieren Ubuntu. Defekte HDD/SSDs vernichten wir mechanisch vor dem Recycling. - Zertifizierte Löschung bei unserem [Kooperationspartner](https://bb-net.de/) (ab ca. 100 Geräten möglich): Die gespendeten Geräte liefert ihr an bb-net media GmbH in Schweinfurt. Dort werden die Festplatten zertifiziert gelöscht. Unser Kooperationspartner behält entweder einen Teil der Geräte zur Kostendeckung oder stellt euch klassisch eine Rechnung für die Löschung aus. ## Weitere Informationen +
Spendenquittungen