diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c048a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/readme.md b/readme.md index b8d61fe..4285156 100644 --- a/readme.md +++ b/readme.md @@ -1,14 +1,6 @@ -# Espe +# Espe | Documentation -Espe ist eine schlichte Nutzerverwaltung, welche als Daten-Quelle für Identitätsanbieter-Dienste verwendet werden kann. +## Beschreibung -Es können damit als Personen begreifbare Entitäten erfasst werden, die folgende Eigenschaft umfassen: -- Identifikations-Name -- Anzeige-Name -- E-Mail-Adresse -- ob aktiv -- Passwort-Daten -- Gruppen-Zugehörigkeiten - -Bei Änderungen am Datenbestand können Ausgabe-Operationen ausgelöst werden, welche dazu dienen sollen evtl. angeschlossene Identitätanbieter-Dienste zu aktualisieren. +- enthält Konzept und Dokumentation für "Espe" (Erweiterte Sächsische Partei-Eingliederung) diff --git a/source/logo.svg b/source/logo.svg new file mode 100644 index 0000000..9161a26 --- /dev/null +++ b/source/logo.svg @@ -0,0 +1,153 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/notizen.md b/source/notizen.md new file mode 100644 index 0000000..2e0a972 --- /dev/null +++ b/source/notizen.md @@ -0,0 +1,90 @@ +## Beschreibung + +Espe soll dazu dienen die Mitglieder einer Partei-Orgranisations-Struktur (z.B. Landesverband) zu erfassen. +Damit ist es eine Zusatz bzw. eine Alternative zum MGL des Bundesverbandes. +Das Haupt-Ziel dabei ist den Mitgliedern die Nutzung verschiedener Dienste im Netz zu ermöglichen, vorrangig E-Mail abseits von privaten Adressen. +Darüber hinaus sollen mittels Espe relevante Mitglieder-Angaben erfasst und berechtigten Stellen zur Verfügung gestellt werden, welche nicht durch das MGL abgedeckt werden bzw. darüber schlecht oder gar nicht abrufbar sind. + +Der Name ist einerseits ein Bezug zum gleichnamigen Pionier-Baum, welcher auch als "Zitter-Pappel" bekannt ist, zum anderen kann man ihn lesen als Abkürzung für "Erweiterte Sächsische Partei-Eingliederung". + + +## Anwendungsfälle + +### Partei-Eintritt + +- Bundespartei erfasst und stellt bereit (z.B. mittels Meldung an Mitglieder-Beauftragen der Organisations-Struktur) + - Mitgliedsnummer (z.B. "123456") + - Klarname (z.B. "Karl Liebknecht") + - private E-Mail-Adresse (optional) +- der zuständige Betreuer des Espe-Instanz legt einen Datensatz für das Mitglied mit diesen Angaben an +- folgende Werte leiten sich aus dem Klarname des Mitglieds ab: + - Anzeigename für Netz-Dienste (im einfachsten Fall entspricht dieser Wert genau dem Klarname) + - Anmeldename für Netz-Dienste (z.B. `karl.liebknecht`) (muss eindeutig sein; bei Namens-Dopplung wird ein Index angehangen) +- dem Mitglied wird eine E-Mail an die private Adresse geschickt mit einem Willkommens-Gruß und einem Link zu einem Registrierungs-Formular in Espe, welches folgende Angaben erfasst: + - soll eine pseudonymisierte E-Mail-Adresse (z.B. "mitglied-1234567@dielinke-sachsen.de") bei der Organisations-Struktur angelegt werden? + - soll eine namentliche E-Mail-Adresse (z.B. "karl.liebknecht@dielinke-sachsen.de") bei der Organisations-Struktur angelegt werden? + - sollen eingehende E-Mails an die private Adresse geleitet werden? (empfohlen) + - welches Passwort soll für die Nutzung der Netz-Dienste verwendet werden? (optional; falls nicht ausgefüllt, kein Zugang zu Netz-Diensten) +- durch Absenden des Formulars werden die Daten zur Espe-Instanz übertragen und dort hinterlegt +- der zuständige Betreuer des Espe-Instanz erhält Benachrichtigung über erfolgte Registrierung des Mitglieds +- der zuständige Betreuer des Espe-Instanz veranlasst die Einrichtung der gewünschten E-Mail-Adresse(n) und schaltet das Mitglieder-Konto frei +- Benachrichtigung des Mitglieds + - ggf. über erfolgte Einrichtung der E-Mail-Adresse(n) + - ggf. Zugangsdaten für Dienste (ohne Passwort) +- fehlschlagenden Prüfungen werden nicht immer an das Frontend kommuniziert um potenziellen Angreifern keine Informationen zu liefern + + +### Änderung des Namens + +__\[TODO\]__ + + +### Änderung der privaten E-Mail-Adresse + +__\[TODO\]__ + + +### Änderung des Passwortes + +- Mitglied gibt Anmelde-Namen oder private E-Mail-Adresse an +- Espe ermittelt das dazu passenden Mitglied-Konten +- Espe prüft: + - ob der letzte Änderungs-Gesuch lang genug zurück liegt (Durchsatzratenbegrenzung) + - ob das Mitglied registriert ist + - ob das Mitglied aktiviert ist +- Espe erzeugt einen Schlüssel und hinterlegt ihn für das Mitglied +- Espe setzt den aktuellen Zeitpunkt als Zeitpunkt des letzten Änderungs-Gesuch des Mitglieds +- Espe sendet eine E-Mail an die private E-Mail-Adresse des Mitglieds mit einem Link zum nächsten Schritt, welcher die ID des Mitglieds sowie den erzeugten Schlüssel transportiert +- Mitglied erhält E-Mail +- Mitglied öffnet Link +- Mitglied gibt das neue Passwort ein und sendet das Formular ab, wobei der mit transportierte Schlüssel ebenfalls übermittelt wird +- Espe prüft ob der Schlüssel korrekt ist +- Espe prüft ob die Passwort-Kriterien erfüllt sind +- Espe speichert das neue Passwort und löscht den hinterlegten Schlüssel +- Espe sendet Benachrichtigung über Passwort-Änderung an private E-Mail-Adresse des Mitglieds + + +### Partei-Austritt + +- Mitglied meldet Austritt +- Meldung an zuständigen Betreuer des Espe-Instanz geht ein +- zuständiger Betreuer des Espe-Instanz löscht Datensatz des betreffenden Mitglieds zum Inkrafttreten des Austritts + + +## Technische Eckpunkte + +- Drei-Teilung in Datenbank, Backend und Frontend +- falls Datenbank und Backend auf verschiedenen Systemen laufen, soll die Übertragung auf einem verschlüsselten Kanal geschehen +- die Übertragung zwischen Clients und Backend- sowie Frontend-Server soll zwingend verschlüsselt sein (z.B. [HSTS](https://de.wikipedia.org/wiki/HTTP_Strict_Transport_Security)) +- Sicherheits-Anforderungen + - müssen hoch sein, da es sich um sensible Daten handelt und potentiell ein hohes Interesse am Abgreifen der Daten durch Dritte besteht + - vor Verwendung soll das ganze System ausgiebig durchleuchtet und auf Schwachstellen abgeklopft werden + - Passwörter werden nicht im Klartext gespeichert +- ["mobile first"](https://www.itportal24.de/ratgeber/mobile-first)-Ansatz für Frontend verfolgen + + +## Logik + +__\[TODO\]__ + + diff --git a/tools/build b/tools/build new file mode 100755 index 0000000..8726273 --- /dev/null +++ b/tools/build @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 + +import sys as _sys +import os as _os +import argparse as _argparse + + +def string_coin( + template, + arguments +): + result = template + for (key, value, ) in arguments.items(): + result = result.replace("{{%s}}" % key, value) + return result + + +def file_read(path): + handle = open(path, "r") + content = handle.read() + handle.close() + return content + + +def file_write(path, content): + handle = open(path, "w") + handle.write(content) + handle.close() + + +def main(): + ## consts + conf = { + "title": "Espe", + "source_directory": "source" + } + + ## args + argument_parser = _argparse.ArgumentParser() + argument_parser.add_argument( + "-t", + "--target-directory", + type = str, + default = "build", + ) + argument_parser.add_argument( + "-f", + "--format", + type = str, + action = "append", + choices = ["markdown", "html", "pdf"], + default = [], + ) + args = argument_parser.parse_args() + + ## vars + target_directory = _os.path.abspath(args.target_directory) + formats = (["html"] if (len(args.format) <= 0) else args.format) + + ## exec + _os.makedirs(args.target_directory, exist_ok = True) + for format_ in formats: + if (format_ == "markdown"): + target_path = string_coin( + "{{target_directory}}/espe.md", + { + "target_directory": target_directory, + } + ) + file_write( + target_path, + string_coin( + "# {{title}}\n\n{{content}}", + { + "title": conf["title"], + "content": file_read( + string_coin( + "{{source_directory}}/notizen.md", + { + "source_directory": conf["source_directory"], + } + ) + ), + } + ) + ) + _sys.stdout.write("%s\n" % target_path) + elif (format_ == "html"): + target_path = string_coin( + "{{target_directory}}/espe.html", + { + "target_directory": target_directory, + } + ) + _os.system( + string_coin( + "pandoc {{source_directory}}/notizen.md --to=html --title={{title}} --metadata='title:{{title}}' --output={{target_path}}", + { + "source_directory": conf["source_directory"], + "target_path": target_path, + "title": conf["title"], + } + ) + ) + _sys.stdout.write("%s\n" % target_path) + elif (format_ == "pdf"): + target_path = string_coin( + "{{target_directory}}/espe.pdf", + { + "target_directory": target_directory, + } + ) + _os.system( + string_coin( + "pandoc {{source_directory}}/notizen.md --to=pdf --title={{title}} --metadata='title:{{title}}' --output={{target_path}}", + { + "source_directory": conf["source_directory"], + "target_path": target_path, + "title": conf["title"], + } + ) + ) + _sys.stdout.write("%s\n" % target_path) + else: + raise ValueError("invalid format: %s" % format_) + + +main()