diff --git a/src/main/kotlin/app/revanced/api/configuration/Dependencies.kt b/src/main/kotlin/app/revanced/api/configuration/Dependencies.kt index a8ed717e..429cbde8 100644 --- a/src/main/kotlin/app/revanced/api/configuration/Dependencies.kt +++ b/src/main/kotlin/app/revanced/api/configuration/Dependencies.kt @@ -7,7 +7,7 @@ import app.revanced.api.configuration.repository.GitHubBackendRepository import app.revanced.api.configuration.services.* import app.revanced.api.configuration.services.AnnouncementService import app.revanced.api.configuration.services.ApiService -import app.revanced.api.configuration.services.AuthService +import app.revanced.api.configuration.services.AuthenticationService import app.revanced.api.configuration.services.OldApiService import app.revanced.api.configuration.services.PatchesService import com.akuleshov7.ktoml.Toml @@ -116,11 +116,11 @@ fun Application.configureDependencies( val jwtSecret = dotenv["JWT_SECRET"] val issuer = dotenv["JWT_ISSUER"] - val validityInMin = dotenv["JWT_VALIDITY_IN_MIN"].toInt() + val validityInMin = dotenv["JWT_VALIDITY_IN_MIN"].toLong() val authSHA256DigestString = dotenv["AUTH_SHA256_DIGEST"] - AuthService(issuer, validityInMin, jwtSecret, authSHA256DigestString) + AuthenticationService(issuer, validityInMin, jwtSecret, authSHA256DigestString) } single { val configuration = get() diff --git a/src/main/kotlin/app/revanced/api/configuration/Security.kt b/src/main/kotlin/app/revanced/api/configuration/Security.kt index 1d6d3864..369f346d 100644 --- a/src/main/kotlin/app/revanced/api/configuration/Security.kt +++ b/src/main/kotlin/app/revanced/api/configuration/Security.kt @@ -1,9 +1,17 @@ package app.revanced.api.configuration -import app.revanced.api.configuration.services.AuthService +import app.revanced.api.configuration.services.AuthenticationService import io.ktor.server.application.* +import io.ktor.server.auth.* import org.koin.ktor.ext.get fun Application.configureSecurity() { - get().configureSecurity(this) + val authenticationService = get() + + install(Authentication) { + with(authenticationService) { + jwt() + digest() + } + } } diff --git a/src/main/kotlin/app/revanced/api/configuration/routes/ApiRoute.kt b/src/main/kotlin/app/revanced/api/configuration/routes/ApiRoute.kt index b88f68eb..07e7def6 100644 --- a/src/main/kotlin/app/revanced/api/configuration/routes/ApiRoute.kt +++ b/src/main/kotlin/app/revanced/api/configuration/routes/ApiRoute.kt @@ -11,7 +11,7 @@ import app.revanced.api.configuration.schema.APIContributable import app.revanced.api.configuration.schema.APIMember import app.revanced.api.configuration.schema.APIRateLimit import app.revanced.api.configuration.services.ApiService -import app.revanced.api.configuration.services.AuthService +import app.revanced.api.configuration.services.AuthenticationService import io.bkbn.kompendium.core.metadata.* import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.oas.payload.Parameter @@ -21,13 +21,12 @@ import io.ktor.server.auth.* import io.ktor.server.plugins.ratelimit.* import io.ktor.server.response.* import io.ktor.server.routing.* -import kotlinx.serialization.json.Json.Default.configuration import kotlin.time.Duration.Companion.days import org.koin.ktor.ext.get as koinGet internal fun Route.apiRoute() { val apiService = koinGet() - val authService = koinGet() + val authenticationService = koinGet() rateLimit(RateLimitName("strong")) { authenticate("auth-digest") { @@ -35,7 +34,7 @@ internal fun Route.apiRoute() { installTokenRouteDocumentation() get { - call.respond(authService.newToken()) + call.respond(authenticationService.newToken()) } } } diff --git a/src/main/kotlin/app/revanced/api/configuration/services/AuthService.kt b/src/main/kotlin/app/revanced/api/configuration/services/AuthService.kt deleted file mode 100644 index 55e43951..00000000 --- a/src/main/kotlin/app/revanced/api/configuration/services/AuthService.kt +++ /dev/null @@ -1,49 +0,0 @@ -package app.revanced.api.configuration.services - -import com.auth0.jwt.JWT -import com.auth0.jwt.algorithms.Algorithm -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.auth.jwt.* -import java.util.* -import kotlin.text.HexFormat -import kotlin.time.Duration.Companion.minutes - -internal class AuthService private constructor( - private val issuer: String, - private val validityInMin: Int, - private val jwtSecret: String, - private val authSHA256Digest: ByteArray, -) { - @OptIn(ExperimentalStdlibApi::class) - constructor(issuer: String, validityInMin: Int, jwtSecret: String, authSHA256DigestString: String) : this( - issuer, - validityInMin, - jwtSecret, - authSHA256DigestString.hexToByteArray(HexFormat.Default), - ) - - val configureSecurity: Application.() -> Unit = { - install(Authentication) { - jwt("jwt") { - realm = "ReVanced" - - verifier(JWT.require(Algorithm.HMAC256(jwtSecret)).withIssuer(issuer).build()) - } - - digest("auth-digest") { - realm = "ReVanced" - algorithmName = "SHA-256" - - digestProvider { _, _ -> - authSHA256Digest - } - } - } - } - - fun newToken(): String = JWT.create() - .withIssuer(issuer) - .withExpiresAt(Date(System.currentTimeMillis() + validityInMin.minutes.inWholeMilliseconds)) - .sign(Algorithm.HMAC256(jwtSecret)) -} diff --git a/src/main/kotlin/app/revanced/api/configuration/services/AuthenticationService.kt b/src/main/kotlin/app/revanced/api/configuration/services/AuthenticationService.kt new file mode 100644 index 00000000..c0e96cf0 --- /dev/null +++ b/src/main/kotlin/app/revanced/api/configuration/services/AuthenticationService.kt @@ -0,0 +1,53 @@ +package app.revanced.api.configuration.services + +import com.auth0.jwt.JWT +import com.auth0.jwt.algorithms.Algorithm +import io.ktor.server.auth.* +import io.ktor.server.auth.jwt.* +import java.time.Instant +import java.time.temporal.ChronoUnit +import kotlin.text.HexFormat + +internal class AuthenticationService private constructor( + private val issuer: String, + private val validityInMin: Long, + private val jwtSecret: String, + private val authSHA256Digest: ByteArray, +) { + @OptIn(ExperimentalStdlibApi::class) + constructor(issuer: String, validityInMin: Long, jwtSecret: String, authSHA256DigestString: String) : this( + issuer, + validityInMin, + jwtSecret, + authSHA256DigestString.hexToByteArray(HexFormat.Default), + ) + + fun AuthenticationConfig.jwt() { + jwt("jwt") { + realm = "ReVanced" + + verifier(JWT.require(Algorithm.HMAC256(jwtSecret)).withIssuer(issuer).build()) + } + } + + fun AuthenticationConfig.digest() { + digest("auth-digest") { + realm = "ReVanced" + algorithmName = "SHA-256" + + digestProvider { _, _ -> + authSHA256Digest + } + } + } + + fun newToken(): String { + val issuedAt = Instant.now() + + return JWT.create() + .withIssuer(issuer) + .withIssuedAt(issuedAt) + .withExpiresAt(issuedAt.plus(validityInMin, ChronoUnit.MINUTES)) + .sign(Algorithm.HMAC256(jwtSecret)) + } +}