mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-04 11:24:35 -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:
@@ -0,0 +1,64 @@
|
||||
package suwayomi.tachidesk.graphql.mutations
|
||||
|
||||
import graphql.schema.DataFetchingEnvironment
|
||||
import suwayomi.tachidesk.global.impl.util.Jwt
|
||||
import suwayomi.tachidesk.graphql.server.getAttribute
|
||||
import suwayomi.tachidesk.server.JavalinSetup.Attribute
|
||||
import suwayomi.tachidesk.server.JavalinSetup.getAttribute
|
||||
import suwayomi.tachidesk.server.serverConfig
|
||||
import suwayomi.tachidesk.server.user.UserType
|
||||
|
||||
class UserMutation {
|
||||
data class LoginInput(
|
||||
val clientMutationId: String? = null,
|
||||
val username: String,
|
||||
val password: String,
|
||||
)
|
||||
|
||||
data class LoginPayload(
|
||||
val clientMutationId: String?,
|
||||
val accessToken: String,
|
||||
val refreshToken: String,
|
||||
)
|
||||
|
||||
fun login(
|
||||
dataFetchingEnvironment: DataFetchingEnvironment,
|
||||
input: LoginInput,
|
||||
): LoginPayload {
|
||||
if (dataFetchingEnvironment.getAttribute(Attribute.TachideskUser) !is UserType.Visitor) {
|
||||
throw IllegalArgumentException("Cannot login while already logged-in")
|
||||
}
|
||||
val isValid =
|
||||
input.username == serverConfig.authUsername.value &&
|
||||
input.password == serverConfig.authPassword.value
|
||||
if (isValid) {
|
||||
val jwt = Jwt.generateJwt()
|
||||
return LoginPayload(
|
||||
clientMutationId = input.clientMutationId,
|
||||
accessToken = jwt.accessToken,
|
||||
refreshToken = jwt.refreshToken,
|
||||
)
|
||||
} else {
|
||||
throw Exception("Incorrect username or password.")
|
||||
}
|
||||
}
|
||||
|
||||
data class RefreshTokenInput(
|
||||
val clientMutationId: String? = null,
|
||||
val refreshToken: String,
|
||||
)
|
||||
|
||||
data class RefreshTokenPayload(
|
||||
val clientMutationId: String?,
|
||||
val accessToken: String,
|
||||
)
|
||||
|
||||
fun refreshToken(input: RefreshTokenInput): RefreshTokenPayload {
|
||||
val accessToken = Jwt.refreshJwt(input.refreshToken)
|
||||
|
||||
return RefreshTokenPayload(
|
||||
clientMutationId = input.clientMutationId,
|
||||
accessToken = accessToken,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user