Compare commits

..

19 Commits

Author SHA1 Message Date
semantic-release-bot
06098415f1 chore: Release v1.3.0-dev.6 [skip ci]
# [1.3.0-dev.6](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.5...v1.3.0-dev.6) (2024-10-02)

### Bug Fixes

* Expose www-authenticate header to JS ([9ed724e](9ed724e161))

### Features

* Only allow requests from HTTPs ([a6d7da1](a6d7da1205))
2024-10-02 04:59:16 +00:00
oSumAtrIX
9ed724e161 fix: Expose www-authenticate header to JS 2024-10-02 06:57:20 +02:00
oSumAtrIX
a6d7da1205 feat: Only allow requests from HTTPs 2024-10-02 06:57:19 +02:00
oSumAtrIX
87174eadd6 ci: Use permissions and regular GitHub token instead of PAT 2024-10-02 06:57:19 +02:00
oSumAtrIX
fde2857915 build(Needs bump): Update dependencies 2024-09-30 23:21:46 +02:00
oSumAtrIX
fae8cb6b23 ci: Adjust release commit message 2024-09-30 22:34:25 +02:00
semantic-release-bot
a754159800 chore(release): 1.3.0-dev.5 [skip ci]
# [1.3.0-dev.5](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.4...v1.3.0-dev.5) (2024-09-30)

### Bug Fixes

* Allow more necessary HTTP methods for CORS ([080e2e5](080e2e582c))
2024-09-30 15:35:42 +00:00
oSumAtrIX
080e2e582c fix: Allow more necessary HTTP methods for CORS 2024-09-30 17:33:15 +02:00
semantic-release-bot
8ff1bbd41f chore(release): 1.3.0-dev.4 [skip ci]
# [1.3.0-dev.4](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.3...v1.3.0-dev.4) (2024-09-29)

### Bug Fixes

* Configure CORS properly to allow authorization and content-type header ([6442757](6442757927))
2024-09-29 23:29:17 +00:00
oSumAtrIX
6442757927 fix: Configure CORS properly to allow authorization and content-type header 2024-09-30 01:27:24 +02:00
semantic-release-bot
710416ff36 chore(release): 1.3.0-dev.3 [skip ci]
# [1.3.0-dev.3](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.2...v1.3.0-dev.3) (2024-09-29)

### Bug Fixes

* Add missing OK response to routes ([1181be1](1181be12e2))
* Respond with JSON when returning token ([1e3e46f](1e3e46ff4f))
* Specify a validation function to fix authentication ([53c3600](53c36002e9))

### Features

* Customize logging level through environment variable ([8b17d88](8b17d8894d))
* Improve response info description wording ([977d252](977d252497))
2024-09-29 21:19:18 +00:00
oSumAtrIX
1181be12e2 fix: Add missing OK response to routes 2024-09-29 23:15:35 +02:00
oSumAtrIX
53c36002e9 fix: Specify a validation function to fix authentication 2024-09-29 23:13:13 +02:00
oSumAtrIX
8b17d8894d feat: Customize logging level through environment variable 2024-09-29 01:03:49 +02:00
oSumAtrIX
1e3e46ff4f fix: Respond with JSON when returning token 2024-09-27 20:19:27 +02:00
oSumAtrIX
977d252497 feat: Improve response info description wording 2024-09-27 19:18:32 +02:00
oSumAtrIX
96bcd7719a chore: Remove unnecessary JWT token field 2024-09-27 19:16:34 +02:00
semantic-release-bot
2d85ce17f6 chore(release): 1.3.0-dev.2 [skip ci]
# [1.3.0-dev.2](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.1...v1.3.0-dev.2) (2024-09-27)

### Bug Fixes

* Expire token relative to current date time instead of just time ([c26e129](c26e129bda))
2024-09-27 12:23:28 +00:00
oSumAtrIX
c26e129bda fix: Expire token relative to current date time instead of just time 2024-09-27 14:16:45 +02:00
16 changed files with 2593 additions and 1319 deletions

View File

@@ -12,7 +12,7 @@ jobs:
name: Release name: Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: write
packages: write packages: write
steps: steps:
- name: Checkout - name: Checkout
@@ -60,7 +60,7 @@ jobs:
DOCKER_REGISTRY_USER: ${{ github.actor }} DOCKER_REGISTRY_USER: ${{ github.actor }}
DOCKER_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} DOCKER_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
GITHUB_ACTOR: ${{ github.actor }} GITHUB_ACTOR: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm exec semantic-release run: npm exec semantic-release
- name: Set Portainer stack webhook URL based on branch - name: Set Portainer stack webhook URL based on branch

View File

@@ -21,10 +21,10 @@
"@semantic-release/git", "@semantic-release/git",
{ {
"assets": [ "assets": [
"README.md",
"CHANGELOG.md", "CHANGELOG.md",
"gradle.properties" "gradle.properties"
] ],
"message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
} }
], ],
[ [

View File

@@ -1,3 +1,51 @@
# [1.3.0-dev.6](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.5...v1.3.0-dev.6) (2024-10-02)
### Bug Fixes
* Expose www-authenticate header to JS ([9ed724e](https://github.com/ReVanced/revanced-api/commit/9ed724e161f9029967f67e4c2066f2fdf7be0a27))
### Features
* Only allow requests from HTTPs ([a6d7da1](https://github.com/ReVanced/revanced-api/commit/a6d7da1205ef7bc23eba0b1fca2480a4327def19))
# [1.3.0-dev.5](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.4...v1.3.0-dev.5) (2024-09-30)
### Bug Fixes
* Allow more necessary HTTP methods for CORS ([080e2e5](https://github.com/ReVanced/revanced-api/commit/080e2e582cb8ea97421c402a4cb82414e11fb1cf))
# [1.3.0-dev.4](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.3...v1.3.0-dev.4) (2024-09-29)
### Bug Fixes
* Configure CORS properly to allow authorization and content-type header ([6442757](https://github.com/ReVanced/revanced-api/commit/6442757927c0307c01b2793858d25df7e3fca122))
# [1.3.0-dev.3](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.2...v1.3.0-dev.3) (2024-09-29)
### Bug Fixes
* Add missing OK response to routes ([1181be1](https://github.com/ReVanced/revanced-api/commit/1181be12e2223b245019f64570bc8f7bef4e7dc2))
* Respond with JSON when returning token ([1e3e46f](https://github.com/ReVanced/revanced-api/commit/1e3e46ff4f7c12569b88fcd1bc252aeb5a611b63))
* Specify a validation function to fix authentication ([53c3600](https://github.com/ReVanced/revanced-api/commit/53c36002e9af89aa5fed71f831470b42d5d777c9))
### Features
* Customize logging level through environment variable ([8b17d88](https://github.com/ReVanced/revanced-api/commit/8b17d8894db8db4a168c30be50af91c04e173e14))
* Improve response info description wording ([977d252](https://github.com/ReVanced/revanced-api/commit/977d25249738b24cb6a3530543349efe1d71a9ba))
# [1.3.0-dev.2](https://github.com/ReVanced/revanced-api/compare/v1.3.0-dev.1...v1.3.0-dev.2) (2024-09-27)
### Bug Fixes
* Expire token relative to current date time instead of just time ([c26e129](https://github.com/ReVanced/revanced-api/commit/c26e129bda09345761f291917f026c13e89a2572))
# [1.3.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.2.0...v1.3.0-dev.1) (2024-09-11) # [1.3.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.2.0...v1.3.0-dev.1) (2024-09-11)

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true org.gradle.parallel = true
org.gradle.caching = true org.gradle.caching = true
kotlin.code.style = official kotlin.code.style = official
version = 1.3.0-dev.1 version = 1.3.0-dev.6

3648
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"@saithodev/semantic-release-backmerge": "^4.0.1", "@saithodev/semantic-release-backmerge": "^4.0.1",
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.9.2", "gradle-semantic-release-plugin": "^1.10.1",
"semantic-release": "^24.0.0" "semantic-release": "^24.1.2"
} }
} }

View File

@@ -1,6 +1,7 @@
package app.revanced.api.command package app.revanced.api.command
import app.revanced.api.configuration.* import app.revanced.api.configuration.*
import io.github.cdimascio.dotenv.Dotenv
import io.ktor.server.engine.* import io.ktor.server.engine.*
import io.ktor.server.jetty.* import io.ktor.server.jetty.*
import picocli.CommandLine import picocli.CommandLine
@@ -33,6 +34,8 @@ internal object StartAPICommand : Runnable {
private var configFile = File("configuration.toml") private var configFile = File("configuration.toml")
override fun run() { override fun run() {
Dotenv.configure().systemProperties().load()
embeddedServer(Jetty, port, host) { embeddedServer(Jetty, port, host) {
configureDependencies(configFile) configureDependencies(configFile)
configureHTTP() configureHTTP()

View File

@@ -7,12 +7,11 @@ import app.revanced.api.configuration.repository.GitHubBackendRepository
import app.revanced.api.configuration.services.* import app.revanced.api.configuration.services.*
import app.revanced.api.configuration.services.AnnouncementService import app.revanced.api.configuration.services.AnnouncementService
import app.revanced.api.configuration.services.ApiService 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.OldApiService
import app.revanced.api.configuration.services.PatchesService import app.revanced.api.configuration.services.PatchesService
import com.akuleshov7.ktoml.Toml import com.akuleshov7.ktoml.Toml
import com.akuleshov7.ktoml.source.decodeFromStream import com.akuleshov7.ktoml.source.decodeFromStream
import io.github.cdimascio.dotenv.Dotenv
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.engine.okhttp.* import io.ktor.client.engine.okhttp.*
import io.ktor.client.plugins.* import io.ktor.client.plugins.*
@@ -38,11 +37,7 @@ import java.io.File
fun Application.configureDependencies( fun Application.configureDependencies(
configFile: File, configFile: File,
) { ) {
val globalModule = module { val miscModule = module {
single {
Dotenv.configure().load()
}
factory { params -> factory { params ->
val defaultRequestUri: String = params.get<String>() val defaultRequestUri: String = params.get<String>()
val configBlock = params.getOrNull<(HttpClientConfig<OkHttpConfig>.() -> Unit)>() ?: {} val configBlock = params.getOrNull<(HttpClientConfig<OkHttpConfig>.() -> Unit)>() ?: {}
@@ -72,7 +67,7 @@ fun Application.configureDependencies(
) )
} }
get<Dotenv>()["BACKEND_API_TOKEN"]?.let { System.getProperty("BACKEND_API_TOKEN")?.let {
install(Auth) { install(Auth) {
bearer { bearer {
loadTokens { loadTokens {
@@ -98,12 +93,10 @@ fun Application.configureDependencies(
} }
single { single {
val dotenv = get<Dotenv>()
TransactionManager.defaultDatabase = Database.connect( TransactionManager.defaultDatabase = Database.connect(
url = dotenv["DB_URL"], url = System.getProperty("DB_URL"),
user = dotenv["DB_USER"], user = System.getProperty("DB_USER"),
password = dotenv["DB_PASSWORD"], password = System.getProperty("DB_PASSWORD"),
) )
AnnouncementRepository() AnnouncementRepository()
@@ -112,15 +105,13 @@ fun Application.configureDependencies(
val serviceModule = module { val serviceModule = module {
single { single {
val dotenv = get<Dotenv>() val jwtSecret = System.getProperty("JWT_SECRET")
val issuer = System.getProperty("JWT_ISSUER")
val validityInMin = System.getProperty("JWT_VALIDITY_IN_MIN").toLong()
val jwtSecret = dotenv["JWT_SECRET"] val authSHA256DigestString = System.getProperty("AUTH_SHA256_DIGEST")
val issuer = dotenv["JWT_ISSUER"]
val validityInMin = dotenv["JWT_VALIDITY_IN_MIN"].toInt()
val authSHA256DigestString = dotenv["AUTH_SHA256_DIGEST"] AuthenticationService(issuer, validityInMin, jwtSecret, authSHA256DigestString)
AuthService(issuer, validityInMin, jwtSecret, authSHA256DigestString)
} }
single { single {
val configuration = get<ConfigurationRepository>() val configuration = get<ConfigurationRepository>()
@@ -140,7 +131,7 @@ fun Application.configureDependencies(
install(Koin) { install(Koin) {
modules( modules(
globalModule, miscModule,
repositoryModule, repositoryModule,
serviceModule, serviceModule,
) )

View File

@@ -1,6 +1,7 @@
package app.revanced.api.configuration package app.revanced.api.configuration
import app.revanced.api.configuration.repository.ConfigurationRepository import app.revanced.api.configuration.repository.ConfigurationRepository
import io.ktor.http.*
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.plugins.* import io.ktor.server.plugins.*
import io.ktor.server.plugins.cors.routing.* import io.ktor.server.plugins.cors.routing.*
@@ -13,11 +14,16 @@ fun Application.configureHTTP() {
val configurationRepository = get<ConfigurationRepository>() val configurationRepository = get<ConfigurationRepository>()
install(CORS) { install(CORS) {
HttpMethod.DefaultMethods.minus(HttpMethod.Options).forEach(::allowMethod)
allowHeader(HttpHeaders.ContentType)
allowHeader(HttpHeaders.Authorization)
exposeHeader(HttpHeaders.WWWAuthenticate)
allowCredentials = true
configurationRepository.corsAllowedHosts.forEach { host -> configurationRepository.corsAllowedHosts.forEach { host ->
allowHost( allowHost(host = host, schemes = listOf("https"))
host = host,
schemes = listOf("http", "https")
)
} }
} }

View File

@@ -1,9 +1,17 @@
package app.revanced.api.configuration 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.application.*
import io.ktor.server.auth.*
import org.koin.ktor.ext.get import org.koin.ktor.ext.get
fun Application.configureSecurity() { fun Application.configureSecurity() {
get<AuthService>().configureSecurity(this) val authenticationService = get<AuthenticationService>()
install(Authentication) {
with(authenticationService) {
jwt()
digest()
}
}
} }

View File

@@ -94,6 +94,8 @@ internal fun Route.announcementsRoute() = route("announcements") {
post<APIAnnouncement> { announcement -> post<APIAnnouncement> { announcement ->
announcementService.new(announcement) announcementService.new(announcement)
call.respond(HttpStatusCode.OK)
} }
route("{id}") { route("{id}") {
@@ -103,12 +105,16 @@ internal fun Route.announcementsRoute() = route("announcements") {
val id: Int by call.parameters val id: Int by call.parameters
announcementService.update(id, announcement) announcementService.update(id, announcement)
call.respond(HttpStatusCode.OK)
} }
delete { delete {
val id: Int by call.parameters val id: Int by call.parameters
announcementService.delete(id) announcementService.delete(id)
call.respond(HttpStatusCode.OK)
} }
route("archive") { route("archive") {
@@ -119,6 +125,8 @@ internal fun Route.announcementsRoute() = route("announcements") {
val archivedAt = call.receiveNullable<APIAnnouncementArchivedAt>()?.archivedAt val archivedAt = call.receiveNullable<APIAnnouncementArchivedAt>()?.archivedAt
announcementService.archive(id, archivedAt) announcementService.archive(id, archivedAt)
call.respond(HttpStatusCode.OK)
} }
} }
@@ -129,6 +137,8 @@ internal fun Route.announcementsRoute() = route("announcements") {
val id: Int by call.parameters val id: Int by call.parameters
announcementService.unarchive(id) announcementService.unarchive(id)
call.respond(HttpStatusCode.OK)
} }
} }
} }
@@ -157,7 +167,7 @@ private fun Route.installAnnouncementRouteDocumentation() = installNotarizedRout
description("The new announcement") description("The new announcement")
} }
response { response {
description("When the announcement was created") description("The announcement is created")
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
responseType<Unit>() responseType<Unit>()
} }
@@ -255,7 +265,7 @@ private fun Route.installAnnouncementArchiveRouteDocumentation() = installNotari
description("Archive an announcement") description("Archive an announcement")
summary("Archive announcement") summary("Archive announcement")
response { response {
description("When the announcement was archived") description("The announcement is archived")
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
responseType<Unit>() responseType<Unit>()
} }
@@ -281,7 +291,7 @@ private fun Route.installAnnouncementUnarchiveRouteDocumentation() = installNota
description("Unarchive an announcement") description("Unarchive an announcement")
summary("Unarchive announcement") summary("Unarchive announcement")
response { response {
description("When announcement was unarchived") description("The announcement is unarchived")
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
responseType<Unit>() responseType<Unit>()
} }
@@ -311,7 +321,7 @@ private fun Route.installAnnouncementIdRouteDocumentation() = installNotarizedRo
description("The new announcement") description("The new announcement")
} }
response { response {
description("When announcement was updated") description("The announcement is updated")
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
responseType<Unit>() responseType<Unit>()
} }
@@ -322,7 +332,7 @@ private fun Route.installAnnouncementIdRouteDocumentation() = installNotarizedRo
description("Delete an announcement") description("Delete an announcement")
summary("Delete announcement") summary("Delete announcement")
response { response {
description("When the announcement was deleted") description("The announcement is deleted")
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
responseType<Unit>() responseType<Unit>()
} }

View File

@@ -6,12 +6,9 @@ import app.revanced.api.configuration.installNoCache
import app.revanced.api.configuration.installNotarizedRoute import app.revanced.api.configuration.installNotarizedRoute
import app.revanced.api.configuration.repository.ConfigurationRepository import app.revanced.api.configuration.repository.ConfigurationRepository
import app.revanced.api.configuration.respondOrNotFound import app.revanced.api.configuration.respondOrNotFound
import app.revanced.api.configuration.schema.APIAbout import app.revanced.api.configuration.schema.*
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.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.core.metadata.*
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
@@ -21,13 +18,12 @@ import io.ktor.server.auth.*
import io.ktor.server.plugins.ratelimit.* import io.ktor.server.plugins.ratelimit.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
import kotlinx.serialization.json.Json.Default.configuration
import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.days
import org.koin.ktor.ext.get as koinGet import org.koin.ktor.ext.get as koinGet
internal fun Route.apiRoute() { internal fun Route.apiRoute() {
val apiService = koinGet<ApiService>() val apiService = koinGet<ApiService>()
val authService = koinGet<AuthService>() val authenticationService = koinGet<AuthenticationService>()
rateLimit(RateLimitName("strong")) { rateLimit(RateLimitName("strong")) {
authenticate("auth-digest") { authenticate("auth-digest") {
@@ -35,7 +31,7 @@ internal fun Route.apiRoute() {
installTokenRouteDocumentation() installTokenRouteDocumentation()
get { get {
call.respond(authService.newToken()) call.respond(authenticationService.newToken())
} }
} }
} }
@@ -199,7 +195,7 @@ private fun Route.installTokenRouteDocumentation() = installNotarizedRoute {
description("The authorization token") description("The authorization token")
mediaTypes("application/json") mediaTypes("application/json")
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
responseType<String>() responseType<APIToken>()
} }
canRespondUnauthorized() canRespondUnauthorized()
} }

View File

@@ -172,3 +172,6 @@ class APIAbout(
val links: List<Link>?, val links: List<Link>?,
) )
} }
@Serializable
class APIToken(val token: String)

View File

@@ -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))
}

View File

@@ -0,0 +1,52 @@
package app.revanced.api.configuration.services
import app.revanced.api.configuration.schema.APIToken
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())
// This is required and not optional. Authentication will fail if this is not present.
validate { JWTPrincipal(it.payload) }
}
}
fun AuthenticationConfig.digest() {
digest("auth-digest") {
realm = "ReVanced"
algorithmName = "SHA-256"
digestProvider { _, _ ->
authSHA256Digest
}
}
}
fun newToken() = APIToken(
JWT.create()
.withIssuer(issuer)
.withExpiresAt(Instant.now().plus(validityInMin, ChronoUnit.MINUTES))
.sign(Algorithm.HMAC256(jwtSecret)),
)
}

View File

@@ -4,7 +4,7 @@
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>
<root level="info"> <root level="\${LOG_LEVEL:-INFO}">
<appender-ref ref="STDOUT"/> <appender-ref ref="STDOUT"/>
</root> </root>
</configuration> </configuration>