Basic JWT implementation (#1524)

* Basic JWT implementation

* Move JWT to UI_LOGIN mode and bring back SIMPLE_LOGIN as before

* Update server/src/main/kotlin/suwayomi/tachidesk/global/impl/util/Jwt.kt

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Refresh: Update only access token

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Implement JWT Audience

* Store JWT key

Generates the key on startup if not set

* Handle invalid Base64

* Make JWT expiry configurable

* Missing value parse

* Update server/src/main/kotlin/suwayomi/tachidesk/global/impl/util/Jwt.kt

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Simplify Duration parsing

* JWT Protect Mutations

* JWT Protect Queries and Subscriptions

* JWT Protect v1 WebSockets

* WebSockets allow sending token via protocol header

* Also respect the `suwayomi-server-token` cookie

* JWT reduce default token expiry

* JWT Support cookie on WebSocket as well

* Lint

* Authenticate graphql subscription via connection_init payload

* WebView: Prefer explicit token over cookie

This hack was implemented because WebView sent `"null"` if no token was
supplied, just don't send a bad token, then we can do this properly

* WebView: Implement basic login dialog if no token supplied

---------

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
Co-authored-by: schroda <50052685+schroda@users.noreply.github.com>
This commit is contained in:
Constantin Piber
2025-08-21 00:04:48 +02:00
committed by GitHub
parent d90bfb6e3e
commit 8547159eec
60 changed files with 1567 additions and 410 deletions

View File

@@ -10,7 +10,10 @@ import suwayomi.tachidesk.manga.impl.update.UpdateStatus
import suwayomi.tachidesk.manga.impl.update.UpdaterSocket
import suwayomi.tachidesk.manga.model.dataclass.MangaChapterDataClass
import suwayomi.tachidesk.manga.model.dataclass.PaginatedList
import suwayomi.tachidesk.server.JavalinSetup.Attribute
import suwayomi.tachidesk.server.JavalinSetup.future
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
import suwayomi.tachidesk.server.user.requireUser
import suwayomi.tachidesk.server.util.formParam
import suwayomi.tachidesk.server.util.handler
import suwayomi.tachidesk.server.util.pathParam
@@ -39,6 +42,7 @@ object UpdateController {
}
},
behaviorOf = { ctx, pageNum ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.future {
future {
Chapter.getRecentChapters(pageNum)
@@ -66,6 +70,7 @@ object UpdateController {
}
},
behaviorOf = { ctx, categoryId ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
val updater = Injekt.get<IUpdater>()
if (categoryId == null) {
logger.info { "Adding Library to Update Queue" }
@@ -96,6 +101,7 @@ object UpdateController {
fun categoryUpdateWS(ws: WsConfig) {
ws.onConnect { ctx ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
UpdaterSocket.addClient(ctx)
}
ws.onMessage { ctx ->
@@ -115,6 +121,7 @@ object UpdateController {
}
},
behaviorOf = { ctx ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
val updater = Injekt.get<IUpdater>()
ctx.json(updater.statusDeprecated.value)
},
@@ -132,6 +139,7 @@ object UpdateController {
}
},
behaviorOf = { ctx ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
val updater = Injekt.get<IUpdater>()
logger.info { "Resetting Updater" }
ctx.future {