Skip to content

Commit

Permalink
feat: Add manager route
Browse files Browse the repository at this point in the history
  • Loading branch information
oSumAtrIX committed Jul 12, 2024
1 parent a34b7c8 commit f814fe5
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 30 deletions.
1 change: 1 addition & 0 deletions configuration.example.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
organization = "revanced"
patches = { repository = "revanced-patches", asset-regex = "jar$", signature-asset-regex = "asc$", public-key-file = "patches-public-key.asc" }
integrations = { repository = "revanced-integrations", asset-regex = "apk$", signature-asset-regex = "asc$", public-key-file = "integrations-public-key.asc" }
manager = { repository = "revanced-manager", asset-regex = "apk$" }
contributors-repositories = [
"revanced-patcher",
"revanced-patches",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ fun Application.configureDependencies(
singleOf(::AnnouncementService)
singleOf(::SignatureService)
singleOf(::PatchesService)
singleOf(::ManagerService)
singleOf(::ApiService)
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/app/revanced/api/configuration/Routing.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package app.revanced.api.configuration

import app.revanced.api.configuration.repository.ConfigurationRepository
import app.revanced.api.configuration.routes.*
import app.revanced.api.configuration.routes.announcementsRoute
import app.revanced.api.configuration.routes.apiRoute
import app.revanced.api.configuration.routes.oldApiRoute
Expand All @@ -22,6 +23,7 @@ internal fun Application.configureRouting() = routing {
route("/v${configuration.apiVersion}") {
announcementsRoute()
patchesRoute()
managerRoute()
apiRoute()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.revanced.api.configuration.repository

import app.revanced.api.configuration.services.ManagerService
import app.revanced.api.configuration.services.PatchesService
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
Expand All @@ -17,6 +18,7 @@ import java.io.File
* @property organization The API backends organization name where the repositories for the patches and integrations are.
* @property patches The source of the patches.
* @property integrations The source of the integrations.
* @property manager The source of the manager.
* @property contributorsRepositoryNames The names of the repositories to get contributors from.
* @property apiVersion The version to use for the API.
* @property corsAllowedHosts The hosts allowed to make requests to the API.
Expand All @@ -26,8 +28,9 @@ import java.io.File
@Serializable
internal class ConfigurationRepository(
val organization: String,
val patches: AssetConfiguration,
val integrations: AssetConfiguration,
val patches: SignedAssetConfiguration,
val integrations: SignedAssetConfiguration,
val manager: AssetConfiguration,
@SerialName("contributors-repositories")
val contributorsRepositoryNames: Set<String>,
@SerialName("api-version")
Expand All @@ -39,9 +42,9 @@ internal class ConfigurationRepository(
val oldApiEndpoint: String,
) {
/**
* An asset configuration.
* Am asset configuration whose asset is signed.
*
* [PatchesService] uses [BackendRepository] to get assets from its releases.
* [PatchesService] for example uses [BackendRepository] to get assets from its releases.
* A release contains multiple assets.
*
* This configuration is used in [ConfigurationRepository]
Expand All @@ -54,7 +57,7 @@ internal class ConfigurationRepository(
* @property publicKeyId The ID of the public key to verify the signature of the asset.
*/
@Serializable
internal class AssetConfiguration(
internal class SignedAssetConfiguration(
val repository: String,
@Serializable(with = RegexSerializer::class)
@SerialName("asset-regex")
Expand All @@ -68,6 +71,26 @@ internal class ConfigurationRepository(
@SerialName("public-key-id")
val publicKeyId: Long,
)

/**
* Am asset configuration.
*
* [ManagerService] for example uses [BackendRepository] to get assets from its releases.
* A release contains multiple assets.
*
* This configuration is used in [ConfigurationRepository]
* to determine which release assets from repositories to get and to verify them.
*
* @property repository The repository in which releases are made to get an asset.
* @property assetRegex The regex matching the asset name.
*/
@Serializable
internal class AssetConfiguration(
val repository: String,
@Serializable(with = RegexSerializer::class)
@SerialName("asset-regex")
val assetRegex: Regex,
)
}

private object RegexSerializer : KSerializer<Regex> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ internal fun Route.apiRoute() {
}
}

fun Route.installRateLimitRouteDocumentation() = installNotarizedRoute {
private fun Route.installRateLimitRouteDocumentation() = installNotarizedRoute {
tags = setOf("API")

get = GetInfo.builder {
Expand All @@ -97,7 +97,7 @@ fun Route.installRateLimitRouteDocumentation() = installNotarizedRoute {
}
}

fun Route.installPingRouteDocumentation() = installNotarizedRoute {
private fun Route.installPingRouteDocumentation() = installNotarizedRoute {
tags = setOf("API")

head = HeadInfo.builder {
Expand All @@ -111,7 +111,7 @@ fun Route.installPingRouteDocumentation() = installNotarizedRoute {
}
}

fun Route.installTeamRouteDocumentation() = installNotarizedRoute {
private fun Route.installTeamRouteDocumentation() = installNotarizedRoute {
tags = setOf("API")

get = GetInfo.builder {
Expand All @@ -126,7 +126,7 @@ fun Route.installTeamRouteDocumentation() = installNotarizedRoute {
}
}

fun Route.installContributorsRouteDocumentation() = installNotarizedRoute {
private fun Route.installContributorsRouteDocumentation() = installNotarizedRoute {
tags = setOf("API")

get = GetInfo.builder {
Expand All @@ -141,7 +141,7 @@ fun Route.installContributorsRouteDocumentation() = installNotarizedRoute {
}
}

fun Route.installTokenRouteDocumentation() = installNotarizedRoute {
private fun Route.installTokenRouteDocumentation() = installNotarizedRoute {
tags = setOf("API")

get = GetInfo.builder {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package app.revanced.api.configuration.routes

import app.revanced.api.configuration.installNotarizedRoute
import app.revanced.api.configuration.schema.APIManagerAsset
import app.revanced.api.configuration.schema.APIRelease
import app.revanced.api.configuration.schema.APIReleaseVersion
import app.revanced.api.configuration.services.ManagerService
import io.bkbn.kompendium.core.metadata.GetInfo
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.plugins.ratelimit.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import org.koin.ktor.ext.get as koinGet

internal fun Route.managerRoute() = route("manager") {
val managerService = koinGet<ManagerService>()

route("latest") {
installLatestManagerRouteDocumentation()

rateLimit(RateLimitName("weak")) {
get {
call.respond(managerService.latestRelease())
}

route("version") {
installLatestManagerVersionRouteDocumentation()

get {
call.respond(managerService.latestVersion())
}
}
}
}
}

private fun Route.installLatestManagerRouteDocumentation() = installNotarizedRoute {
tags = setOf("Manager")

get = GetInfo.builder {
description("Get the latest manager release")
summary("Get latest Manager release")
response {
description("The latest manager release")
mediaTypes("application/json")
responseCode(HttpStatusCode.OK)
responseType<APIRelease<APIManagerAsset>>()
}
}
}

private fun Route.installLatestManagerVersionRouteDocumentation() = installNotarizedRoute {
tags = setOf("Manager")

get = GetInfo.builder {
description("Get the latest manager release version")
summary("Get latest manager release version")
response {
description("The latest manager release version")
mediaTypes("application/json")
responseCode(HttpStatusCode.OK)
responseType<APIReleaseVersion>()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app.revanced.api.configuration.routes
import app.revanced.api.configuration.installCache
import app.revanced.api.configuration.installNotarizedRoute
import app.revanced.api.configuration.schema.APIAssetPublicKeys
import app.revanced.api.configuration.schema.APIPatchesAsset
import app.revanced.api.configuration.schema.APIRelease
import app.revanced.api.configuration.schema.APIReleaseVersion
import app.revanced.api.configuration.services.PatchesService
Expand Down Expand Up @@ -59,7 +60,7 @@ internal fun Route.patchesRoute() = route("patches") {
}
}

fun Route.installLatestPatchesRouteDocumentation() = installNotarizedRoute {
private fun Route.installLatestPatchesRouteDocumentation() = installNotarizedRoute {
tags = setOf("Patches")

get = GetInfo.builder {
Expand All @@ -69,12 +70,12 @@ fun Route.installLatestPatchesRouteDocumentation() = installNotarizedRoute {
description("The latest patches release")
mediaTypes("application/json")
responseCode(HttpStatusCode.OK)
responseType<APIRelease>()
responseType<APIRelease<APIPatchesAsset>>()
}
}
}

fun Route.installLatestPatchesVersionRouteDocumentation() = installNotarizedRoute {
private fun Route.installLatestPatchesVersionRouteDocumentation() = installNotarizedRoute {
tags = setOf("Patches")

get = GetInfo.builder {
Expand All @@ -89,7 +90,7 @@ fun Route.installLatestPatchesVersionRouteDocumentation() = installNotarizedRout
}
}

fun Route.installLatestPatchesListRouteDocumentation() = installNotarizedRoute {
private fun Route.installLatestPatchesListRouteDocumentation() = installNotarizedRoute {
tags = setOf("Patches")

get = GetInfo.builder {
Expand All @@ -104,7 +105,7 @@ fun Route.installLatestPatchesListRouteDocumentation() = installNotarizedRoute {
}
}

fun Route.installPatchesPublicKeyRouteDocumentation() = installNotarizedRoute {
private fun Route.installPatchesPublicKeyRouteDocumentation() = installNotarizedRoute {
tags = setOf("Patches")

get = GetInfo.builder {
Expand Down
25 changes: 15 additions & 10 deletions src/main/kotlin/app/revanced/api/configuration/schema/APISchema.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,6 @@ package app.revanced.api.configuration.schema
import kotlinx.datetime.LocalDateTime
import kotlinx.serialization.Serializable

@Serializable
class APIRelease(
val version: String,
val createdAt: LocalDateTime,
val description: String,
// Using a list instead of a set because set semantics are unnecessary here.
val assets: List<APIAsset>,
)

interface APIUser {
val name: String
val avatarUrl: String
Expand Down Expand Up @@ -48,7 +39,21 @@ class APIContributable(
)

@Serializable
class APIAsset(
class APIRelease<T>(
val version: String,
val createdAt: LocalDateTime,
val description: String,
// Using a list instead of a set because set semantics are unnecessary here.
val assets: List<T>,
)

@Serializable
class APIManagerAsset(
val downloadUrl: String,
)

@Serializable
class APIPatchesAsset(
val downloadUrl: String,
val signatureDownloadUrl: String,
// TODO: Remove this eventually when integrations are merged into patches.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package app.revanced.api.configuration.services

import app.revanced.api.configuration.repository.BackendRepository
import app.revanced.api.configuration.repository.BackendRepository.BackendOrganization.BackendRepository.BackendRelease.Companion.first
import app.revanced.api.configuration.repository.ConfigurationRepository
import app.revanced.api.configuration.schema.*

internal class ManagerService(
private val backendRepository: BackendRepository,
private val configurationRepository: ConfigurationRepository,
) {
suspend fun latestRelease(): APIRelease<APIManagerAsset> {
val managerRelease = backendRepository.release(
configurationRepository.organization,
configurationRepository.manager.repository,
)

val managerAsset = APIManagerAsset(
managerRelease.assets.first(configurationRepository.manager.assetRegex).downloadUrl,
)

return APIRelease(
managerRelease.tag,
managerRelease.createdAt,
managerRelease.releaseNote,
listOf(managerAsset),
)
}

suspend fun latestVersion(): APIReleaseVersion {
val managerRelease = backendRepository.release(
configurationRepository.organization,
configurationRepository.manager.repository,
)

return APIReleaseVersion(managerRelease.tag)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal class PatchesService(
private val backendRepository: BackendRepository,
private val configurationRepository: ConfigurationRepository,
) {
suspend fun latestRelease(): APIRelease {
suspend fun latestRelease(): APIRelease<APIPatchesAsset> {
val patchesRelease = backendRepository.release(
configurationRepository.organization,
configurationRepository.patches.repository,
Expand All @@ -29,10 +29,10 @@ internal class PatchesService(
configurationRepository.integrations.repository,
)

fun ConfigurationRepository.AssetConfiguration.asset(
fun ConfigurationRepository.SignedAssetConfiguration.asset(
release: BackendRepository.BackendOrganization.BackendRepository.BackendRelease,
assetName: APIAssetName,
) = APIAsset(
) = APIPatchesAsset(
release.assets.first(assetRegex).downloadUrl,
release.assets.first(signatureAssetRegex).downloadUrl,
assetName,
Expand Down Expand Up @@ -113,8 +113,8 @@ internal class PatchesService(
}

fun publicKeys(): APIAssetPublicKeys {
fun publicKeyBase64(getAssetConfiguration: ConfigurationRepository.() -> ConfigurationRepository.AssetConfiguration) =
configurationRepository.getAssetConfiguration().publicKeyFile.readBytes().encodeBase64()
fun publicKeyBase64(getSignedAssetConfiguration: ConfigurationRepository.() -> ConfigurationRepository.SignedAssetConfiguration) =
configurationRepository.getSignedAssetConfiguration().publicKeyFile.readBytes().encodeBase64()

return APIAssetPublicKeys(
publicKeyBase64 { patches },
Expand Down

0 comments on commit f814fe5

Please sign in to comment.