Transparenz

Diese Seite dient dazu, die grundlegenden Datenflüsse innerhalb der App zu erklären, um Transparenz und Vertrauen zu schaffen.

Der gesamte Source Code ist öffentlich im HTWK GitLab einsehbar.

Das Hosting erfolgt über den Server des FSR IM im Zuse-Bau der HTWK.

Datenbank Struktur

voteData

Metadaten der Abstimmungen

NameDatentypBeschreibung
idZahl Eindeutige Identifikation der Zeile in der Tabelle. Wird in der App als "Abstimmungs-ID" angezeigt.
titleWort Titel der Abstimmung
descriptionWort Beschreibung der Abstimmung
boardWort Name der Gremiums (was bei der Erstellung in das "Gremium" Feld eingegeben wurde)
isPersonVoteWahr/Falsch Ob die Abstimmung eine Personenwahl ist
isSecretWahr/Falsch Ob die Abstimmung geheim ist
isJoinEnabledWahr/Falsch Ob man der Abstimmung noch beitreten kann. Wenn falsch, werden alle neuen Personen automatisch blockiert.
hasStartedWahr/Falsch Ob die Abstimmung gestartet wurde
isClosedWahr/Falsch Ob die Abstimmung geschlossen wurde
isDeletedWahr/Falsch Ob die Abstimmung als gelöscht markiert wurde
createdByWort Name der Person, die die Abstimmung erstellt hat
createdAtDatum Zeitstempel der Erstellung der Abstimmung (Unix Timestamp)

userVotes

Metadaten zu den Teilnehmenden der Abstimmung

NameDatentypBeschreibung
idZahl Eindeutige Identifikation der Zeile in der Tabelle
userIdWort userId der Person. Kommt in Kombination mit `voteId` nur 1x vor.
voteIdZahl ID der Abstimmung. Kommt in Kombination mit `userId` nur 1x vor.
isConnectedWahr/Falsch Ob die Person online mit der Abstimmung verbunden ist
isEntitledWahr/Falsch Ob die Person berechtigt ist, an der Abstimmung teilzunehmen. Wird erst bei Abstimmungsbeginn gesetzt.
hasVotedWahr/Falsch Ob die Person abgestimmt hat
isBlockedWahr/Falsch Ob die Person blockiert wurde

normalVotes

Stimmen zu normalen Abstimmungen

NameDatentypBeschreibung
idZahl Eindeutige Identifikation der Zeile in der Tabelle
userIdWort / LeeruserId der Person, die die Stimme abgegeben hat. Wird bei geheimen Abstimmungen leer gelassen.
voteIdZahl ID der Abstimmung, zu der die Stimme gehört
agreeWahr/Falsch Wahr, wenn die Stimme "Ja" ist
disagreeWahr/Falsch Wahr, wenn die Stimme "Nein" ist
abstainWahr/Falsch Wahr, wenn die Stimme "Enthaltung" ist oder die Abstimmung vorzeitig beendet und nicht abgestimmt wurde

personVotes

Stimmen zu Personenwahlen

NameDatentypBeschreibung
idZahl Eindeutige Identifikation der Zeile in der Tabelle
userIdWort / LeeruserId der Person, die die Stimme abgegeben hat. Wird bei geheimen Abstimmungen leer gelassen.
voteIdZahl ID der Abstimmung, zu der die Stimme gehört
vote0Wort / LeerName der Person, für die die erste Stimme abgegeben wurde
vote1Wort / LeerName der Person, für die die zweite Stimme abgegeben wurde
vote2Wort / LeerName der Person, für die die dritte Stimme abgegeben wurde

voteCandidates

Namen der kandidierenden Personen für jede Personenwahl

NameDatentypBeschreibung
idZahl Eindeutige Identifikation der Zeile in der Tabelle
voteIdZahl ID der Abstimmung, zu der die Kandidatur gehört
candidateWort Name der kandidierenden Person

users

Alle angemeldeten Personen

NameDatentypBeschreibung
idWort Eindeutige Identifikation der Zeile in der Tabelle. Nutzt eine zufällige UUIDv7 (z. B. "0192ce11-26d5-7dc3-9305-1426de888c5a"). Wenn Informationen mit anderen Personen geteilt werden, wird dieses Feld genutzt.
userNameWort Name der Person
userIdWort Einzigartige Zeichenkombination für diese Person, basierend auf der E-Mail Adresse. Wird zur Identifizierung der Person innerhalb der Datenbank genutzt.
customNameWort Name, den sich die Person selbst gegeben hat.
changedAtDatum Zeitstempel, an dem der Name geändert wurde.

ignoredVotes

Abstimmungen, über die auf dem Hauptbildschirm nicht mehr informiert werden soll

NameDatentypBeschreibung
idZahl Eindeutige Identifikation der Zeile in der Tabelle
userIdWort userId der Person, für die die Abstimmung nicht mehr angezeigt werden soll
voteIdZahl ID der Abstimmung, die nicht mehr angezeigt werden soll

Begriffe und Konzepte

Begriffe

  • Client: Webbrowser einer Person, die die App benutzt
  • Server: Zentraler Computer um die Daten der App zu verwalten
  • Datenbank: Dauerhafter Speicher für alle Daten der App
  • Erstellende Person: Die Person, die die Abstimmung erstellt hat
  • Teilnehmende / Stimmberechtigte Person: Personen, die abstimmen können. Muss nicht mit den stimmberechtigten Personen des Gremiums übereinstimmen.
  • Zuschauende Person: Nicht stimmberechtigte Personen, die nur zuschauen können

Konzepte

Alle Daten werden dauerhaft in der Datenbank gespeichert und validiert, sodass durch einen Serverabsturz oder einen Verbindungsabbruch bei den Nutzenden keine Daten verloren gehen. Der Server hat immer die Autorität über die Daten.

Die App unterscheidet mehrere Gruppen:

  • Die Person, die die Abstimmung erstellt hat
  • Personen, die an der Abstimmung teilnehmen
  • Personen, die nur zuschauen

Je nach Gruppe gibt es unterschiedliche Rechte.

Als erstellende Person kann man alle administrativen Aktionen während der Abstimmung ausführen, solange sie vom Abstimmungsfluss vorgesehen sind (man kann z. B. keine Personen blockieren, nachdem die Abstimmung gestartet wurde). Man kann auch selber abstimmen.

Als teilnehmende Person kann man an der Abstimmung teilnehmen. Dafür muss man eingeloggt sein. Andere Aktionen geben einen Fehler zurück.

Wenn man nur zuschaut, gibt der Server bei den meisten irregulären Anfragen direkt einen Fehler zurück.

Datenfluss bei einer Abstimmung

Erstellen der Abstimmung

Die auf der Startseite eingegebenen Daten werden an den Server übermittelt. Dieser erstellt daraufhin einen neuen Eintrag in der Datenbank und schickt die neu generierte ID der Abstimmung zurück an die erstellende Person.

Sobald die Daten vom Client empfangen wurden, wird automatisch auf die "Lobby" Seite weitergeleitet.

Hier werden die Metadaten der Abstimmung vom Server abgefragt, um festzustellen, ob die Abstimmung evtl. schon gestartet wurde.

Wenn sich andere Personen mit der Seite verbinden, wird ein neuer Eintrag für Metadaten dieser Person in dieser Abstimmung in der Datenbank erstellt.

Der erstellende Client fragt automatisch den Block-Status der neuen Personen ab und zeigt diese entsprechend an. Nur der erstellende Client kann auf diese Daten zugreifen, für alle anderen verweigert der Server die Anfrage.

Abstimmung

Sobald die Abstimmung gestartet wird, bekommen alle aktuell verbundenen und nicht blockierten Personen ein Stimmrecht (isEntitled = true in der Datenbank). Wer kein Stimmrecht hat, kann auch nicht auf die Abstimmungsseite zugreifen.

Die Abstimmungsseite bekommt alle Abstimmungsrelevanten Daten vom Server, z. B. ob es eine Personenwahl ist und wer die kandidierenden Personen sind.

Wenn eine Stimme abgegeben wird, wird sie in der Datenbank mit dem Namen der Person vermerkt. Im Falle einer geheimen Wahl wird der Name nicht gespeichert. In jedem Fall wird aber vermerkt, dass die Person abgestimmt hat (hasVoted = true).

Die zuschauenden Clients fragen daraufhin die Abstimmungszahlen vom Server ab und zeigen diese an (wie viele haben abgestimmt, wie viele haben nicht abgestimmt). Hierbei werden nur diese beiden Zahlen gesendet, es werden keine Details zu individuellen Stimmen übertragen.

Beenden der Abstimmung

Sobald alle stimmberechtigten Personen abgestimmt haben, wird durch den erstellenden Client automatisch die Schließung der Abstimmung vom Server angefragt. Die Abstimmung kann auch während der Abstimmung durch die erstellende Person geschlossen werden.

Im Falle einer manuellen Schließung werden die Stimmen aller stimmberechtigten Personen, die nicht abgestimmt haben, auf Enthaltung gesetzt. Der "hasVoted" Wert bleibt false.

Sobald der Server die Schließung in die Datenbank eingetragen hat, werden alle Clients auf die Ergebnis Seite weitergeleitet.

Personen Blockieren

Blockierte Personen können nicht auf die Abstimmungsseite zugreifen und können nur zuschauen.

Personen werden automatisch durch den Server blockiert, wenn der Beitritt deaktiviert wurde oder sie nicht in der Liste der stimmberechtigten Personen stehen. Falls diese Liste leer ist, wird niemand blockiert.

Wenn eine Person durch die erstellende Person blockiert wird, ändert der Server den Eintrag dieser Person entsprechend in der Datenbank (isBlocked = true). Beim Entblocken wird der Eintrag entsprechend wieder zurückgesetzt.

Ergebnisse

Anzeige der Ergebnisse

Die Ergebnisse werden aus der Datenbank abgefragt und in zwei Abfragen an die Clients geschickt:

  • Metadaten
  • Abstimmungsergebnisse

In den Abstimmungsergebnissen sind folgende Daten gelistet:

  • IDs der stimmberechtigten Personen
  • Anzahl der Stimmen für jede Option / jede kandidierende Person
  • Anzahl an Personen, die nicht abgestimmt haben, falls die Abstimmung vorzeitig beendet wurde
  • Wenn die Abstimmung nicht geheim war: Welche Person wie gestimmt hat

Die Ergebniszahlen werden sortiert. Bei Personenwahlen wird nach Anzahl der Stimmen sortiert, bei normalen Abstimmungen gilt die Reihenfolge "Ja-Nein-Enthaltung". Diese Sortierung wird auch für die Erstellung der Graphen genutzt.

Die Details-Liste wird alphabetisch nach Personenname sortiert. Falls die Abstimmung geheim war, werden nur die Personen gelistet, da keine Ergebnisse zugeordnet werden können.

Wenn die Anzahl an Personen, die nicht abgestimmt haben, nicht 0 ist, wird die Abstimmung als vorzeitig beendet markiert.

Verifikation von Ergebnissen

Auf den Ergebnis Seiten und in der exportierten CSV ist ein Verifikationscode gelistet. Dieser kann genutzt werden, um die Gültigkeit der Ergebnisse zu überprüfen.

Die Metadaten und die Ergebnisse der Abstimmung werden kombiniert und durch einen SHA-256 Hash Algorithmus in eine 40-stellige Zeichenfolge konvertiert. Diese Konvertierung kann nicht rückgängig gemacht werden.

Die Konvertierung erfolgt vor der Sortierung und Verarbeitung der Daten durch die App, d. h. es werden die rohen Daten verwendet, die vom Server gesendet wurden.

Jede kleine Änderung der Quelldaten, wie z. B. eine Änderung der Reihenfolge der Ergebnisse, würde einen unterschiedlichen Wert produzieren. Dadurch kann zu einem späteren Zeitpunkt sichergestellt werden, dass die Abstimmungsergebnisse in der Datenbank unverändert sind.

Abstimmungen löschen

Die erstellende Person kann eine Abstimmung löschen, wenn diese noch nicht angefangen hat oder bereits beendet wurde.

Die Abstimmung kann nur durch die erstellende Person gelöscht werden. Für andere Personen wird der Knopf nicht angezeigt.

Gelöschte Abstimmungen werden nicht in der Abstimmungsübersicht gelistet und können auch nicht aufgerufen werden.

Es werden keine Daten aus der Datenbank gelöscht. Die Abstimmung wird in der Datenbank lediglich als gelöscht markiert (isDeleted = true).

Die Abstimmung kann wiederhergestellt werden, indem diese Markierung in der Datenbank durch die Serveradmins des FSR IM entfernt wird.

Absicherung gegen bösartige Anfragen

Die App ist durch mehrere Sicherheitsmechanismen gegen Anfragen mit inkorrekten Daten geschützt.

  • Datenvalidierung durch den Server
  • Überprüfung auf Rechte und korrekten Abstimmungs-Ablauf
  • Daten in Datenbankoperationen werden automatisch unschädlich gemacht
  • Vorgaben und Einschränkungen in der Datenbank zu Datentypen und Werten

Der Server validiert jede eingehende Anfrage auf korrekte Form. Wenn die Form nicht eingehalten wird, wird ein Fehler zurückgegeben.

Wenn dem anfragenden Client die nötigen Rechte fehlen oder die Anfrage nicht in den Ablauf der aktuellen Abstimmung passt (z. B. Personen blockieren nachdem die Abstimmung gestartet hat), wird ein Fehler zurückgegeben.

Das verwendete Datenbanksystem "Drizzle" maskiert automatisch alle Parameter, sodass keine SQL Injection möglich ist.

Die Datenbank selbst hat strikte Vorgaben zu Datentypen, die in bestimmte Felder eingetragen werden können. Außerdem können manche Werte oder Kombination von Werten nur 1x in der gesamten Datenbank auftreten.

Benachrichtigung zu offenen Abstimmungen

Wenn es Abstimmungen gibt, in denen man noch nicht abgestimmt hat oder die man noch nicht gestartet oder beendet hat, bekommt man auf der Startseite der App eine Popup-Benachrichtigung.

Dafür werden beim Laden der Seite alle noch ausstehenden Abstimmungen nach folgenden Kriterien geladen. Wenn eines der Kriterien wahr ist, wird die Benachrichtigung angezeigt.

  • Von der Person erstellt UND noch nicht gestartet
  • Von der Person erstellt UND noch nicht beendet
  • Person ist stimmberechtigt UND hat nicht abgestimmt UND die Abstimmung ist noch nicht beendet

Basierend darauf, welcher Wert wahr ist, zeigt der angezeigte Link auf die entsprechende Seite.

Login

Der Login erfolgt über die HTWK Server. Das Passwort wird dabei direkt an den HTWK Server übergeben, nicht an die Abstimmungs-App. (OAuth)

Der Server bekommt nach erfolgreicher Anmeldung einen Schlüssel mit bestimmten Daten der Person, wie Name, Nutzername und E-Mail.

Der Schlüssel ist durch den HTWK Server signiert. Diese Signatur kann zwar von jeder anderen Person verifiziert, allerdings nicht nachgemacht werden. Dadurch ist die Sicherheit des Schlüssels gewährleistet.

Der Server speichert nur Name und E-Mail. Mit diesen Daten wird eine neue Session auf dem Server erstellt, die innerhalb der App zur Authentifizierung verwendet wird. Auf diese Session können sowohl Client als auch Server zugreifen.

Um Personen innerhalb der App eindeutig zu identifizieren, wird die E-Mail Adresse mit dem SHA-256 Algorithmus gehasht und als base64 Zeichenkette (z. B. "mmhc1cXL1Bbxv1aCCSnvX/ex2TmtutXcWT94TFNTYgg=") in der Datenbank neben dem Namen der Person gespeichert. Dadurch werden keine unnötigen privaten Daten direkt gespeichert, allerdings kann die Person trotzdem noch mit relativ wenig Aufwand identifiziert werden.

Namensänderungen

Du kannst deinen angezeigten Namen ändern, indem du oben rechts auf Profil -> Namen ändern drückst (nur nach Login sichtbar).

Geänderte Namen werden mit einem * markiert. Dadurch soll verhindert werden, dass sich eine Person als eine andere reale Person ausgibt.

Auf Anfrage an die im Impressum gelistete verantwortliche Person kann diese Markierung entfernt werden.

Der Server verschickt bei Anfragen immer nur User IDs in Form einer zufälligen UUID (z. B. "019599c4-f06c-7000-a439-96e82600f38b"). Die Clients fragen dann in einer separaten Anfrage die zugehörigen Namen an. Dadurch wird sichergestellt, dass nur die relevanten personenbezogenen Daten übertragen werden und die Privatsphäre geschützt wird.

Statische Personenlisten

Die App beinhaltet zwei Listen von Personen:

  • Namensüberschreibungen
  • Stimmberechtigte Personen pro Gremium

Die Liste mit Namensüberschreibungen erlaubt es, die Markierung von geänderten Namen bei bestimmte Personen auszublenden. Hierbei wird ein bestimmter Zeitstempel gespeichert, an dem die Markierung entfernt wurde. Wenn der Name danach nochmal geändert wird, wird die Markierung wieder angezeigt.

Die Liste mit Stimmberechtigten erlaubt eine automatische Zulassung/Blockierung von Personen bei Abstimmungen.

Diese Listen sind statisch und müssen direkt im Quellcode geändert werden. Um in eine dieser Listen aufgenommen zu werden, bitte die eigene HTWK E-Mail Adresse an die im Impressum gelistete verantwortliche Person schicken.

Die Listen beinhalten die E-Mail Hashes der Personen, wie sie auch in der Datenbank vorhanden sind. Zum Schutz vor Web-Scrapern und -Crawlern sind die Werte auch zusätzlich noch Base64 kodiert, sodass ein zusätzlicher Schritt nötig ist, um die Daten zu lesen.