diff --git a/src/main/kotlin/app/revanced/api/configuration/Extensions.kt b/src/main/kotlin/app/revanced/api/configuration/Extensions.kt index 4d387216..7a3664c7 100644 --- a/src/main/kotlin/app/revanced/api/configuration/Extensions.kt +++ b/src/main/kotlin/app/revanced/api/configuration/Extensions.kt @@ -1,5 +1,6 @@ package app.revanced.api.configuration +import io.bkbn.kompendium.core.metadata.MethodInfo import io.bkbn.kompendium.core.plugin.NotarizedRoute import io.ktor.http.* import io.ktor.http.content.* @@ -40,3 +41,11 @@ internal fun Route.staticFiles( extensions("json") }, ) = staticFiles(remotePath, dir.toFile(), null, block) + +internal fun MethodInfo.Builder<*>.canRespondUnauthorized() { + canRespond { + responseCode(HttpStatusCode.Unauthorized) + description("Unauthorized") + responseType() + } +} diff --git a/src/main/kotlin/app/revanced/api/configuration/routes/Announcements.kt b/src/main/kotlin/app/revanced/api/configuration/routes/Announcements.kt index 938d5565..adf8216e 100644 --- a/src/main/kotlin/app/revanced/api/configuration/routes/Announcements.kt +++ b/src/main/kotlin/app/revanced/api/configuration/routes/Announcements.kt @@ -1,5 +1,6 @@ package app.revanced.api.configuration.routes +import app.revanced.api.configuration.canRespondUnauthorized import app.revanced.api.configuration.installCache import app.revanced.api.configuration.installNotarizedRoute import app.revanced.api.configuration.respondOrNotFound @@ -8,10 +9,7 @@ import app.revanced.api.configuration.schema.APIAnnouncementArchivedAt import app.revanced.api.configuration.schema.APIResponseAnnouncement import app.revanced.api.configuration.schema.APIResponseAnnouncementId import app.revanced.api.configuration.services.AnnouncementService -import io.bkbn.kompendium.core.metadata.DeleteInfo -import io.bkbn.kompendium.core.metadata.GetInfo -import io.bkbn.kompendium.core.metadata.PatchInfo -import io.bkbn.kompendium.core.metadata.PostInfo +import io.bkbn.kompendium.core.metadata.* import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.oas.payload.Parameter import io.ktor.http.* @@ -138,9 +136,19 @@ internal fun Route.announcementsRoute() = route("announcements") { } } +private val authHeaderParameter = Parameter( + name = "Authorization", + `in` = Parameter.Location.header, + schema = TypeDefinition.STRING, + required = true, + examples = mapOf("Bearer authentication" to Parameter.Example("Bearer abc123")), +) + private fun Route.installAnnouncementRouteDocumentation() = installNotarizedRoute { tags = setOf("Announcements") + parameters = listOf(authHeaderParameter) + post = PostInfo.builder { description("Create a new announcement") summary("Create announcement") @@ -153,6 +161,7 @@ private fun Route.installAnnouncementRouteDocumentation() = installNotarizedRout responseCode(HttpStatusCode.OK) responseType() } + canRespondUnauthorized() } } @@ -239,6 +248,7 @@ private fun Route.installAnnouncementArchiveRouteDocumentation() = installNotari description = "The date and time the announcement to be archived", required = false, ), + authHeaderParameter, ) post = PostInfo.builder { @@ -249,6 +259,7 @@ private fun Route.installAnnouncementArchiveRouteDocumentation() = installNotari responseCode(HttpStatusCode.OK) responseType() } + canRespondUnauthorized() } } @@ -263,6 +274,7 @@ private fun Route.installAnnouncementUnarchiveRouteDocumentation() = installNota description = "The id of the announcement to unarchive", required = true, ), + authHeaderParameter, ) post = PostInfo.builder { @@ -273,6 +285,7 @@ private fun Route.installAnnouncementUnarchiveRouteDocumentation() = installNota responseCode(HttpStatusCode.OK) responseType() } + canRespondUnauthorized() } } @@ -287,6 +300,7 @@ private fun Route.installAnnouncementIdRouteDocumentation() = installNotarizedRo description = "The id of the announcement to update", required = true, ), + authHeaderParameter, ) patch = PatchInfo.builder { @@ -301,6 +315,7 @@ private fun Route.installAnnouncementIdRouteDocumentation() = installNotarizedRo responseCode(HttpStatusCode.OK) responseType() } + canRespondUnauthorized() } delete = DeleteInfo.builder { @@ -311,6 +326,7 @@ private fun Route.installAnnouncementIdRouteDocumentation() = installNotarizedRo responseCode(HttpStatusCode.OK) responseType() } + canRespondUnauthorized() } } 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 d041461f..b88f68eb 100644 --- a/src/main/kotlin/app/revanced/api/configuration/routes/ApiRoute.kt +++ b/src/main/kotlin/app/revanced/api/configuration/routes/ApiRoute.kt @@ -4,6 +4,7 @@ import app.revanced.api.configuration.* import app.revanced.api.configuration.installCache import app.revanced.api.configuration.installNoCache import app.revanced.api.configuration.installNotarizedRoute +import app.revanced.api.configuration.repository.ConfigurationRepository import app.revanced.api.configuration.respondOrNotFound import app.revanced.api.configuration.schema.APIAbout import app.revanced.api.configuration.schema.APIContributable @@ -12,12 +13,15 @@ import app.revanced.api.configuration.schema.APIRateLimit import app.revanced.api.configuration.services.ApiService import app.revanced.api.configuration.services.AuthService import io.bkbn.kompendium.core.metadata.* +import io.bkbn.kompendium.json.schema.definition.TypeDefinition +import io.bkbn.kompendium.oas.payload.Parameter import io.ktor.http.* import io.ktor.server.application.* 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 @@ -165,16 +169,38 @@ private fun Route.installContributorsRouteDocumentation() = installNotarizedRout } private fun Route.installTokenRouteDocumentation() = installNotarizedRoute { + val configuration = koinGet() + tags = setOf("API") get = GetInfo.builder { description("Get a new authorization token") summary("Get authorization token") + parameters( + Parameter( + name = "Authorization", + `in` = Parameter.Location.header, + schema = TypeDefinition.STRING, + required = true, + examples = mapOf( + "Digest access authentication" to Parameter.Example( + value = "Digest " + + "username=\"ReVanced\", " + + "realm=\"ReVanced\", " + + "nonce=\"abc123\", " + + "uri=\"/v${configuration.apiVersion}/token\", " + + "algorithm=SHA-256, " + + "response=\"yxz456\"", + ), + ), // Provide an example for the header + ), + ) response { description("The authorization token") mediaTypes("application/json") responseCode(HttpStatusCode.OK) responseType() } + canRespondUnauthorized() } }