diff --git a/.gitignore b/.gitignore index 674971b..3900863 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ configuration.toml docker-compose.yml patches-public-key.asc integrations-public-key.asc -node_modules/ \ No newline at end of file +node_modules/ +static/ \ No newline at end of file diff --git a/configuration.example.toml b/configuration.example.toml index 0ad3059..c380e15 100644 --- a/configuration.example.toml +++ b/configuration.example.toml @@ -17,3 +17,5 @@ cors-allowed-hosts = [ ] endpoint = "https://api.revanced.app" old-api-endpoint = "https://old-api.revanced.app" +static-files-path = "static/root" +versioned-static-files-path = "static/versioned" \ No newline at end of file diff --git a/docker-compose.example.yml b/docker-compose.example.yml index a82e58e..49b9d54 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -8,6 +8,7 @@ services: - /data/revanced-api/configuration.toml:/app/configuration.toml - /data/revanced-api/patches-public-key.asc:/app/patches-public-key.asc - /data/revanced-api/integrations-public-key.asc:/app/integrations-public-key.asc + - /data/revanced-api/static:/app/static environment: - COMMAND=start ports: diff --git a/src/main/kotlin/app/revanced/api/configuration/Extensions.kt b/src/main/kotlin/app/revanced/api/configuration/Extensions.kt index d754693..4d38721 100644 --- a/src/main/kotlin/app/revanced/api/configuration/Extensions.kt +++ b/src/main/kotlin/app/revanced/api/configuration/Extensions.kt @@ -4,8 +4,12 @@ import io.bkbn.kompendium.core.plugin.NotarizedRoute import io.ktor.http.* import io.ktor.http.content.* import io.ktor.server.application.* +import io.ktor.server.http.content.* import io.ktor.server.plugins.cachingheaders.* import io.ktor.server.response.* +import io.ktor.server.routing.* +import java.io.File +import java.nio.file.Path import kotlin.time.Duration internal suspend fun ApplicationCall.respondOrNotFound(value: Any?) = respond(value ?: HttpStatusCode.NotFound) @@ -25,3 +29,14 @@ internal fun ApplicationCallPipeline.installCache(cacheControl: CacheControl) = internal fun ApplicationCallPipeline.installNotarizedRoute(configure: NotarizedRoute.Config.() -> Unit = {}) = install(NotarizedRoute(), configure) + +internal fun Route.staticFiles( + remotePath: String, + dir: Path, + block: StaticContentConfig.() -> Unit = { + contentType { + ContentType.Application.Json + } + extensions("json") + }, +) = staticFiles(remotePath, dir.toFile(), null, block) diff --git a/src/main/kotlin/app/revanced/api/configuration/Routing.kt b/src/main/kotlin/app/revanced/api/configuration/Routing.kt index fe60ebc..91018a9 100644 --- a/src/main/kotlin/app/revanced/api/configuration/Routing.kt +++ b/src/main/kotlin/app/revanced/api/configuration/Routing.kt @@ -8,9 +8,7 @@ import app.revanced.api.configuration.routes.oldApiRoute import app.revanced.api.configuration.routes.patchesRoute import io.bkbn.kompendium.core.routes.redoc import io.bkbn.kompendium.core.routes.swagger -import io.ktor.http.* import io.ktor.server.application.* -import io.ktor.server.http.content.* import io.ktor.server.routing.* import kotlin.time.Duration.Companion.minutes import org.koin.ktor.ext.get as koinGet @@ -27,10 +25,7 @@ internal fun Application.configureRouting() = routing { apiRoute() } - staticResources("/", "/app/revanced/api/static/root") { - contentType { ContentType.Application.Json } - extensions("json") - } + staticFiles("/", configuration.staticFilesPath) swagger(pageTitle = "ReVanced API", path = "/") redoc(pageTitle = "ReVanced API", path = "/redoc") diff --git a/src/main/kotlin/app/revanced/api/configuration/repository/ConfigurationRepository.kt b/src/main/kotlin/app/revanced/api/configuration/repository/ConfigurationRepository.kt index 4e13cf6..6325b3c 100644 --- a/src/main/kotlin/app/revanced/api/configuration/repository/ConfigurationRepository.kt +++ b/src/main/kotlin/app/revanced/api/configuration/repository/ConfigurationRepository.kt @@ -11,6 +11,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import java.io.File +import java.nio.file.Path /** * The repository storing the configuration for the API. @@ -24,6 +25,8 @@ import java.io.File * @property corsAllowedHosts The hosts allowed to make requests to the API. * @property endpoint The endpoint of the API. * @property oldApiEndpoint The endpoint of the old API to proxy requests to. + * @property staticFilesPath The path to the static files to be served under the root path. + * @property versionedStaticFilesPath The path to the static files to be served under a versioned path. */ @Serializable internal class ConfigurationRepository( @@ -40,6 +43,12 @@ internal class ConfigurationRepository( val endpoint: String, @SerialName("old-api-endpoint") val oldApiEndpoint: String, + @Serializable(with = PathSerializer::class) + @SerialName("static-files-path") + val staticFilesPath: Path, + @Serializable(with = PathSerializer::class) + @SerialName("versioned-static-files-path") + val versionedStaticFilesPath: Path, ) { /** * Am asset configuration whose asset is signed. @@ -108,3 +117,11 @@ private object FileSerializer : KSerializer { override fun deserialize(decoder: Decoder) = File(decoder.decodeString()) } + +private object PathSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Path", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: Path) = encoder.encodeString(value.toString()) + + override fun deserialize(decoder: Decoder) = Path.of(decoder.decodeString()) +} 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 5152d65..7c6c580 100644 --- a/src/main/kotlin/app/revanced/api/configuration/routes/ApiRoute.kt +++ b/src/main/kotlin/app/revanced/api/configuration/routes/ApiRoute.kt @@ -1,5 +1,6 @@ package app.revanced.api.configuration.routes +import app.revanced.api.configuration.* import app.revanced.api.configuration.installCache import app.revanced.api.configuration.installNoCache import app.revanced.api.configuration.installNotarizedRoute @@ -13,7 +14,6 @@ import io.bkbn.kompendium.core.metadata.* import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.auth.* -import io.ktor.server.http.content.* import io.ktor.server.plugins.ratelimit.* import io.ktor.server.response.* import io.ktor.server.routing.* @@ -75,10 +75,7 @@ internal fun Route.apiRoute() { } } - staticResources("/", "/app/revanced/api/static/versioned") { - contentType { ContentType.Application.Json } - extensions("json") - } + staticFiles("/", apiService.versionedStaticFilesPath) } } diff --git a/src/main/kotlin/app/revanced/api/configuration/services/ApiService.kt b/src/main/kotlin/app/revanced/api/configuration/services/ApiService.kt index 0a73fff..cac63e6 100644 --- a/src/main/kotlin/app/revanced/api/configuration/services/ApiService.kt +++ b/src/main/kotlin/app/revanced/api/configuration/services/ApiService.kt @@ -12,6 +12,8 @@ internal class ApiService( private val backendRepository: BackendRepository, private val configurationRepository: ConfigurationRepository, ) { + val versionedStaticFilesPath = configurationRepository.versionedStaticFilesPath + suspend fun contributors() = withContext(Dispatchers.IO) { configurationRepository.contributorsRepositoryNames.map { async { diff --git a/src/main/resources/app/revanced/api/static/root/robots.txt b/src/main/resources/app/revanced/api/static/root/robots.txt deleted file mode 100644 index 77470cb..0000000 --- a/src/main/resources/app/revanced/api/static/root/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / \ No newline at end of file diff --git a/src/main/resources/app/revanced/api/static/versioned/about.json b/src/main/resources/app/revanced/api/static/versioned/about.json deleted file mode 100644 index a947c48..0000000 --- a/src/main/resources/app/revanced/api/static/versioned/about.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "name": "ReVanced", - "about": "ReVanced was born out of Vanced's discontinuation and it is our goal to continue the legacy of what Vanced left behind. Thanks to ReVanced Patcher, it's possible to create long-lasting patches for nearly any Android app. ReVanced's patching system is designed to allow patches to work on new versions of the apps automatically with bare minimum maintenance.", - "branding": { - "logo": "https://raw.githubusercontent.com/ReVanced/revanced-branding/main/assets/revanced-logo/revanced-logo.svg" - }, - "contact": { - "email": "contact@revanced.app" - }, - "socials": [ - { - "name": "Website", - "url": "https://revanced.app", - "preferred": true - }, - { - "name": "GitHub", - "url": "https://github.com/revanced" - }, - { - "name": "Twitter", - "url": "https://twitter.com/revancedapp" - }, - { - "name": "Discord", - "url": "https://revanced.app/discord", - "preferred": true - }, - { - "name": "Reddit", - "url": "https://www.reddit.com/r/revancedapp" - }, - { - "name": "Telegram", - "url": "https://t.me/app_revanced" - }, - { - "name": "YouTube", - "url": "https://www.youtube.com/@ReVanced" - } - ], - "donations": { - "wallets": [ - { - "network": "Bitcoin", - "currency_code": "BTC", - "address": "bc1q4x8j6mt27y5gv0q625t8wkr87ruy8fprpy4v3f" - }, - { - "network": "Dogecoin", - "currency_code": "DOGE", - "address": "D8GH73rNjudgi6bS2krrXWEsU9KShedLXp", - "preferred": true - }, - { - "network": "Ethereum", - "currency_code": "ETH", - "address": "0x7ab4091e00363654bf84B34151225742cd92FCE5" - }, - { - "network": "Litecoin", - "currency_code": "LTC", - "address": "LbJi8EuoDcwaZvykcKmcrM74jpjde23qJ2" - }, - { - "network": "Monero", - "currency_code": "XMR", - "address": "46YwWDbZD6jVptuk5mLHsuAmh1BnUMSjSNYacozQQEraWSQ93nb2yYVRHoMR6PmFYWEHsLHg9tr1cH5M8Rtn7YaaGQPCjSh" - } - ], - "links": [ - { - "name": "Open Collective", - "url": "https://opencollective.com/revanced", - "preferred": true - }, - { - "name": "GitHub Sponsors", - "url": "https://github.com/sponsors/ReVanced" - } - ] - } -}