1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
\newenvironment{urlParameter}
{
\newcommand{\urlParamItem}[2]
{
\rowcolor{\methodLightColor} ##1 & ##2 \\
}
\newcommand{\noUrlParameter}[1]
{
\small{\textit{##1}}
}
%\vspace{-0.61em}
\arrayrulecolor{\methodColor}
\begin{tabularx}{\textwidth}{X}
\rowcolor{\methodLightColor!20}
\textbf{URL-Parameter} \\ \hline
\end{tabularx}
\tabularx{\textwidth}{l X}
}
\newenvironment{pathParameter}
{
\newcommand{\pathParamItem}[2]
{
\rowcolor{\methodLightColor} ##1 & ##2 \\
}
\newcommand{\noPathParameter}[1]
{
\small{\textit{##1}}
}
%\vspace{-0.61em}
\arrayrulecolor{\methodColor}
\begin{tabularx}{\textwidth}{X}
\rowcolor{\methodLightColor!20}
\textbf{Pfad-Parameter} \\ \hline
\end{tabularx}
\tabularx{\textwidth}{l X}
}
\newenvironment{jsonKeys}
{
\newcommand{\jsonKeyItem}[2]
{
\rowcolor{\methodLightColor} ##1 & ##2 \\
}
\newcommand{\nojsonKeys}[1]
{
\small{\textit{##1}}
}
%\vspace{-0.61em}
\arrayrulecolor{\methodColor}
\begin{tabularx}{\textwidth}{X}
\rowcolor{\methodLightColor!20}
\textbf{Json-Keys} \\ \hline
\end{tabularx}
\tabularx{\textwidth}{l X}
}
\section{Änderungen zum Entwurfsheft}
Im Folgenden werden die Änderungen zum Entwurfsheft aufgelistet und erläutert warum diese
Änderungen gemacht wurden.
\subsection{Kompatibilität mit \Glspl{podcatcher}}
Um die Kompatibilität mit \Glspl{podcatcher} - insbesondere AntennaPod und Kasts - sicherzustellen, mussten einige Änderungen vorgenommen werden.
\subsubsection*{Speicherung von Benutzernamen und E-Mail-Adressen}
AntennaPod erlaubt bei der Verknüpfung mit einem Synchronisations-Server nur die Anmeldung mit einem Benutzername, der keine E-Mail-Adresse ist.
Deshalb werden nun sowohl ein Benutzername als auch eine E-Mail-Adresse für jeden Nutzer gespeichert.
Der Benutzername wird dabei unverschlüsselt gespeichert.
Er wird zur Authentifizierung sowie für die Zuordnung der Anfragen verwendet.
Die E-Mail-Adresse hingegen, wird vor der Speicherung mit einem festen Geheimschlüssel gesalted und anschließend gehashed.
Sie existiert lediglich um bei einer Passwort-vergessen-Anfrage denjenigen Nutzer zu finden, zu dem die übergebene E-Mail-Adresse gehört, beziehungsweise dessen Existenz zu überprüfen.
Diese Änderung impliziert eine Anpassung des Formats, in dem Registrierungsanfragen als \GLS{json}-Payload übergeben werden.
Wie in der folgenden aktualisierten Spezifikation zu sehen existiert nun ein zusätzliches \GLS{json}-Attribut namens \enquote{username}.
\newline
\begin{apiRoute}{post}{/api/2/auth/register.json}
{Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort.
Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.}
\begin{routeRequest}{application/json}
\begin{routeRequestBody}
{
"username": "jeff",
"email": "jeff@example.com",
"password": "MyNameIsJeff"
}
\end{routeRequestBody}
\end{routeRequest}
\begin{routeResponse}{application/json}
\begin{routeResponseItem}{200}
{OK: Nutzer wurde erfolgreich angelegt und E-Mail versendet.}
\end{routeResponseItem}
\begin{routeResponseItem}{400}
{Bad Request: Fehler beim Parsen oder Eingabe nicht anforderungsgemäß.}
\end{routeResponseItem}
\end{routeResponse}
\end{apiRoute}
\subsubsection*{Device API}
Beim Einrichten eines Synchronisations-Servers rufen sowohl AntennaPod als auch Kasts statt einem anfänglichen Login sofort den List-Devices-Endpunkt der \gls{gpodder}.net API auf.
Dieser Endpunkt wurde entsprechend hinzugefügt.
Da jedoch explizit keine Unterscheidung von Geräten bei der Synchronisation unterstützt wird, wird dieser intern wie ein Login-Aufruf behandelt.
\newline
\begin{apiRoute}{get}{/api/2/devices/\{username\}.json}
{Gegebenen Nutzer des gegebenen Geräts mithilfe HTTP Basic Auth einloggen oder Gültigkeit des im \enquote{sessionid} \Gls{cookie} gespeicherten JWTs bestätigen.
Gibt außerdem eine Liste mit einem Dummy-Device zurück, damit die Einrichtung der Synchronisation mit AntennaPod und Kasts möglich ist.}
\begin{pathParameter}
\pathParamItem{username}{Nutzername des einzuloggenden Nutzers}
\end{pathParameter}
\begin{routeResponse}{application/json}
\begin{routeResponseItem}{200}
{OK: Der Benutzer wurde erfolgreich mittles HTTP Basic Auth oder JWT eingeloggt und das \enquote{sessionid} Cookie wurde auf ein gültiges JWT gesetzt.}
\newline
\begin{routeResponseItemBody}
[
{
"id": "dummy",
"caption": "device",
"type": "other",
"subscriptions": 0
}
]
\end{routeResponseItemBody}
\end{routeResponseItem}
\begin{routeResponseItem}{401}
{Unauthorized: Es liegen falsche Anmeldedaten oder ein ungültiges JWT vor.}
\end{routeResponseItem}
\end{routeResponse}
\begin{jsonKeys}
\jsonKeyItem{id}{Geräte-ID}
\jsonKeyItem{caption}{Ein für Menschen lesbarer Name für das Gerät}
\jsonKeyItem{type}{Typ des Geräts - mögliche Typen: desktop, laptop, mobile, server, other}
\jsonKeyItem{subscriptions}{Anzahl der Subscriptions auf dem Gerät}
\end{jsonKeys}
\end{apiRoute}
\newpage
\subsection{Verifizierung der E-Mail-Adresse}
Dieser Endpunkt wurde zur Verifizierung der bei der Registrierung angegebenen E-Mail-Adresse hinzugefügt.
Nach der Registrierung wird dem Benutzer eine E-Mail mit der URL dieses Endpunkts (inklusive Benutzernamen und JWT)
zugesendet. Klickt der Benutzer auf den Link wird die Anfrage im Backend verarbeitet und der Nutzer automatisch
zum Webfrontend weitergeleitet. Erst nach der Verifizierung der E-Mail-Adresse ist die Registrierung vollständig
abgeschlossen und der Account aktiviert - nun kann sich der Nutzer anmelden.
\newline
\begin{apiRoute}{get}{/api/2/auth/\{username\}/verify.json}
{Verifiziere die bei der Registrierung angegebene E-Mail-Adresse durch diese, per E-Mail versendete, URL.}
\begin{pathParameter}
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
\end{pathParameter}
\begin{urlParameter}
\urlParamItem{token}{JSON-Web-Token (24h gültig)}
\end{urlParameter}
\begin{routeResponse}{application/json}
\begin{routeResponseItem}{200}
{OK: Der Benutzer wurde erfolgreich aktiviert und kann sich nun anmelden.}
\end{routeResponseItem}
\begin{routeResponseItem}{400}
{Bad Request: Der Nutzer mit dem angegebenen Namen ist bereits verifiziert. }
\end{routeResponseItem}
\begin{routeResponseItem}{401}
{Unauthorized: Der JWT ist ungültig. }
\end{routeResponseItem}
\begin{routeResponseItem}{404}
{Not Found: Es exisitiert kein Nutzer mit dem angegebenen Benutzernamen. }
\end{routeResponseItem}
\end{routeResponse}
\end{apiRoute}
\newpage
\subsection{RSSParser}
Das primäre Ziel beim Entwurf des RSSParsers war es den Rest der Anwendung nicht
aufzuhalten, da das fetchen und parsen länger dauert. Daher soll der RSSParser asynchron
ausgeführt werden.
Damit das für die Implementierung verwendete Framework \Gls{spring} dies unterstützt müssen
mehr Bedingungen erfüllt sein als im Entwurf berücksichtigt wurden, weshalb dieser abgeändert werden musste.
Unter anderem können nur Komponenten die von \Gls{spring} verwaltet werden asynchron ausgeführt werden.
Weiter können nur öffentliche Methoden von \Gls{spring} als asynchron erkannt werden und bei
dem Aufruf einer asynchronen Methode muss die Klasse gewechselt werden damit diese asynchron
ausgeführt wird.
Um diese Bedingungen zu erfüllen ruft der SubscriptionService oder der EpisodeActionService
die Validate Methode des RSSParsers mit der Subscription die überprüft werden
soll auf. Dies geschieht asynchron nach dem \enquote{Fire and Forget} Prinzip. Daher können
die Services unmittelbar weiter arbeiten und dem Nutzer so möglichst schnell eine Antwort
liefern.
Die Validate Methode fragt den aktuellen \GLS{rss}-Feed der Subscription ab und parsed diesen.
Erfüllt der Feed die von Apple und Google für \Glspl{podcast} definierten Anforderungen
werden die Informationen aus dem Feed gespeichert. Dabei werden nur die \Glspl{episode} gespeichert,
die von mindestens einem Nutzer gehört wurden. Ist der Feed der Subscription nicht
valide wird die Subscription gelöscht. Um das Löschen und Speichern ausführen zu können
hält der Parser Referenzen auf das SubscriptionDao und EpisodeDao.
Die im Entwurfsheft definierten Getter werden nicht mehr oder nur
noch als private Hilfsmethoden benötigt.
\subsection{Reduzierte Datenzugriffsschicht}
Mithilfe von JPA Repositories können Datenbankzugriffe und Abfragen ohne weitere Logik in den DAO-Schnittstellen einfach implementiert werden.
Wird beispielsweise nach einem \Gls{abo} anhand einer URL gesucht, so wird eine Methode der Form \textit{Optional<Subscription> findByUrl(String url)} in der SubscriptionDao deklariert.
Um die Implementierung dieser Abfrage kümmert sich JPA.
Damit fallen alle ursprünglich geplanten DAO-Implementierungen weg, was für eine bessere Übersicht in der Datenzugriffsschicht sorgt.
\newpage
\begin{landscape}
\subsection{Überarbeitetes Klassendiagramm des Backends}
Das Klassendiagramm zeigt alle den überarbeiteten Entwurf des Backends.
Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver.
% \input{assets/diagrams/classdiagram.latex}
\includegraphics[width=\linewidth]{assets/diagrams/class_after}
\end{landscape}
|