OPDS: Allow fallback to Basic Auth (#1613)

* Move API authorization to UserType

We already verify the JWT there, so do the same with cookies. This makes
the next steps easier

* OPDS: Allow basic auth as fallback

* Send 404 for any unmatched API request

Redirecting to the UI is weird and can cause problems with the
SIMPLE_LOGIN check (which ignores API requests)

* Webview: Present Login page in SIMPLE_LOGIN mode

For BASIC_AUTH, the dialog is always presented. With UI_LOGIN, we have a
custom login dialog.
Before, SIMPLE_LOGIN would just say "Unauthorized", as with all API
endpoints. With the last commits, SIMPLE_LOGIN is checked by the
endpoints, which Webview did not, so the page would load, but then the
Websocket would error out, despite showing the login dialog.

* Lint
This commit is contained in:
Constantin Piber
2025-08-24 18:36:11 +02:00
committed by GitHub
parent 9a33e3808a
commit 46e2ef125a
4 changed files with 94 additions and 36 deletions

View File

@@ -12,7 +12,7 @@ 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.user.requireUserWithBasicFallback
import suwayomi.tachidesk.server.util.handler
import suwayomi.tachidesk.server.util.pathParam
import suwayomi.tachidesk.server.util.queryParam
@@ -67,7 +67,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.contentType(OPDS_MIME).result(OpdsFeedBuilder.getRootFeed(BASE_URL, locale))
},
@@ -90,7 +90,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, pageNumber, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -116,7 +116,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.contentType("application/opensearchdescription+xml").result(
"""
@@ -144,7 +144,7 @@ object OpdsV1Controller {
handler(
documentWith = { withOperation { summary("OPDS Series in Library Feed") } },
behaviorOf = { ctx ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val pageNumber = ctx.queryParam("pageNumber")?.toIntOrNull()
val query = ctx.queryParam("query")
val author = ctx.queryParam("author")
@@ -199,7 +199,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, pageNumber, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -226,7 +226,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, pageNumber, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -253,7 +253,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, pageNumber, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -280,7 +280,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, pageNumber, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -306,7 +306,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -332,7 +332,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -359,7 +359,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, pageNumber, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -388,7 +388,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, sourceId, pageNumber, sort, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -424,7 +424,7 @@ object OpdsV1Controller {
pathParam<Long>("sourceId"),
documentWith = { withOperation { summary("OPDS Library Source Specific Series Feed") } },
behaviorOf = { ctx, sourceId ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val criteria = buildCriteriaFromContext(ctx, OpdsMangaFilter(sourceId = sourceId, primaryFilter = PrimaryFilterType.SOURCE))
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria, isSearch = false)
},
@@ -442,7 +442,7 @@ object OpdsV1Controller {
pathParam<Int>("categoryId"),
documentWith = { withOperation { summary("OPDS Category Specific Series Feed") } },
behaviorOf = { ctx, categoryId ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val criteria =
buildCriteriaFromContext(ctx, OpdsMangaFilter(categoryId = categoryId, primaryFilter = PrimaryFilterType.CATEGORY))
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria, isSearch = false)
@@ -461,7 +461,7 @@ object OpdsV1Controller {
pathParam<String>("genre"),
documentWith = { withOperation { summary("OPDS Genre Specific Series Feed") } },
behaviorOf = { ctx, genre ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val criteria = buildCriteriaFromContext(ctx, OpdsMangaFilter(genre = genre, primaryFilter = PrimaryFilterType.GENRE))
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria, isSearch = false)
},
@@ -479,7 +479,7 @@ object OpdsV1Controller {
pathParam<Int>("statusId"),
documentWith = { withOperation { summary("OPDS Status Specific Series Feed") } },
behaviorOf = { ctx, statusId ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val criteria = buildCriteriaFromContext(ctx, OpdsMangaFilter(statusId = statusId, primaryFilter = PrimaryFilterType.STATUS))
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria, isSearch = false)
},
@@ -502,7 +502,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, langCode ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val criteria =
buildCriteriaFromContext(ctx, OpdsMangaFilter(langCode = langCode, primaryFilter = PrimaryFilterType.LANGUAGE))
getLibraryFeed(ctx, ctx.queryParam("pageNumber")?.toIntOrNull(), criteria, isSearch = false)
@@ -530,7 +530,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, seriesId, pageNumber, sort, filter, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {
@@ -561,7 +561,7 @@ object OpdsV1Controller {
}
},
behaviorOf = { ctx, seriesId, chapterIndex, lang ->
ctx.getAttribute(Attribute.TachideskUser).requireUser()
ctx.getAttribute(Attribute.TachideskUser).requireUserWithBasicFallback(ctx)
val locale: Locale = LocalizationHelper.ctxToLocale(ctx, lang)
ctx.future {
future {