mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-08 05:14:37 -05:00
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:
@@ -9,7 +9,10 @@ import suwayomi.tachidesk.opds.dto.OpdsMangaFilter
|
||||
import suwayomi.tachidesk.opds.dto.OpdsSearchCriteria
|
||||
import suwayomi.tachidesk.opds.dto.PrimaryFilterType
|
||||
import suwayomi.tachidesk.opds.impl.OpdsFeedBuilder
|
||||
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.handler
|
||||
import suwayomi.tachidesk.server.util.pathParam
|
||||
import suwayomi.tachidesk.server.util.queryParam
|
||||
@@ -62,6 +65,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.contentType(OPDS_MIME).result(OpdsFeedBuilder.getRootFeed(BASE_URL, locale))
|
||||
},
|
||||
@@ -84,6 +88,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, pageNumber, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -109,6 +114,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.contentType("application/opensearchdescription+xml").result(
|
||||
"""
|
||||
@@ -136,6 +142,7 @@ object OpdsV1Controller {
|
||||
handler(
|
||||
documentWith = { withOperation { summary("OPDS Series in Library Feed") } },
|
||||
behaviorOf = { ctx ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val pageNumber = ctx.queryParam("pageNumber")?.toIntOrNull()
|
||||
val query = ctx.queryParam("query")
|
||||
val author = ctx.queryParam("author")
|
||||
@@ -188,6 +195,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, pageNumber, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -214,6 +222,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, pageNumber, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -240,6 +249,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, pageNumber, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -266,6 +276,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, pageNumber, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -291,6 +302,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -316,6 +328,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -342,6 +355,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, pageNumber, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -370,6 +384,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, sourceId, pageNumber, sort, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -405,6 +420,7 @@ object OpdsV1Controller {
|
||||
pathParam<Long>("sourceId"),
|
||||
documentWith = { withOperation { summary("OPDS Library Source Specific Series Feed") } },
|
||||
behaviorOf = { ctx, sourceId ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val criteria = buildCriteriaFromContext(ctx, OpdsMangaFilter(sourceId = sourceId, primaryFilter = PrimaryFilterType.SOURCE))
|
||||
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria)
|
||||
},
|
||||
@@ -422,6 +438,7 @@ object OpdsV1Controller {
|
||||
pathParam<Int>("categoryId"),
|
||||
documentWith = { withOperation { summary("OPDS Category Specific Series Feed") } },
|
||||
behaviorOf = { ctx, categoryId ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val criteria =
|
||||
buildCriteriaFromContext(ctx, OpdsMangaFilter(categoryId = categoryId, primaryFilter = PrimaryFilterType.CATEGORY))
|
||||
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria)
|
||||
@@ -440,6 +457,7 @@ object OpdsV1Controller {
|
||||
pathParam<String>("genre"),
|
||||
documentWith = { withOperation { summary("OPDS Genre Specific Series Feed") } },
|
||||
behaviorOf = { ctx, genre ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val criteria = buildCriteriaFromContext(ctx, OpdsMangaFilter(genre = genre, primaryFilter = PrimaryFilterType.GENRE))
|
||||
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria)
|
||||
},
|
||||
@@ -457,6 +475,7 @@ object OpdsV1Controller {
|
||||
pathParam<Int>("statusId"),
|
||||
documentWith = { withOperation { summary("OPDS Status Specific Series Feed") } },
|
||||
behaviorOf = { ctx, statusId ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val criteria = buildCriteriaFromContext(ctx, OpdsMangaFilter(statusId = statusId, primaryFilter = PrimaryFilterType.STATUS))
|
||||
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria)
|
||||
},
|
||||
@@ -479,6 +498,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, langCode ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val criteria =
|
||||
buildCriteriaFromContext(ctx, OpdsMangaFilter(langCode = langCode, primaryFilter = PrimaryFilterType.LANGUAGE))
|
||||
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria)
|
||||
@@ -506,6 +526,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, seriesId, pageNumber, sort, filter, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
@@ -536,6 +557,7 @@ object OpdsV1Controller {
|
||||
}
|
||||
},
|
||||
behaviorOf = { ctx, seriesId, chapterIndex, lang ->
|
||||
ctx.getAttribute(Attribute.TachideskUser).requireUser()
|
||||
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
|
||||
ctx.future {
|
||||
future {
|
||||
|
||||
Reference in New Issue
Block a user