From 70ba6ae4f852e509b07f37eb43142d5a6ab4ce7f Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 22 Sep 2023 23:42:22 +0900 Subject: [PATCH 1/5] =?UTF-8?q?refactor:=20Ktor=E4=BD=BF=E7=94=A8=E7=AE=87?= =?UTF-8?q?=E6=89=80=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/dev/usbharu/hideout/Application.kt | 172 ------------------ .../usbharu/hideout/plugins/ActivityPub.kt | 8 - .../usbharu/hideout/plugins/Compression.kt | 20 -- .../dev/usbharu/hideout/plugins/HTTP.kt | 24 --- .../dev/usbharu/hideout/plugins/Koin.kt | 14 -- .../dev/usbharu/hideout/plugins/Monitoring.kt | 12 -- .../dev/usbharu/hideout/plugins/Routing.kt | 52 ------ .../dev/usbharu/hideout/plugins/Security.kt | 51 ------ .../usbharu/hideout/plugins/Serialization.kt | 21 --- .../usbharu/hideout/plugins/StaticRouting.kt | 22 --- .../usbharu/hideout/plugins/StatusPages.kt | 24 --- .../hideout/routing/RegisterRouting.kt | 44 ----- .../routing/activitypub/InboxRouting.kt | 77 -------- .../routing/activitypub/OutboxRouting.kt | 26 --- .../routing/activitypub/UserRouting.kt | 65 ------- .../hideout/routing/api/internal/v1/Auth.kt | 32 ---- .../hideout/routing/api/internal/v1/Posts.kt | 102 ----------- .../hideout/routing/api/internal/v1/Users.kt | 107 ----------- .../routing/api/mastodon/v1/Statuses.kt | 18 -- .../routing/wellknown/WebfingerRouting.kt | 45 ----- 20 files changed, 936 deletions(-) delete mode 100644 src/main/kotlin/dev/usbharu/hideout/Application.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/Compression.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/HTTP.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/Koin.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/Monitoring.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/Routing.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/Security.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/Serialization.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/StaticRouting.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/plugins/StatusPages.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/RegisterRouting.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/activitypub/InboxRouting.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/activitypub/OutboxRouting.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/activitypub/UserRouting.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Auth.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Posts.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Users.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/api/mastodon/v1/Statuses.kt delete mode 100644 src/main/kotlin/dev/usbharu/hideout/routing/wellknown/WebfingerRouting.kt diff --git a/src/main/kotlin/dev/usbharu/hideout/Application.kt b/src/main/kotlin/dev/usbharu/hideout/Application.kt deleted file mode 100644 index 5b1530a4..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/Application.kt +++ /dev/null @@ -1,172 +0,0 @@ -package dev.usbharu.hideout - -import com.auth0.jwk.JwkProvider -import com.auth0.jwk.JwkProviderBuilder -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import dev.usbharu.hideout.config.CharacterLimit -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.config.ConfigData -import dev.usbharu.hideout.domain.model.job.DeliverPostJob -import dev.usbharu.hideout.domain.model.job.DeliverReactionJob -import dev.usbharu.hideout.domain.model.job.DeliverRemoveReactionJob -import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob -import dev.usbharu.hideout.plugins.* -import dev.usbharu.hideout.query.FollowerQueryService -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.routing.register -import dev.usbharu.hideout.service.ap.APService -import dev.usbharu.hideout.service.ap.APUserService -import dev.usbharu.hideout.service.api.PostApiService -import dev.usbharu.hideout.service.api.UserApiService -import dev.usbharu.hideout.service.api.UserAuthApiService -import dev.usbharu.hideout.service.api.WebFingerApiService -import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService -import dev.usbharu.hideout.service.core.* -import dev.usbharu.hideout.service.job.JobQueueParentService -import dev.usbharu.hideout.service.job.KJobJobQueueParentService -import dev.usbharu.hideout.service.user.UserService -import dev.usbharu.kjob.exposed.ExposedKJob -import io.ktor.client.* -import io.ktor.client.engine.cio.* -import io.ktor.client.plugins.logging.* -import io.ktor.server.application.* -import kjob.core.kjob -import kotlinx.coroutines.runBlocking -import org.jetbrains.exposed.sql.Database -import org.koin.ksp.generated.module -import org.koin.ktor.ext.inject -import java.util.concurrent.TimeUnit - -@Deprecated("Ktor is deprecated") -fun main(args: Array): Unit = io.ktor.server.cio.EngineMain.main(args) - -val Application.property: Application.(propertyName: String) -> String - get() = { - environment.config.property(it).getString() - } - -val Application.propertyOrNull: Application.(propertyName: String) -> String? - get() = { - environment.config.propertyOrNull(it)?.getString() - } - -// application.conf references the main function. This annotation prevents the IDE from marking it as unused. -@Deprecated("Ktor is deprecated") -@Suppress("unused", "LongMethod") -fun Application.parent() { - Config.configData = ConfigData( - url = property("hideout.url"), - objectMapper = jacksonObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) - .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false), - characterLimit = CharacterLimit( - general = CharacterLimit.General.of( - url = propertyOrNull("hideout.character-limit.general.url")?.toIntOrNull(), - domain = propertyOrNull("hideout.character-limit.general.domain")?.toIntOrNull(), - publicKey = propertyOrNull("hideout.character-limit.general.publicKey")?.toIntOrNull(), - privateKey = propertyOrNull("hideout.character-limit.general.privateKey")?.toIntOrNull() - ) - ) - ) - - val module = org.koin.dsl.module { - single { - Database.connect( - url = property("hideout.database.url"), - driver = property("hideout.database.driver"), - user = property("hideout.database.username"), - password = property("hideout.database.password") - ) - } - single { - val kJobJobQueueService = KJobJobQueueParentService(get()) - kJobJobQueueService.init(emptyList()) - kJobJobQueueService - } - single { - HttpClient(CIO).config { - install(Logging) { - logger = Logger.DEFAULT - level = LogLevel.INFO - } - install(httpSignaturePlugin) { - keyMap = KtorKeyMap(get(), get()) - } - expectSuccess = true - } - } - single { TwitterSnowflakeIdGenerateService } - single { - JwkProviderBuilder(Config.configData.url).cached( - 10, - 24, - TimeUnit.HOURS - ) - .rateLimited(10, 1, TimeUnit.MINUTES).build() - } - } - configureKoin(module, HideoutModule().module) - configureStatusPages() - runBlocking { - inject().value.init() - } - configureCompression() - configureHTTP() - configureStaticRouting() - configureMonitoring() - configureSerialization() - register(inject().value) - configureSecurity( - - inject().value, - inject().value - ) - configureRouting( - httpSignatureVerifyService = inject().value, - apService = inject().value, - userService = inject().value, - apUserService = inject().value, - postService = inject().value, - userApiService = inject().value, - userQueryService = inject().value, - followerQueryService = inject().value, - userAuthApiService = inject().value, - webFingerApiService = inject().value, - transaction = inject().value - ) -} - -@Deprecated("Ktor is deprecated") -@Suppress("unused") -fun Application.worker() { - val kJob = kjob(ExposedKJob) { - connectionDatabase = inject().value - }.start() - - val apService = inject().value - - kJob.register(ReceiveFollowJob) { - execute { - apService.processActivity(this, it) - } - } - kJob.register(DeliverPostJob) { - execute { - apService.processActivity(this, it) - } - } - - kJob.register(DeliverReactionJob) { - execute { - apService.processActivity(this, it) - } - } - - kJob.register(DeliverRemoveReactionJob) { - execute { - apService.processActivity(this, it) - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt index f501fa98..a3e61051 100644 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt +++ b/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt @@ -11,8 +11,6 @@ import io.ktor.client.plugins.api.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.response.* import kotlinx.coroutines.runBlocking import tech.barbero.http.message.signing.HttpMessage import tech.barbero.http.message.signing.HttpMessageSigner @@ -28,12 +26,6 @@ import java.text.SimpleDateFormat import java.util.* import javax.crypto.SecretKey -suspend fun ApplicationCall.respondAp(message: T, status: HttpStatusCode = HttpStatusCode.OK) { - message.context += "https://www.w3.org/ns/activitystreams" - val activityJson = Config.configData.objectMapper.writeValueAsString(message) - respondText(activityJson, ContentType.Application.Activity, status) -} - suspend fun HttpClient.postAp(urlString: String, username: String, jsonLd: JsonLd): HttpResponse { jsonLd.context += "https://www.w3.org/ns/activitystreams" return this.post(urlString) { diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/Compression.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/Compression.kt deleted file mode 100644 index d1387d28..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/Compression.kt +++ /dev/null @@ -1,20 +0,0 @@ -package dev.usbharu.hideout.plugins - -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.plugins.compression.* - -@Deprecated("Ktor is deprecated") -fun Application.configureCompression() { - install(Compression) { - gzip { - matchContentType(ContentType.Application.JavaScript) - priority = 1.0 - } - deflate { - matchContentType(ContentType.Application.JavaScript) - priority = 10.0 - minimumSize(1024) // condition - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/HTTP.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/HTTP.kt deleted file mode 100644 index 44f88bbd..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/HTTP.kt +++ /dev/null @@ -1,24 +0,0 @@ -package dev.usbharu.hideout.plugins - -import io.ktor.server.application.* -import io.ktor.server.plugins.defaultheaders.* -import io.ktor.server.plugins.forwardedheaders.* - -@Deprecated("Ktor is deprecated") -fun Application.configureHTTP() { -// install(CORS) { -// allowMethod(HttpMethod.Options) -// allowMethod(HttpMethod.Put) -// allowMethod(HttpMethod.Delete) -// allowMethod(HttpMethod.Patch) -// allowHeader(HttpHeaders.Authorization) -// allow -// allowHeader("MyCustomHeader") -// anyHost() // @TODO: Don't do this in production if possible. Try to limit it. -// } - install(DefaultHeaders) { - header("X-Engine", "Ktor") // will send this header with each response - } - install(ForwardedHeaders) // WARNING: for security, do not include this if not behind a reverse proxy - install(XForwardedHeaders) // WARNING: for security, do not include this if not behind a reverse proxy -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/Koin.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/Koin.kt deleted file mode 100644 index a7b1ed16..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/Koin.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.usbharu.hideout.plugins - -import io.ktor.server.application.* -import org.koin.core.module.Module -import org.koin.ktor.plugin.Koin -import org.koin.logger.slf4jLogger - -@Deprecated("Ktor is deprecated") -fun Application.configureKoin(vararg module: Module) { - install(Koin) { - slf4jLogger() - modules(*module) - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/Monitoring.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/Monitoring.kt deleted file mode 100644 index a2345312..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/Monitoring.kt +++ /dev/null @@ -1,12 +0,0 @@ -package dev.usbharu.hideout.plugins - -import io.ktor.server.application.* -import io.ktor.server.plugins.callloging.* -import org.slf4j.event.Level - -@Deprecated("Ktor is deprecated") -fun Application.configureMonitoring() { - install(CallLogging) { - level = Level.INFO - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/Routing.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/Routing.kt deleted file mode 100644 index 7a11e3be..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/Routing.kt +++ /dev/null @@ -1,52 +0,0 @@ -package dev.usbharu.hideout.plugins - -import dev.usbharu.hideout.query.FollowerQueryService -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.routing.activitypub.inbox -import dev.usbharu.hideout.routing.activitypub.outbox -import dev.usbharu.hideout.routing.activitypub.usersAP -import dev.usbharu.hideout.routing.api.internal.v1.auth -import dev.usbharu.hideout.routing.api.internal.v1.posts -import dev.usbharu.hideout.routing.api.internal.v1.users -import dev.usbharu.hideout.routing.wellknown.webfinger -import dev.usbharu.hideout.service.ap.APService -import dev.usbharu.hideout.service.ap.APUserService -import dev.usbharu.hideout.service.api.PostApiService -import dev.usbharu.hideout.service.api.UserApiService -import dev.usbharu.hideout.service.api.UserAuthApiService -import dev.usbharu.hideout.service.api.WebFingerApiService -import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService -import dev.usbharu.hideout.service.core.Transaction -import dev.usbharu.hideout.service.user.UserService -import io.ktor.server.application.* -import io.ktor.server.plugins.autohead.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -@Suppress("LongParameterList") -fun Application.configureRouting( - httpSignatureVerifyService: HttpSignatureVerifyService, - apService: APService, - userService: UserService, - apUserService: APUserService, - postService: PostApiService, - userApiService: UserApiService, - userQueryService: UserQueryService, - followerQueryService: FollowerQueryService, - userAuthApiService: UserAuthApiService, - webFingerApiService: WebFingerApiService, - transaction: Transaction -) { - install(AutoHeadResponse) - routing { - inbox(httpSignatureVerifyService, apService) - outbox() - usersAP(apUserService, userQueryService, followerQueryService, transaction) - webfinger(webFingerApiService) - route("/api/internal/v1") { - posts(postService) - users(userService, userApiService) - auth(userAuthApiService) - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/Security.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/Security.kt deleted file mode 100644 index 104c5844..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/Security.kt +++ /dev/null @@ -1,51 +0,0 @@ -package dev.usbharu.hideout.plugins - -import com.auth0.jwk.JwkProvider -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.service.core.MetaService -import dev.usbharu.hideout.util.JsonWebKeyUtil -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.auth.jwt.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -const val TOKEN_AUTH = "jwt-auth" - -@Deprecated("Ktor is deprecated") -@Suppress("MagicNumber") -fun Application.configureSecurity( - jwkProvider: JwkProvider, - metaService: MetaService -) { - val issuer = Config.configData.url - install(Authentication) { - jwt(TOKEN_AUTH) { - verifier(jwkProvider, issuer) { - acceptLeeway(3) - } - validate { jwtCredential -> - val uid = jwtCredential.payload.getClaim("uid") - if (uid.isMissing) { - return@validate null - } - if (uid.asLong() == null) { - return@validate null - } - return@validate JWTPrincipal(jwtCredential.payload) - } - } - } - - routing { - get("/.well-known/jwks.json") { - //language=JSON - val jwt = metaService.getJwtMeta() - call.respondText( - contentType = ContentType.Application.Json, - text = JsonWebKeyUtil.publicKeyToJwk(jwt.publicKey, jwt.kid.toString()) - ) - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/Serialization.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/Serialization.kt deleted file mode 100644 index 1e81e2e7..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/Serialization.kt +++ /dev/null @@ -1,21 +0,0 @@ -package dev.usbharu.hideout.plugins - -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.annotation.JsonSetter -import com.fasterxml.jackson.annotation.Nulls -import com.fasterxml.jackson.databind.DeserializationFeature -import io.ktor.serialization.jackson.* -import io.ktor.server.application.* -import io.ktor.server.plugins.contentnegotiation.* - -@Deprecated("Ktor is deprecated") -fun Application.configureSerialization() { - install(ContentNegotiation) { - jackson { - enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) - setSerializationInclusion(JsonInclude.Include.NON_EMPTY) - configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - configOverride(List::class.java).setSetterInfo(JsonSetter.Value.forContentNulls(Nulls.AS_EMPTY)) - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/StaticRouting.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/StaticRouting.kt deleted file mode 100644 index c4cc37d6..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/StaticRouting.kt +++ /dev/null @@ -1,22 +0,0 @@ -package dev.usbharu.hideout.plugins - -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.http.content.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -fun Application.configureStaticRouting() { - routing { - get("/") { - call.respondText( - String.javaClass.classLoader.getResourceAsStream("static/index.html").readAllBytes().decodeToString(), - contentType = ContentType.Text.Html - ) - } - static("/") { - resources("static") - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/StatusPages.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/StatusPages.kt deleted file mode 100644 index 9a9ea5ac..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/StatusPages.kt +++ /dev/null @@ -1,24 +0,0 @@ -package dev.usbharu.hideout.plugins - -import dev.usbharu.hideout.exception.InvalidUsernameOrPasswordException -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.plugins.statuspages.* -import io.ktor.server.response.* - -@Deprecated("Ktor is deprecated") -fun Application.configureStatusPages() { - install(StatusPages) { - exception { call, cause -> - call.respondText(text = "400: $cause", status = HttpStatusCode.BadRequest) - call.application.log.warn("Bad Request", cause) - } - exception { call, _ -> - call.respond(HttpStatusCode.Unauthorized) - } - exception { call, cause -> - call.respondText(text = "500: ${cause.stackTraceToString()}", status = HttpStatusCode.InternalServerError) - call.application.log.error("Internal Server Error", cause) - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/RegisterRouting.kt b/src/main/kotlin/dev/usbharu/hideout/routing/RegisterRouting.kt deleted file mode 100644 index 232ee918..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/RegisterRouting.kt +++ /dev/null @@ -1,44 +0,0 @@ -package dev.usbharu.hideout.routing - -import dev.usbharu.hideout.service.api.UserApiService -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -fun Application.register(userApiService: UserApiService) { - routing { - get("/register") { - val principal = call.principal() - if (principal != null) { - call.respondRedirect("/users/${principal.name}") - } - call.respondText(ContentType.Text.Html) { - //language=HTML - """ - - - - -
- - - -
- - - """.trimIndent() - } - } - post("/register") { - val parameters = call.receiveParameters() - val password = parameters["password"] ?: return@post call.respondRedirect("/register") - val username = parameters["username"] ?: return@post call.respondRedirect("/register") - userApiService.createUser(username, password) - call.respondRedirect("/users/$username") - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/InboxRouting.kt b/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/InboxRouting.kt deleted file mode 100644 index e1204f39..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/InboxRouting.kt +++ /dev/null @@ -1,77 +0,0 @@ -package dev.usbharu.hideout.routing.activitypub - -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.domain.model.ActivityPubObjectResponse -import dev.usbharu.hideout.domain.model.ActivityPubStringResponse -import dev.usbharu.hideout.exception.HttpSignatureVerifyException -import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -fun Routing.inbox( - httpSignatureVerifyService: HttpSignatureVerifyService, - apService: dev.usbharu.hideout.service.ap.APService -) { - route("/inbox") { - get { - call.respond(HttpStatusCode.MethodNotAllowed) - } - post { - if (httpSignatureVerifyService.verify(call.request.headers).not()) { - throw HttpSignatureVerifyException() - } - val json = call.receiveText() - call.application.log.trace("Received: $json") - val activityTypes = apService.parseActivity(json) - call.application.log.debug("ActivityTypes: ${activityTypes.name}") - val response = apService.processActivity(json, activityTypes) - when (response) { - is ActivityPubObjectResponse -> call.respond( - response.httpStatusCode, - Config.configData.objectMapper.writeValueAsString( - response.message.apply { - context = - listOf("https://www.w3.org/ns/activitystreams") - } - ) - ) - - is ActivityPubStringResponse -> call.respond(response.httpStatusCode, response.message) - null -> call.respond(HttpStatusCode.NotImplemented) - } - } - } - route("/users/{name}/inbox") { - get { - call.respond(HttpStatusCode.MethodNotAllowed) - } - post { - if (httpSignatureVerifyService.verify(call.request.headers).not()) { - throw HttpSignatureVerifyException() - } - val json = call.receiveText() - call.application.log.trace("Received: $json") - val activityTypes = apService.parseActivity(json) - call.application.log.debug("ActivityTypes: ${activityTypes.name}") - val response = apService.processActivity(json, activityTypes) - when (response) { - is ActivityPubObjectResponse -> call.respond( - response.httpStatusCode, - Config.configData.objectMapper.writeValueAsString( - response.message.apply { - context = - listOf("https://www.w3.org/ns/activitystreams") - } - ) - ) - - is ActivityPubStringResponse -> call.respond(response.httpStatusCode, response.message) - null -> call.respond(HttpStatusCode.NotImplemented) - } - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/OutboxRouting.kt b/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/OutboxRouting.kt deleted file mode 100644 index 9f6c2689..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/OutboxRouting.kt +++ /dev/null @@ -1,26 +0,0 @@ -package dev.usbharu.hideout.routing.activitypub - -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -fun Routing.outbox() { - route("/outbox") { - get { - call.respond(HttpStatusCode.NotImplemented) - } - post { - call.respond(HttpStatusCode.NotImplemented) - } - } - route("/users/{name}/outbox") { - get { - call.respond(HttpStatusCode.NotImplemented) - } - post { - call.respond(HttpStatusCode.NotImplemented) - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/UserRouting.kt b/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/UserRouting.kt deleted file mode 100644 index 39d7a299..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/UserRouting.kt +++ /dev/null @@ -1,65 +0,0 @@ -package dev.usbharu.hideout.routing.activitypub - -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.exception.ParameterNotExistException -import dev.usbharu.hideout.plugins.respondAp -import dev.usbharu.hideout.query.FollowerQueryService -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.service.ap.APUserService -import dev.usbharu.hideout.service.core.Transaction -import dev.usbharu.hideout.util.HttpUtil.Activity -import dev.usbharu.hideout.util.HttpUtil.JsonLd -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -fun Routing.usersAP( - apUserService: APUserService, - userQueryService: UserQueryService, - followerQueryService: FollowerQueryService, - transaction: Transaction -) { - route("/users/{name}") { - createChild(ContentTypeRouteSelector(ContentType.Application.Activity, ContentType.Application.JsonLd)).handle { - call.application.log.debug("Signature: ${call.request.header("Signature")}") - call.application.log.debug("Authorization: ${call.request.header("Authorization")}") - val name = - call.parameters["name"] ?: throw ParameterNotExistException("Parameter(name='name') does not exist.") - val person = apUserService.getPersonByName(name) - return@handle call.respondAp(person, HttpStatusCode.OK) - } - get { - // TODO: 暫定処置なので治す - transaction.transaction { - val userEntity = userQueryService.findByNameAndDomain( - call.parameters["name"] - ?: throw ParameterNotExistException("Parameter(name='name') does not exist."), - Config.configData.domain - ) - val personByName = apUserService.getPersonByName(userEntity.name) - call.respondText( - userEntity.toString() + "\n" + followerQueryService.findFollowersById(userEntity.id) + - "\n" + Config.configData.objectMapper.writeValueAsString( - personByName - ) - ) - } - } - } -} - -@Deprecated("Ktor is deprecated") -class ContentTypeRouteSelector(private vararg val contentType: ContentType) : RouteSelector() { - override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation { - context.call.application.log.debug("Accept: ${context.call.request.accept()}") - val requestContentType = context.call.request.accept() ?: return RouteSelectorEvaluation.FailedParameter - return if (requestContentType.split(",").any { contentType.any { contentType -> contentType.match(it) } }) { - RouteSelectorEvaluation.Constant - } else { - RouteSelectorEvaluation.FailedParameter - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Auth.kt b/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Auth.kt deleted file mode 100644 index 4a70ab5b..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Auth.kt +++ /dev/null @@ -1,32 +0,0 @@ -package dev.usbharu.hideout.routing.api.internal.v1 - -import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken -import dev.usbharu.hideout.domain.model.hideout.form.UserLogin -import dev.usbharu.hideout.plugins.TOKEN_AUTH -import dev.usbharu.hideout.service.api.UserAuthApiService -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.auth.jwt.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -fun Route.auth(userAuthApiService: UserAuthApiService) { - post("/login") { - val loginUser = call.receive() - return@post call.respond(userAuthApiService.login(loginUser.username, loginUser.password)) - } - - post("/refresh-token") { - val refreshToken = call.receive() - return@post call.respond(userAuthApiService.refreshToken(refreshToken)) - } - authenticate(TOKEN_AUTH) { - get("/auth-check") { - val principal = call.principal() ?: throw IllegalStateException("no principal") - val username = principal.payload.getClaim("uid") - call.respondText("Hello $username") - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Posts.kt b/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Posts.kt deleted file mode 100644 index 3137bc6c..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Posts.kt +++ /dev/null @@ -1,102 +0,0 @@ -package dev.usbharu.hideout.routing.api.internal.v1 - -import dev.usbharu.hideout.domain.model.hideout.form.Post -import dev.usbharu.hideout.domain.model.hideout.form.Reaction -import dev.usbharu.hideout.exception.ParameterNotExistException -import dev.usbharu.hideout.plugins.TOKEN_AUTH -import dev.usbharu.hideout.service.api.PostApiService -import dev.usbharu.hideout.util.InstantParseUtil -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.auth.jwt.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -@Suppress("LongMethod") -fun Route.posts(postApiService: PostApiService) { - route("/posts") { - authenticate(TOKEN_AUTH) { - post { - val principal = call.principal() ?: throw IllegalStateException("no principal") - val userId = principal.payload.getClaim("uid").asLong() - - val receive = call.receive() - val create = postApiService.createPost(receive, userId) - call.response.header("Location", create.url) - call.respond(HttpStatusCode.OK) - } - route("/{id}/reactions") { - get { - val principal = call.principal() ?: throw IllegalStateException("no principal") - val userId = principal.payload.getClaim("uid").asLong() - val postId = ( - call.parameters["id"]?.toLong() - ?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.") - ) - call.respond(postApiService.getReactionByPostId(postId, userId)) - } - post { - val jwtPrincipal = call.principal() ?: throw IllegalStateException("no principal") - val userId = jwtPrincipal.payload.getClaim("uid").asLong() - val postId = call.parameters["id"]?.toLong() - ?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.") - val reaction = try { - call.receive() - } catch (_: ContentTransformationException) { - Reaction(null) - } - - postApiService.appendReaction(reaction.reaction ?: "❤", userId, postId) - call.respond(HttpStatusCode.NoContent) - } - delete { - val jwtPrincipal = call.principal() ?: throw IllegalStateException("no principal") - val userId = jwtPrincipal.payload.getClaim("uid").asLong() - val postId = call.parameters["id"]?.toLong() - ?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.") - postApiService.removeReaction(userId, postId) - call.respond(HttpStatusCode.NoContent) - } - } - } - authenticate(TOKEN_AUTH, optional = true) { - get { - val userId = call.principal()?.payload?.getClaim("uid")?.asLong() - val since = InstantParseUtil.parse(call.request.queryParameters["since"]) - val until = InstantParseUtil.parse(call.request.queryParameters["until"]) - val minId = call.request.queryParameters["minId"]?.toLong() - val maxId = call.request.queryParameters["maxId"]?.toLong() - val limit = call.request.queryParameters["limit"]?.toInt() - call.respond(HttpStatusCode.OK, postApiService.getAll(since, until, minId, maxId, limit, userId)) - } - get("/{id}") { - val userId = call.principal()?.payload?.getClaim("uid")?.asLong() - val id = call.parameters["id"]?.toLong() - ?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.") - val post = postApiService.getById(id, userId) - call.respond(post) - } - } - } - route("/users/{name}/posts") { - authenticate(TOKEN_AUTH, optional = true) { - get { - val userId = call.principal()?.payload?.getClaim("uid")?.asLong() - val targetUserName = call.parameters["name"] - ?: throw ParameterNotExistException("Parameter(name='userName@domain') does not exist.") - val posts = postApiService.getByUser(targetUserName, userId = userId) - call.respond(posts) - } - get("/{id}") { - val userId = call.principal()?.payload?.getClaim("uid")?.asLong() - val id = call.parameters["id"]?.toLong() - ?: throw ParameterNotExistException("Parameter(name='postsId' does not exist.") - val post = postApiService.getById(id, userId) - call.respond(post) - } - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Users.kt b/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Users.kt deleted file mode 100644 index 96f4f198..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/api/internal/v1/Users.kt +++ /dev/null @@ -1,107 +0,0 @@ -package dev.usbharu.hideout.routing.api.internal.v1 - -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto -import dev.usbharu.hideout.domain.model.hideout.form.UserCreate -import dev.usbharu.hideout.exception.ParameterNotExistException -import dev.usbharu.hideout.plugins.TOKEN_AUTH -import dev.usbharu.hideout.service.api.UserApiService -import dev.usbharu.hideout.service.user.UserService -import dev.usbharu.hideout.util.AcctUtil -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.auth.jwt.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -@Suppress("LongMethod", "CognitiveComplexMethod") -fun Route.users(userService: UserService, userApiService: UserApiService) { - route("/users") { - get { - call.respond(userApiService.findAll()) - } - post { - val userCreate = call.receive() - if (userService.usernameAlreadyUse(userCreate.username)) { - return@post call.respond(HttpStatusCode.BadRequest) - } - val user = userService.createLocalUser( - UserCreateDto( - userCreate.username, - userCreate.username, - "", - userCreate.password - ) - ) - call.response.header("Location", "${Config.configData.url}/api/internal/v1/users/${user.name}") - call.respond(HttpStatusCode.Created) - } - route("/{name}") { - authenticate(TOKEN_AUTH, optional = true) { - get { - val userParameter = ( - call.parameters["name"] - ?: throw ParameterNotExistException( - "Parameter(name='userName@domain') does not exist." - ) - ) - if (userParameter.toLongOrNull() != null) { - return@get call.respond(userApiService.findById(userParameter.toLong())) - } else { - val acct = AcctUtil.parse(userParameter) - return@get call.respond(userApiService.findByAcct(acct)) - } - } - } - - route("/followers") { - get { - val userParameter = call.parameters["name"] - ?: throw ParameterNotExistException("Parameter(name='userName@domain') does not exist.") - if (userParameter.toLongOrNull() != null) { - return@get call.respond(userApiService.findFollowers(userParameter.toLong())) - } - val acct = AcctUtil.parse(userParameter) - return@get call.respond(userApiService.findFollowersByAcct(acct)) - } - authenticate(TOKEN_AUTH) { - post { - val userId = call.principal()?.payload?.getClaim("uid")?.asLong() - ?: throw IllegalStateException("no principal") - val userParameter = call.parameters["name"] - ?: throw ParameterNotExistException("Parameter(name='userName@domain') does not exist.") - if (if (userParameter.toLongOrNull() != null) { - userApiService.follow(userParameter.toLong(), userId) - } else { - val parse = AcctUtil.parse(userParameter) - userApiService.follow(parse, userId) - } - ) { - call.respond(HttpStatusCode.OK) - } else { - call.respond(HttpStatusCode.Accepted) - } - } - } - } - route("/following") { - get { - val userParameter = ( - call.parameters["name"] - ?: throw ParameterNotExistException( - "Parameter(name='userName@domain') does not exist." - ) - ) - if (userParameter.toLongOrNull() != null) { - return@get call.respond(userApiService.findFollowings(userParameter.toLong())) - } - val acct = AcctUtil.parse(userParameter) - return@get call.respond(userApiService.findFollowingsByAcct(acct)) - } - } - } - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/api/mastodon/v1/Statuses.kt b/src/main/kotlin/dev/usbharu/hideout/routing/api/mastodon/v1/Statuses.kt deleted file mode 100644 index ba757257..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/api/mastodon/v1/Statuses.kt +++ /dev/null @@ -1,18 +0,0 @@ -package dev.usbharu.hideout.routing.api.mastodon.v1 - -// @Suppress("UnusedPrivateMember") -// fun Route.statuses(postService: IPostService) { -// // route("/statuses") { -// // post { -// // val status: StatusForPost = call.receive() -// // val post = dev.usbharu.hideout.domain.model.hideout.form.Post( -// // userId = status.userId, -// // createdAt = System.currentTimeMillis(), -// // text = status.status, -// // visibility = 1 -// // ) -// // postService.create(post) -// // call.respond(status) -// // } -// // } -// } diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/wellknown/WebfingerRouting.kt b/src/main/kotlin/dev/usbharu/hideout/routing/wellknown/WebfingerRouting.kt deleted file mode 100644 index efa782c9..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/routing/wellknown/WebfingerRouting.kt +++ /dev/null @@ -1,45 +0,0 @@ -package dev.usbharu.hideout.routing.wellknown - -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.domain.model.wellknown.WebFinger -import dev.usbharu.hideout.exception.IllegalParameterException -import dev.usbharu.hideout.exception.ParameterNotExistException -import dev.usbharu.hideout.service.api.WebFingerApiService -import dev.usbharu.hideout.util.HttpUtil.Activity -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -@Deprecated("Ktor is deprecated") -fun Routing.webfinger(webFingerApiService: WebFingerApiService) { - route("/.well-known/webfinger") { - get { - val acct = call.request.queryParameters["resource"]?.decodeURLPart() - ?: throw ParameterNotExistException("Parameter(name='resource') does not exist.") - - if (acct.startsWith("acct:").not()) { - throw IllegalParameterException("Parameter(name='resource') is not start with 'acct:'.") - } - - val accountName = acct.substringBeforeLast("@") - .substringAfter("acct:") - .trimStart('@') - - val userEntity = webFingerApiService.findByNameAndDomain(accountName, Config.configData.domain) - - val webFinger = WebFinger( - subject = acct, - links = listOf( - WebFinger.Link( - rel = "self", - type = ContentType.Application.Activity.toString(), - href = "${Config.configData.url}/users/${userEntity.name}" - ) - ) - ) - - return@get call.respond(webFinger) - } - } -} From 89963c489e86ae317de123ac3136cecc2c87dae0 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 22 Sep 2023 23:49:45 +0900 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20Ktor=E3=81=AE=E4=BE=9D=E5=AD=98?= =?UTF-8?q?=E9=96=A2=E4=BF=82=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 104 +---------------------------------------------- 1 file changed, 1 insertion(+), 103 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1941b614..9bba1dd5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,3 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.openapitools.generator.gradle.plugin.tasks.GenerateTask @@ -11,7 +10,6 @@ val koin_version: String by project plugins { kotlin("jvm") version "1.8.21" - id("io.ktor.plugin") version "2.3.0" id("org.graalvm.buildtools.native") version "0.9.21" id("io.gitlab.arturbosch.detekt") version "1.23.1" id("com.google.devtools.ksp") version "1.8.21-1.0.11" @@ -27,12 +25,6 @@ apply { group = "dev.usbharu" version = "0.0.1" -application { - mainClass.set("dev.usbharu.hideout.SpringApplicationKt") - - val isDevelopment: Boolean = project.ext.has("development") - applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") -} tasks.withType { useJUnitPlatform() @@ -51,47 +43,11 @@ tasks.withType { mustRunAfter("openApiGenerateMastodonCompatibleApi") } -tasks.withType { - manifest { - attributes( - "Implementation-Version" to project.version.toString() - ) - } -} tasks.clean { delete += listOf("$rootDir/src/main/resources/static") } -//tasks.create("openApiGenerateServer", GenerateTask::class) { -// generatorName.set("kotlin-spring") -// inputSpec.set("$rootDir/src/main/resources/openapi/api.yaml") -// outputDir.set("$buildDir/generated/sources/openapi") -// apiPackage.set("dev.usbharu.hideout.controller.generated") -// modelPackage.set("dev.usbharu.hideout.domain.model.generated") -// configOptions.put("interfaceOnly", "true") -// configOptions.put("useSpringBoot3", "true") -// additionalProperties.put("useTags", "true") -// schemaMappings.putAll( -// mapOf( -// "ReactionResponse" to "dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse", -// "Account" to "dev.usbharu.hideout.domain.model.hideout.dto.Account", -// "JwtToken" to "dev.usbharu.hideout.domain.model.hideout.dto.JwtToken", -// "PostRequest" to "dev.usbharu.hideout.domain.model.hideout.form.Post", -// "PostResponse" to "dev.usbharu.hideout.domain.model.hideout.dto.PostResponse", -// "Reaction" to "dev.usbharu.hideout.domain.model.hideout.form.Reaction", -// "RefreshToken" to "dev.usbharu.hideout.domain.model.hideout.form.RefreshToken", -// "UserLogin" to "dev.usbharu.hideout.domain.model.hideout.form.UserLogin", -// "UserResponse" to "dev.usbharu.hideout.domain.model.hideout.dto.UserResponse", -// "UserCreate" to "dev.usbharu.hideout.domain.model.hideout.form.UserCreate", -// "Visibility" to "dev.usbharu.hideout.domain.model.hideout.entity.Visibility", -// ) -// ) -// -//// importMappings.putAll(mapOf("ReactionResponse" to "ReactionResponse")) -//// typeMappings.putAll(mapOf("ReactionResponse" to "ReactionResponse")) -//} - tasks.create("openApiGenerateMastodonCompatibleApi", GenerateTask::class) { generatorName.set("kotlin-spring") inputSpec.set("$rootDir/src/main/resources/openapi/mastodon.yaml") @@ -128,31 +84,18 @@ sourceSets.main { } dependencies { - implementation("io.ktor:ktor-server-core-jvm:$ktor_version") - implementation("io.ktor:ktor-server-auth:$ktor_version") - implementation("io.ktor:ktor-server-auth-jwt:$ktor_version") - implementation("io.ktor:ktor-server-sessions-jvm:$ktor_version") - implementation("io.ktor:ktor-server-auto-head-response-jvm:$ktor_version") - implementation("io.ktor:ktor-server-cors-jvm:$ktor_version") - implementation("io.ktor:ktor-server-default-headers-jvm:$ktor_version") - implementation("io.ktor:ktor-server-forwarded-header-jvm:$ktor_version") - implementation("io.ktor:ktor-server-call-logging-jvm:$ktor_version") - implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktor_version") implementation("io.ktor:ktor-serialization-jackson:$ktor_version") implementation("org.jetbrains.exposed:exposed-core:$exposed_version") implementation("org.jetbrains.exposed:exposed-jdbc:$exposed_version") implementation("com.h2database:h2:$h2_version") implementation("org.xerial:sqlite-jdbc:3.40.1.0") - implementation("io.ktor:ktor-server-websockets-jvm:$ktor_version") - implementation("io.ktor:ktor-server-cio-jvm:$ktor_version") - implementation("io.ktor:ktor-server-compression:$ktor_version") implementation("ch.qos.logback:logback-classic:$logback_version") implementation("io.insert-koin:koin-core:$koin_version") implementation("io.insert-koin:koin-ktor:$koin_version") implementation("io.insert-koin:koin-logger-slf4j:$koin_version") implementation("io.insert-koin:koin-annotations:1.2.0") - implementation("io.ktor:ktor-server-compression-jvm:2.3.0") + implementation("org.springframework.boot:spring-boot-starter-actuator") ksp("io.insert-koin:koin-ksp-compiler:1.2.0") @@ -178,10 +121,7 @@ dependencies { implementation("org.springframework.security:spring-security-oauth2-jose") implementation("io.ktor:ktor-client-logging-jvm:$ktor_version") - implementation("io.ktor:ktor-server-host-common-jvm:$ktor_version") - implementation("io.ktor:ktor-server-status-pages-jvm:$ktor_version") - testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4") @@ -197,53 +137,11 @@ dependencies { implementation("org.drewcarlson:kjob-core:0.6.0") - testImplementation("io.ktor:ktor-server-test-host-jvm:$ktor_version") - testImplementation("org.slf4j:slf4j-simple:2.0.7") detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.22.0") } -jib { - if (System.getProperty("os.name").toLowerCase().contains("windows")) { - dockerClient.environment = mapOf( - "DOCKER_HOST" to "localhost:2375" - ) - } -} - -ktor { - docker { - localImageName.set("hideout") - } -} - -graalvmNative { - binaries { - named("main") { - fallback.set(false) - verbose.set(true) - agent { - enabled.set(false) - } - - buildArgs.add("--initialize-at-build-time=io.ktor,kotlin,kotlinx") -// buildArgs.add("--trace-class-initialization=ch.qos.logback.classic.Logger") -// buildArgs.add("--trace-object-instantiation=ch.qos.logback.core.AsyncAppenderBase"+"$"+"Worker") -// buildArgs.add("--trace-object-instantiation=ch.qos.logback.classic.Logger") - buildArgs.add("--initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback") -// buildArgs.add("--trace-object-instantiation=kotlinx.coroutines.channels.ArrayChannel") - buildArgs.add("--initialize-at-build-time=kotlinx.coroutines.channels.ArrayChannel") - buildArgs.add("-H:+InstallExitHandlers") - buildArgs.add("-H:+ReportUnsupportedElementsAtRuntime") - buildArgs.add("-H:+ReportExceptionStackTraces") - - runtimeArgs.add("-config=$buildDir/resources/main/application-native.conf") - imageName.set("graal-server") - } - } -} - detekt { parallel = true config = files("detekt.yml") From 9b68f1941f3a2b088ccfa902cd3a76898df09190 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 22 Sep 2023 23:59:17 +0900 Subject: [PATCH 3/5] =?UTF-8?q?chore:=20=E5=BF=85=E8=A6=81=E3=81=AA?= =?UTF-8?q?=E4=BE=9D=E5=AD=98=E9=96=A2=E4=BF=82=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 9bba1dd5..8e9b80fd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -90,6 +90,9 @@ dependencies { implementation("com.h2database:h2:$h2_version") implementation("org.xerial:sqlite-jdbc:3.40.1.0") implementation("ch.qos.logback:logback-classic:$logback_version") + implementation("com.auth0:java-jwt:4.4.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") implementation("io.insert-koin:koin-core:$koin_version") implementation("io.insert-koin:koin-ktor:$koin_version") From b8e4d2dc3bd5ddb3322e2f0401f6e6f5b0621e73 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 22 Sep 2023 23:59:42 +0900 Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20Ktor=E3=81=AB=E9=96=A2=E9=80=A3?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E5=89=8A?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usbharu/hideout/plugins/SecurityKtTest.kt | 573 -------------- .../ContentTypeRouteSelectorTest.kt | 134 ---- .../routing/activitypub/InboxRoutingKtTest.kt | 104 --- .../routing/activitypub/UsersAPTest.kt | 202 ----- .../routing/api/internal/v1/PostsTest.kt | 734 ------------------ .../routing/api/internal/v1/UsersTest.kt | 692 ----------------- 6 files changed, 2439 deletions(-) delete mode 100644 src/test/kotlin/dev/usbharu/hideout/plugins/SecurityKtTest.kt delete mode 100644 src/test/kotlin/dev/usbharu/hideout/routing/activitypub/ContentTypeRouteSelectorTest.kt delete mode 100644 src/test/kotlin/dev/usbharu/hideout/routing/activitypub/InboxRoutingKtTest.kt delete mode 100644 src/test/kotlin/dev/usbharu/hideout/routing/activitypub/UsersAPTest.kt delete mode 100644 src/test/kotlin/dev/usbharu/hideout/routing/api/internal/v1/PostsTest.kt delete mode 100644 src/test/kotlin/dev/usbharu/hideout/routing/api/internal/v1/UsersTest.kt diff --git a/src/test/kotlin/dev/usbharu/hideout/plugins/SecurityKtTest.kt b/src/test/kotlin/dev/usbharu/hideout/plugins/SecurityKtTest.kt deleted file mode 100644 index a47cc283..00000000 --- a/src/test/kotlin/dev/usbharu/hideout/plugins/SecurityKtTest.kt +++ /dev/null @@ -1,573 +0,0 @@ -package dev.usbharu.hideout.plugins - -import com.auth0.jwk.Jwk -import com.auth0.jwk.JwkProvider -import com.auth0.jwt.JWT -import com.auth0.jwt.algorithms.Algorithm -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.config.ConfigData -import dev.usbharu.hideout.domain.model.hideout.dto.JwtToken -import dev.usbharu.hideout.domain.model.hideout.entity.Jwt -import dev.usbharu.hideout.domain.model.hideout.entity.User -import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken -import dev.usbharu.hideout.domain.model.hideout.form.UserLogin -import dev.usbharu.hideout.exception.InvalidRefreshTokenException -import dev.usbharu.hideout.exception.InvalidUsernameOrPasswordException -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.routing.api.internal.v1.auth -import dev.usbharu.hideout.service.api.UserAuthApiService -import dev.usbharu.hideout.service.auth.JwtService -import dev.usbharu.hideout.service.core.MetaService -import dev.usbharu.hideout.service.user.UserAuthService -import dev.usbharu.hideout.util.Base64Util -import dev.usbharu.hideout.util.JsonWebKeyUtil -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import io.ktor.server.config.* -import io.ktor.server.routing.* -import io.ktor.server.testing.* -import org.junit.jupiter.api.Test -import org.mockito.ArgumentMatchers.anyString -import org.mockito.kotlin.* -import java.security.KeyPairGenerator -import java.security.interfaces.RSAPrivateKey -import java.security.interfaces.RSAPublicKey -import java.time.Instant -import java.time.temporal.ChronoUnit -import java.util.* -import kotlin.test.assertEquals - -class SecurityKtTest { - @Test - fun `login ログイン出来るか`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper()) - val jwtToken = JwtToken("Token", "RefreshToken") - val userAuthService = mock { - onBlocking { login(eq("testUser"), eq("password")) } doReturn jwtToken - } - val metaService = mock() - val userQueryService = mock { - onBlocking { findByNameAndDomain(eq("testUser"), eq("example.com")) } doReturn User.of( - id = 1L, - name = "testUser", - domain = "example.com", - screenName = "test", - description = "", - password = "hashedPassword", - inbox = "https://example.com/inbox", - outbox = "https://example.com/outbox", - url = "https://example.com/profile", - publicKey = "", - privateKey = "", - createdAt = Instant.now() - ) - } - val jwkProvider = mock() - application { - configureSerialization() - configureSecurity(jwkProvider, metaService) - routing { - auth(userAuthService) - } - } - - client.post("/login") { - contentType(ContentType.Application.Json) - setBody(Config.configData.objectMapper.writeValueAsString(UserLogin("testUser", "password"))) - }.apply { - assertEquals(HttpStatusCode.OK, call.response.status) - assertEquals(jwtToken, Config.configData.objectMapper.readValue(call.response.bodyAsText())) - } - } - - @Test - fun `login 存在しないユーザーのログインに失敗する`() { - testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper()) - mock { - onBlocking { verifyAccount(anyString(), anyString()) }.doReturn(false) - } - val metaService = mock() - mock() - mock() - val jwkProvider = mock() - val userAuthApiService = mock { - onBlocking { login(anyString(), anyString()) } doThrow InvalidUsernameOrPasswordException() - } - application { - configureStatusPages() - configureSerialization() - configureSecurity(jwkProvider, metaService) - routing { - auth(userAuthApiService) - } - } - client.post("/login") { - contentType(ContentType.Application.Json) - setBody(Config.configData.objectMapper.writeValueAsString(UserLogin("InvalidTtestUser", "password"))) - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - } - - @Test - fun `login 不正なパスワードのログインに失敗する`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper()) - val metaService = mock() - val jwkProvider = mock() - val userAuthApiService = mock { - onBlocking { login(anyString(), eq("InvalidPassword")) } doThrow InvalidUsernameOrPasswordException() - } - application { - configureStatusPages() - configureSerialization() - configureSecurity(jwkProvider, metaService) - routing { - auth(userAuthApiService) - } - } - client.post("/login") { - contentType(ContentType.Application.Json) - setBody(Config.configData.objectMapper.writeValueAsString(UserLogin("TestUser", "InvalidPassword"))) - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `auth-check Authorizedヘッダーが無いと401が帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper()) - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - auth(mock()) - } - } - client.get("/auth-check").apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `auth-check Authorizedヘッダーの形式が間違っていると401が帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper()) - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - auth(mock()) - } - } - client.get("/auth-check") { - header("Authorization", "Digest dsfjjhogalkjdfmlhaog") - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `auth-check Authorizedヘッダーが空だと401が帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper()) - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - auth(mock()) - } - } - client.get("/auth-check") { - header("Authorization", "") - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `auth-check AuthorizedヘッダーがBeararで空だと401が帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper()) - - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - auth(mock()) - } - } - client.get("/auth-check") { - header("Authorization", "Bearer ") - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `auth-check 正当なJWTだとアクセスできる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(2048) - val keyPair = keyPairGenerator.generateKeyPair() - val rsaPublicKey = keyPair.public as RSAPublicKey - - Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper()) - - val now = Instant.now() - val kid = UUID.randomUUID() - val token = JWT.create() - .withAudience("${Config.configData.url}/users/test") - .withIssuer(Config.configData.url) - .withKeyId(kid.toString()) - .withClaim("uid", 123456L) - .withExpiresAt(now.plus(30, ChronoUnit.MINUTES)) - .sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey)) - val metaService = mock { - onBlocking { getJwtMeta() }.doReturn( - Jwt( - kid, - Base64Util.encode(keyPair.private.encoded), - Base64Util.encode(rsaPublicKey.encoded) - ) - ) - } - - val readValue = Config.configData.objectMapper.readerFor(Map::class.java) - .readValue?>( - JsonWebKeyUtil.publicKeyToJwk( - rsaPublicKey, - kid.toString() - ) - ) - val jwkProvider = mock { - onBlocking { get(anyString()) }.doReturn( - Jwk.fromValues( - (readValue["keys"] as List>)[0] - ) - ) - } - application { - configureSerialization() - configureSecurity(jwkProvider, metaService) - routing { - auth(mock()) - } - } - - client.get("/auth-check") { - header("Authorization", "Bearer $token") - }.apply { - assertEquals(HttpStatusCode.OK, call.response.status) - assertEquals("Hello 123456", call.response.bodyAsText()) - } - } - - @Test - fun `auth-check 期限切れのトークンではアクセスできない`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(2048) - val keyPair = keyPairGenerator.generateKeyPair() - val rsaPublicKey = keyPair.public as RSAPublicKey - - Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper()) - - val now = Instant.now() - val kid = UUID.randomUUID() - val token = JWT.create() - .withAudience("${Config.configData.url}/users/test") - .withIssuer(Config.configData.url) - .withKeyId(kid.toString()) - .withClaim("uid", 123345L) - .withExpiresAt(now.minus(30, ChronoUnit.MINUTES)) - .sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey)) - val metaService = mock { - onBlocking { getJwtMeta() }.doReturn( - Jwt( - kid, - Base64Util.encode(keyPair.private.encoded), - Base64Util.encode(rsaPublicKey.encoded) - ) - ) - } - - val readValue = Config.configData.objectMapper.readerFor(Map::class.java) - .readValue?>( - JsonWebKeyUtil.publicKeyToJwk( - rsaPublicKey, - kid.toString() - ) - ) - val jwkProvider = mock { - onBlocking { get(anyString()) }.doReturn( - Jwk.fromValues( - (readValue["keys"] as List>)[0] - ) - ) - } - application { - configureSerialization() - configureSecurity(jwkProvider, metaService) - routing { - auth(mock()) - } - } - client.get("/auth-check") { - header("Authorization", "Bearer $token") - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `auth-check issuerが間違っているとアクセスできない`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(2048) - val keyPair = keyPairGenerator.generateKeyPair() - val rsaPublicKey = keyPair.public as RSAPublicKey - - Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper()) - - val now = Instant.now() - val kid = UUID.randomUUID() - val token = JWT.create() - .withAudience("${Config.configData.url}/users/test") - .withIssuer("https://example.com") - .withKeyId(kid.toString()) - .withClaim("uid", 12345L) - .withExpiresAt(now.plus(30, ChronoUnit.MINUTES)) - .sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey)) - val metaService = mock { - onBlocking { getJwtMeta() }.doReturn( - Jwt( - kid, - Base64Util.encode(keyPair.private.encoded), - Base64Util.encode(rsaPublicKey.encoded) - ) - ) - } - - val readValue = Config.configData.objectMapper.readerFor(Map::class.java) - .readValue?>( - JsonWebKeyUtil.publicKeyToJwk( - rsaPublicKey, - kid.toString() - ) - ) - val jwkProvider = mock { - onBlocking { get(anyString()) }.doReturn( - Jwk.fromValues( - (readValue["keys"] as List>)[0] - ) - ) - } - application { - configureSerialization() - configureSecurity(jwkProvider, metaService) - routing { - auth(mock()) - } - } - client.get("/auth-check") { - header("Authorization", "Bearer $token") - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `auth-check usernameが空だと失敗する`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(2048) - val keyPair = keyPairGenerator.generateKeyPair() - val rsaPublicKey = keyPair.public as RSAPublicKey - - Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper()) - - val now = Instant.now() - val kid = UUID.randomUUID() - val token = JWT.create() - .withAudience("${Config.configData.url}/users/test") - .withIssuer(Config.configData.url) - .withKeyId(kid.toString()) - .withClaim("uid", null as Long?) - .withExpiresAt(now.plus(30, ChronoUnit.MINUTES)) - .sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey)) - val metaService = mock { - onBlocking { getJwtMeta() }.doReturn( - Jwt( - kid, - Base64Util.encode(keyPair.private.encoded), - Base64Util.encode(rsaPublicKey.encoded) - ) - ) - } - - val readValue = Config.configData.objectMapper.readerFor(Map::class.java) - .readValue?>( - JsonWebKeyUtil.publicKeyToJwk( - rsaPublicKey, - kid.toString() - ) - ) - val jwkProvider = mock { - onBlocking { get(anyString()) }.doReturn( - Jwk.fromValues( - (readValue["keys"] as List>)[0] - ) - ) - } - application { - configureSerialization() - configureSecurity(jwkProvider, metaService) - routing { - auth(mock()) - } - } - client.get("/auth-check") { - header("Authorization", "Bearer $token") - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `auth-check usernameが存在しないと失敗する`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(2048) - val keyPair = keyPairGenerator.generateKeyPair() - val rsaPublicKey = keyPair.public as RSAPublicKey - - Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper()) - - val now = Instant.now() - val kid = UUID.randomUUID() - val token = JWT.create() - .withAudience("${Config.configData.url}/users/test") - .withIssuer(Config.configData.url) - .withKeyId(kid.toString()) - .withExpiresAt(now.plus(30, ChronoUnit.MINUTES)) - .sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey)) - val metaService = mock { - onBlocking { getJwtMeta() }.doReturn( - Jwt( - kid, - Base64Util.encode(keyPair.private.encoded), - Base64Util.encode(rsaPublicKey.encoded) - ) - ) - } - - val readValue = Config.configData.objectMapper.readerFor(Map::class.java) - .readValue?>( - JsonWebKeyUtil.publicKeyToJwk( - rsaPublicKey, - kid.toString() - ) - ) - val jwkProvider = mock { - onBlocking { get(anyString()) }.doReturn( - Jwk.fromValues( - (readValue["keys"] as List>)[0] - ) - ) - } - application { - configureSerialization() - configureSecurity(jwkProvider, metaService) - routing { - auth(mock()) - } - } - client.get("/auth-check") { - header("Authorization", "Bearer $token") - }.apply { - assertEquals(HttpStatusCode.Unauthorized, call.response.status) - } - } - - @Test - fun `refresh-token リフレッシュトークンが正当だとトークンを発行する`() = testApplication { - Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper()) - environment { - config = ApplicationConfig("empty.conf") - } - val jwtService = mock { - onBlocking { refreshToken(any()) }.doReturn(JwtToken("token", "refreshToken2")) - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - auth(jwtService) - } - } - client.post("/refresh-token") { - header("Content-Type", "application/json") - setBody(Config.configData.objectMapper.writeValueAsString(RefreshToken("refreshToken"))) - }.apply { - assertEquals(HttpStatusCode.OK, call.response.status) - } - } - - @Test - fun `refresh-token リフレッシュトークンが不正だと失敗する`() = testApplication { - Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper()) - environment { - config = ApplicationConfig("empty.conf") - } - val jwtService = mock { - onBlocking { refreshToken(any()) } doThrow InvalidRefreshTokenException("Invalid Refresh Token") - } - application { - configureStatusPages() - configureSerialization() - configureSecurity(mock(), mock()) - routing { - auth(jwtService) - } - } - client.post("/refresh-token") { - header("Content-Type", "application/json") - setBody(Config.configData.objectMapper.writeValueAsString(RefreshToken("InvalidRefreshToken"))) - }.apply { - assertEquals(HttpStatusCode.BadRequest, call.response.status) - } - } -} diff --git a/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/ContentTypeRouteSelectorTest.kt b/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/ContentTypeRouteSelectorTest.kt deleted file mode 100644 index b10e2a07..00000000 --- a/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/ContentTypeRouteSelectorTest.kt +++ /dev/null @@ -1,134 +0,0 @@ -package dev.usbharu.hideout.routing.activitypub - -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.config.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import io.ktor.server.testing.* -import org.junit.jupiter.api.Test -import kotlin.test.assertEquals - -class ContentTypeRouteSelectorTest { - @Test - fun `Content-Typeが一つでマッチする`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - application { - routing { - route("/test") { - createChild(ContentTypeRouteSelector(ContentType.Application.Json)).handle { - call.respondText("OK") - } - get { - call.respondText("NG") - } - } - } - } - - client.get("/test") { - accept(ContentType.Text.Html) - }.apply { - assertEquals("NG", bodyAsText()) - } - client.get("/test") { - accept(ContentType.Application.Json) - }.apply { - assertEquals("OK", bodyAsText()) - } - } - - @Test - fun `Content-Typeが一つのとき違うとマッチしない`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - application { - routing { - route("/test") { - createChild(ContentTypeRouteSelector(ContentType.Application.Json)).handle { - call.respondText("OK") - } - get { - call.respondText("NG") - } - } - } - } - - client.get("/test") { - accept(ContentType.Text.Html) - }.apply { - assertEquals("NG", bodyAsText()) - } - } - - @Test - fun `Content-Typeがからのときマッチしない`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - application { - routing { - route("/test") { - createChild(ContentTypeRouteSelector()).handle { - call.respondText("OK") - } - get { - call.respondText("NG") - } - } - } - } - - client.get("/test") { - accept(ContentType.Text.Html) - }.apply { - assertEquals("NG", bodyAsText()) - } - - client.get("/test").apply { - assertEquals("NG", bodyAsText()) - } - } - - @Test - fun `Content-Typeが複数指定されていてマッチする`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - application { - routing { - route("/test") { - createChild(ContentTypeRouteSelector(ContentType.Application.Json, ContentType.Text.Html)).handle { - call.respondText("OK") - } - get { - call.respondText("NG") - } - } - } - } - - client.get("/test") { - accept(ContentType.Text.Html) - }.apply { - assertEquals("OK", bodyAsText()) - } - - client.get("/test") { - accept(ContentType.Application.Json) - }.apply { - assertEquals("OK", bodyAsText()) - } - client.get("/test") { - accept(ContentType.Application.Xml) - }.apply { - assertEquals("NG", bodyAsText()) - } - } -} diff --git a/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/InboxRoutingKtTest.kt b/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/InboxRoutingKtTest.kt deleted file mode 100644 index 75a2c335..00000000 --- a/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/InboxRoutingKtTest.kt +++ /dev/null @@ -1,104 +0,0 @@ -package dev.usbharu.hideout.routing.activitypub - -import dev.usbharu.hideout.exception.JsonParseException -import dev.usbharu.hideout.plugins.configureSerialization -import dev.usbharu.hideout.plugins.configureStatusPages -import dev.usbharu.hideout.service.ap.APService -import dev.usbharu.hideout.service.ap.APUserService -import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService -import dev.usbharu.hideout.service.user.UserService -import io.ktor.client.request.* -import io.ktor.http.* -import io.ktor.server.config.* -import io.ktor.server.routing.* -import io.ktor.server.testing.* -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.mockito.kotlin.any -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.doThrow -import org.mockito.kotlin.mock - -class InboxRoutingKtTest { - @Test - fun `sharedInboxにGETしたら405が帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - application { - configureSerialization() - routing { - inbox(mock(), mock()) - } - } - client.get("/inbox").let { - Assertions.assertEquals(HttpStatusCode.MethodNotAllowed, it.status) - } - } - - @Test - fun `sharedInboxに空のリクエストボディでPOSTしたら400が帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val httpSignatureVerifyService = mock { - on { verify(any()) } doReturn true - } - val apService = mock { - on { parseActivity(any()) } doThrow JsonParseException() - } - mock() - mock() - application { - configureStatusPages() - configureSerialization() - routing { - inbox(httpSignatureVerifyService, apService) - } - } - client.post("/inbox").let { - Assertions.assertEquals(HttpStatusCode.BadRequest, it.status) - } - } - - @Test - fun `ユーザのinboxにGETしたら405が帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - application { - configureSerialization() - routing { - inbox(mock(), mock()) - } - } - client.get("/users/test/inbox").let { - Assertions.assertEquals(HttpStatusCode.MethodNotAllowed, it.status) - } - } - - @Test - fun `ユーザーのinboxに空のリクエストボディでPOSTしたら400が帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val httpSignatureVerifyService = mock { - on { verify(any()) } doReturn true - } - val apService = mock { - on { parseActivity(any()) } doThrow JsonParseException() - } - mock() - mock() - application { - configureStatusPages() - configureSerialization() - routing { - inbox(httpSignatureVerifyService, apService) - } - } - client.post("/users/test/inbox").let { - Assertions.assertEquals(HttpStatusCode.BadRequest, it.status) - } - } -} diff --git a/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/UsersAPTest.kt b/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/UsersAPTest.kt deleted file mode 100644 index 81b780c8..00000000 --- a/src/test/kotlin/dev/usbharu/hideout/routing/activitypub/UsersAPTest.kt +++ /dev/null @@ -1,202 +0,0 @@ -package dev.usbharu.hideout.routing.activitypub - -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.annotation.JsonSetter -import com.fasterxml.jackson.annotation.Nulls -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.domain.model.ap.Image -import dev.usbharu.hideout.domain.model.ap.Key -import dev.usbharu.hideout.domain.model.ap.Person -import dev.usbharu.hideout.domain.model.hideout.entity.User -import dev.usbharu.hideout.plugins.configureSerialization -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.service.ap.APUserService -import dev.usbharu.hideout.util.HttpUtil.Activity -import dev.usbharu.hideout.util.HttpUtil.JsonLd -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import io.ktor.server.config.* -import io.ktor.server.routing.* -import io.ktor.server.testing.* -import org.junit.jupiter.api.Test -import org.mockito.ArgumentMatchers.anyString -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.eq -import org.mockito.kotlin.mock -import utils.TestTransaction -import java.time.Instant -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class UsersAPTest { - - @Test() - fun `ユーザのURLにAcceptヘッダーをActivityにしてアクセスしたときPersonが返ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val person = Person( - type = emptyList(), - name = "test", - id = "http://example.com/users/test", - preferredUsername = "test", - summary = "test user", - inbox = "http://example.com/users/test/inbox", - outbox = "http://example.com/users/test/outbox", - url = "http://example.com/users/test", - icon = Image( - type = emptyList(), - name = "http://example.com/users/test/icon.png", - mediaType = "image/png", - url = "http://example.com/users/test/icon.png" - ), - publicKey = Key( - type = emptyList(), - name = "Public Key", - id = "http://example.com/users/test#pubkey", - owner = "https://example.com/users/test", - publicKeyPem = "-----BEGIN PUBLIC KEY-----\n\n-----END PUBLIC KEY-----" - ) - ) - person.context = listOf("https://www.w3.org/ns/activitystreams") - - val apUserService = mock { - onBlocking { getPersonByName(anyString()) } doReturn person - } - - application { - configureSerialization() - routing { - usersAP(apUserService, mock(), mock(), TestTransaction) - } - } - client.get("/users/test") { - accept(ContentType.Application.Activity) - }.let { - val objectMapper = jacksonObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) - .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - objectMapper.configOverride(List::class.java).setSetterInfo( - JsonSetter.Value.forValueNulls( - Nulls.AS_EMPTY - ) - ) - val actual = it.bodyAsText() - val readValue = objectMapper.readValue(actual) - assertEquals(person, readValue) - } - } - - // @Disabled - @Test() - fun `ユーザのURLにAcceptヘッダーをActivityとJson-LDにしてアクセスしたときPersonが返ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val person = Person( - type = emptyList(), - name = "test", - id = "http://example.com/users/test", - preferredUsername = "test", - summary = "test user", - inbox = "http://example.com/users/test/inbox", - outbox = "http://example.com/users/test/outbox", - url = "http://example.com/users/test", - icon = Image( - type = emptyList(), - name = "http://example.com/users/test/icon.png", - mediaType = "image/png", - url = "http://example.com/users/test/icon.png" - ), - publicKey = Key( - type = emptyList(), - name = "Public Key", - id = "http://example.com/users/test#pubkey", - owner = "https://example.com/users/test", - publicKeyPem = "-----BEGIN PUBLIC KEY-----\n\n-----END PUBLIC KEY-----" - ) - ) - person.context = listOf("https://www.w3.org/ns/activitystreams") - - val apUserService = mock { - onBlocking { getPersonByName(anyString()) } doReturn person - } - - application { - configureSerialization() - routing { - usersAP(apUserService, mock(), mock(), TestTransaction) - } - } - client.get("/users/test") { - accept(ContentType.Application.JsonLd) - accept(ContentType.Application.Activity) - }.let { - val objectMapper = jacksonObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) - .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - objectMapper.configOverride(List::class.java).setSetterInfo( - JsonSetter.Value.forValueNulls( - Nulls.AS_EMPTY - ) - ) - val actual = it.bodyAsText() - val readValue = objectMapper.readValue(actual) - assertEquals(person, readValue) - } - } - - // @Disabled - @Test - fun contentType_Test() { - assertTrue(ContentType.Application.Activity.match("application/activity+json")) - val listOf = listOf(ContentType.Application.JsonLd, ContentType.Application.Activity) - assertTrue( - listOf.find { contentType -> - contentType.match("application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") - }.let { it != null } - ) - assertTrue( - ContentType.Application.JsonLd.match( - "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" - ) - ) - } - - @Test - fun ユーザーのURLにAcceptヘッダーをhtmlにしてアクセスしたときはただの文字を返す() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val userService = mock { - onBlocking { findByNameAndDomain(eq("test"), anyString()) } doReturn User.of( - 1L, - "test", - "example.com", - "test", - "", - "hashedPassword", - "https://example.com/inbox", - "https://example.com/outbox", - "https://example.com", - "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----", - "-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----", - Instant.now() - ) - } - application { - routing { - usersAP(mock(), userService, mock(), TestTransaction) - } - } - client.get("/users/test") { - accept(ContentType.Text.Html) - }.let { - assertEquals(HttpStatusCode.OK, it.status) - assertTrue(it.contentType()?.match(ContentType.Text.Plain) == true) - } - } -} diff --git a/src/test/kotlin/dev/usbharu/hideout/routing/api/internal/v1/PostsTest.kt b/src/test/kotlin/dev/usbharu/hideout/routing/api/internal/v1/PostsTest.kt deleted file mode 100644 index 81f9e66c..00000000 --- a/src/test/kotlin/dev/usbharu/hideout/routing/api/internal/v1/PostsTest.kt +++ /dev/null @@ -1,734 +0,0 @@ -package dev.usbharu.hideout.routing.api.internal.v1 - -import com.auth0.jwt.interfaces.Claim -import com.auth0.jwt.interfaces.Payload -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse -import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse -import dev.usbharu.hideout.domain.model.hideout.entity.Visibility -import dev.usbharu.hideout.plugins.TOKEN_AUTH -import dev.usbharu.hideout.plugins.configureSecurity -import dev.usbharu.hideout.plugins.configureSerialization -import dev.usbharu.hideout.service.api.PostApiService -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import io.ktor.server.auth.* -import io.ktor.server.auth.jwt.* -import io.ktor.server.config.* -import io.ktor.server.routing.* -import io.ktor.server.testing.* -import org.junit.jupiter.api.Test -import org.mockito.kotlin.* -import utils.JsonObjectMapper -import java.time.Instant -import kotlin.test.assertContentEquals -import kotlin.test.assertEquals - -class PostsTest { - - @Test - fun 認証情報無しでpostsにGETしたらPUBLICな投稿一覧が返ってくる() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ) - val posts = listOf( - PostResponse( - id = "12345", - user = user, - text = "test1", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/1" - ), - PostResponse( - id = "123456", - user = user, - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - ) - val postService = mock { - onBlocking { - getAll( - since = anyOrNull(), - until = anyOrNull(), - minId = anyOrNull(), - maxId = anyOrNull(), - limit = anyOrNull(), - userId = isNull() - ) - } doReturn posts - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/posts").apply { - assertEquals(HttpStatusCode.OK, status) - assertContentEquals(posts, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun 認証情報ありでpostsにGETすると権限のある投稿が返ってくる() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val claim = mock { - on { asLong() } doReturn 1234 - } - val payload = mock { - on { getClaim(eq("uid")) } doReturn claim - } - val user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ) - val posts = listOf( - PostResponse( - id = "12345", - user = user, - text = "test1", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/1" - ), - PostResponse( - id = "123456", - user = user, - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ), - PostResponse( - id = "1234567", - user = user, - text = "Followers only", - visibility = Visibility.FOLLOWERS, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/3" - ) - ) - - val postService = mock { - onBlocking { - getAll( - since = anyOrNull(), - until = anyOrNull(), - minId = anyOrNull(), - maxId = anyOrNull(), - limit = anyOrNull(), - userId = isNotNull() - ) - } doReturn posts - } - application { - authentication { - bearer(TOKEN_AUTH) { - authenticate { - JWTPrincipal(payload) - } - } - } - configureSerialization() - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - client.get("/api/internal/v1/posts") { - header("Authorization", "Bearer asdkaf") - }.apply { - assertEquals(HttpStatusCode.OK, status) - } - } - - @Test - fun `posts id にGETしたらPUBLICな投稿を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ) - val post = PostResponse( - id = "12345", - user = user, - text = "aaa", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/1" - ) - val postService = mock { - onBlocking { getById(any(), anyOrNull()) } doReturn post - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - client.get("/api/internal/v1/posts/1").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(post, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `認証情報ありでposts id にGETしたら権限のある投稿を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val post = PostResponse( - "12345", - UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ), - text = "aaa", - visibility = Visibility.FOLLOWERS, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/1" - ) - val postService = mock { - onBlocking { getById(any(), isNotNull()) } doReturn post - } - val claim = mock { - on { asLong() } doReturn 1234 - } - val payload = mock { - on { getClaim(eq("uid")) } doReturn claim - } - application { - configureSerialization() - authentication { - bearer(TOKEN_AUTH) { - authenticate { - JWTPrincipal(payload) - } - } - } - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - client.get("/api/internal/v1/posts/1") { - header("Authorization", "Bearer asdkaf") - }.apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(post, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `posts-post postsにpostしたら投稿できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val claim = mock { - on { asLong() } doReturn 1234 - } - val payload = mock { - on { getClaim(eq("uid")) } doReturn claim - } - val postService = mock { - onBlocking { createPost(any(), any()) } doAnswer { - val argument = it.getArgument(0) - val userId = it.getArgument(1) - PostResponse( - id = "123", - user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ), - overview = null, - text = argument.text, - createdAt = Instant.now().toEpochMilli(), - visibility = Visibility.PUBLIC, - url = "https://example.com" - ) - } - } - application { - authentication { - bearer(TOKEN_AUTH) { - authenticate { - println("aaaaaaaaaaaa") - JWTPrincipal(payload) - } - } - } - routing { - route("/api/internal/v1") { - posts(postService) - } - } - configureSerialization() - } - - val post = dev.usbharu.hideout.domain.model.hideout.form.Post("test") - client.post("/api/internal/v1/posts") { - header("Authorization", "Bearer asdkaf") - contentType(ContentType.Application.Json) - setBody(Config.configData.objectMapper.writeValueAsString(post)) - }.apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals("https://example.com", headers["Location"]) - } - argumentCaptor { - verify(postService).createPost(capture(), any()) - assertEquals(dev.usbharu.hideout.domain.model.hideout.form.Post("test"), firstValue) - } - } - - @Test - fun `users userId postsにGETしたらユーザーのPUBLICな投稿一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ) - val posts = listOf( - PostResponse( - id = "12345", - user = user, - text = "test1", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/1" - ), - PostResponse( - id = "123456", - user = user, - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - ) - val postService = mock { - onBlocking { - getByUser( - nameOrId = any(), - since = anyOrNull(), - until = anyOrNull(), - minId = anyOrNull(), - maxId = anyOrNull(), - limit = anyOrNull(), - userId = anyOrNull() - ) - } doReturn posts - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/users/1/posts").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(posts, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users username postsにGETしたらユーザーのPUBLICな投稿一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ) - val posts = listOf( - PostResponse( - id = "12345", - user = user, - text = "test1", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/1" - ), - PostResponse( - id = "123456", - user = user, - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - ) - val postService = mock { - onBlocking { - getByUser( - nameOrId = eq("test1"), - since = anyOrNull(), - until = anyOrNull(), - minId = anyOrNull(), - maxId = anyOrNull(), - limit = anyOrNull(), - userId = anyOrNull() - ) - } doReturn posts - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/users/test1/posts").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(posts, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users username@domain postsにGETしたらユーザーのPUBLICな投稿一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ) - val posts = listOf( - PostResponse( - id = "12345", - user = user, - text = "test1", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/1" - ), - PostResponse( - id = "123456", - user = user, - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - ) - val postService = mock { - onBlocking { - getByUser( - nameOrId = eq("test1@example.com"), - since = anyOrNull(), - until = anyOrNull(), - minId = anyOrNull(), - maxId = anyOrNull(), - limit = anyOrNull(), - userId = anyOrNull() - ) - } doReturn posts - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/users/test1@example.com/posts").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(posts, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users @username@domain postsにGETしたらユーザーのPUBLICな投稿一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ) - val posts = listOf( - PostResponse( - id = "12345", - user = user, - text = "test1", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/1" - ), - PostResponse( - id = "123456", - user = user, - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - ) - val postService = mock { - onBlocking { - getByUser( - nameOrId = eq("@test1@example.com"), - since = anyOrNull(), - until = anyOrNull(), - minId = anyOrNull(), - maxId = anyOrNull(), - limit = anyOrNull(), - userId = anyOrNull() - ) - } doReturn posts - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/users/@test1@example.com/posts").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(posts, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users name posts id にGETしたらPUBLICな投稿を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val post = PostResponse( - id = "123456", - user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ), - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - val postService = mock { - onBlocking { getById(eq(12345L), anyOrNull()) } doReturn post - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/users/test/posts/12345").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(post, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users id posts id にGETしたらPUBLICな投稿を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val post = PostResponse( - id = "123456", - user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ), - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - val postService = mock { - onBlocking { getById(eq(12345L), anyOrNull()) } doReturn post - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/users/1/posts/12345").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(post, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users name posts id にGETしたらUserIdが間違っててもPUBLICな投稿を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val post = PostResponse( - id = "123456", - user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ), - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - val postService = mock { - onBlocking { getById(eq(12345L), anyOrNull()) } doReturn post - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/users/423827849732847/posts/12345").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(post, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users name posts id にGETしたらuserNameが間違っててもPUBLICな投稿を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val post = PostResponse( - id = "123456", - user = UserResponse( - id = "54321", - name = "user1", - domain = "example.com", - screenName = "user 1", - description = "Test user", - url = "https://example.com/users/54321", - createdAt = Instant.now().toEpochMilli() - ), - text = "test2", - visibility = Visibility.PUBLIC, - createdAt = Instant.now().toEpochMilli(), - url = "https://example.com/posts/2" - ) - val postService = mock { - onBlocking { getById(eq(12345L), anyOrNull()) } doReturn post - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - posts(postService) - } - } - } - - client.get("/api/internal/v1/users/invalidUserName/posts/12345").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(post, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } -} diff --git a/src/test/kotlin/dev/usbharu/hideout/routing/api/internal/v1/UsersTest.kt b/src/test/kotlin/dev/usbharu/hideout/routing/api/internal/v1/UsersTest.kt deleted file mode 100644 index 9bc0db7d..00000000 --- a/src/test/kotlin/dev/usbharu/hideout/routing/api/internal/v1/UsersTest.kt +++ /dev/null @@ -1,692 +0,0 @@ -package dev.usbharu.hideout.routing.api.internal.v1 - -import com.auth0.jwt.interfaces.Claim -import com.auth0.jwt.interfaces.Payload -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.domain.model.Acct -import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse -import dev.usbharu.hideout.domain.model.hideout.entity.User -import dev.usbharu.hideout.domain.model.hideout.form.UserCreate -import dev.usbharu.hideout.plugins.TOKEN_AUTH -import dev.usbharu.hideout.plugins.configureSecurity -import dev.usbharu.hideout.plugins.configureSerialization -import dev.usbharu.hideout.service.api.UserApiService -import dev.usbharu.hideout.service.user.UserService -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import io.ktor.server.auth.* -import io.ktor.server.auth.jwt.* -import io.ktor.server.config.* -import io.ktor.server.routing.* -import io.ktor.server.testing.* -import org.junit.jupiter.api.Test -import org.mockito.kotlin.* -import utils.JsonObjectMapper -import java.time.Instant -import kotlin.test.assertEquals -@Suppress("LargeClass") -class UsersTest { - @Test - fun `users にGETするとユーザー一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val users = listOf( - UserResponse( - "12345", - "test1", - "example.com", - "test", - "", - "https://example.com/test", - Instant.now().toEpochMilli() - ), - UserResponse( - "12343", - "tes2", - "example.com", - "test", - "", - "https://example.com/tes2", - Instant.now().toEpochMilli() - ), - ) - val userService = mock { - onBlocking { findAll(anyOrNull(), anyOrNull()) } doReturn users - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userService) - } - } - } - client.get("/api/internal/v1/users").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(users, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users にPOSTすると新規ユーザー作成ができる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val userCreateDto = UserCreate("test", "XXXXXXX") - val userService = mock { - onBlocking { usernameAlreadyUse(any()) } doReturn false - onBlocking { createLocalUser(any()) } doReturn User.of( - id = 12345, - name = "test", - domain = "example.com", - screenName = "testUser", - description = "test user", - password = "XXXXXXX", - inbox = "https://example.com/inbox", - outbox = "https://example.com/outbox", - url = "https://example.com", - publicKey = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----", - privateKey = "-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----", - createdAt = Instant.now() - ) - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(userService, mock()) - } - } - } - - client.post("/api/internal/v1/users") { - contentType(ContentType.Application.Json) - setBody(JsonObjectMapper.objectMapper.writeValueAsString(userCreateDto)) - }.apply { - assertEquals(HttpStatusCode.Created, status) - assertEquals( - "${Config.configData.url}/api/internal/v1/users/${userCreateDto.username}", - headers["Location"] - ) - } - } - - @Test - fun `users 既にユーザー名が使用されているときはBadRequestが帰ってくる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val userCreateDto = UserCreate("test", "XXXXXXX") - val userService = mock { - onBlocking { usernameAlreadyUse(any()) } doReturn true - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(userService, mock()) - } - } - } - - client.post("/api/internal/v1/users") { - contentType(ContentType.Application.Json) - setBody(JsonObjectMapper.objectMapper.writeValueAsString(userCreateDto)) - }.apply { - assertEquals(HttpStatusCode.BadRequest, status) - } - } - - @Test - fun `users name にGETしたらユーザーを取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val userResponse = UserResponse( - "1234", - "test1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - val userApiService = mock { - onBlocking { findByAcct(any()) } doReturn userResponse - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/test1").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(userResponse, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users id にGETしたらユーザーを取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val userResponse = UserResponse( - "1234", - "test1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - val userApiService = mock { - onBlocking { findById(any()) } doReturn userResponse - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/1234").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(userResponse, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users name@domain にGETしたらユーザーを取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val userResponse = UserResponse( - "1234", - "test1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - val userApiService = mock { - onBlocking { findByAcct(any()) } doReturn userResponse - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/test1").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(userResponse, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users @name@domain にGETしたらユーザーを取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - val userResponse = UserResponse( - "1234", - "test1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - val userApiService = mock { - onBlocking { findByAcct(any()) } doReturn userResponse - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/test1").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(userResponse, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users name followers にGETしたらフォロワー一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val followers = listOf( - UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ), - UserResponse( - "1236", - "follower2", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - ) - val userApiService = mock { - onBlocking { findFollowersByAcct(any()) } doReturn followers - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/test1/followers").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(followers, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users name@domain followers にGETしたらフォロワー一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val followers = listOf( - UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ), - UserResponse( - "1236", - "follower2", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - ) - val userApiService = mock { - onBlocking { findFollowersByAcct(any()) } doReturn followers - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/@test1@example.com/followers").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(followers, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users id followers にGETしたらフォロワー一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val followers = listOf( - UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ), - UserResponse( - "1236", - "follower2", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - ) - val userApiService = mock { - onBlocking { findFollowers(any()) } doReturn followers - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/1234/followers").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(followers, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users name followers に認証情報ありでGETしたらフォローできる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val claim = mock { - on { asLong() } doReturn 1234 - } - val payload = mock { - on { getClaim(eq("uid")) } doReturn claim - } - - val userApiService = mock { - onBlocking { findByAcct(any()) } doReturn UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - onBlocking { follow(any(), eq(1234)) } doReturn true - } - application { - configureSerialization() - authentication { - bearer(TOKEN_AUTH) { - authenticate { - JWTPrincipal(payload) - } - } - } - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.post("/api/internal/v1/users/test1/followers") { - header(HttpHeaders.Authorization, "Bearer test") - }.apply { - assertEquals(HttpStatusCode.OK, status) - } - } - - @Test - fun `users name followers に認証情報ありでGETしたらフォロー処理受付になることもある`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val claim = mock { - on { asLong() } doReturn 1234 - } - val payload = mock { - on { getClaim(eq("uid")) } doReturn claim - } - - val userApiService = mock { - onBlocking { findByAcct(any()) } doReturn UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - onBlocking { follow(any(), eq(1234)) } doReturn false - } - application { - configureSerialization() - authentication { - bearer(TOKEN_AUTH) { - authenticate { - JWTPrincipal(payload) - } - } - } - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.post("/api/internal/v1/users/test1/followers") { - header(HttpHeaders.Authorization, "Bearer test") - }.apply { - assertEquals(HttpStatusCode.Accepted, status) - } - } - - @Test - fun `users id followers に認証情報ありでGETしたらフォロー処理受付になることもある`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val claim = mock { - on { asLong() } doReturn 1234 - } - val payload = mock { - on { getClaim(eq("uid")) } doReturn claim - } - - val userApiService = mock { - onBlocking { findById(any()) } doReturn UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - onBlocking { follow(eq(1235), eq(1234)) } doReturn false - } - application { - configureSerialization() - authentication { - bearer(TOKEN_AUTH) { - authenticate { - JWTPrincipal(payload) - } - } - } - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.post("/api/internal/v1/users/1235/followers") { - header(HttpHeaders.Authorization, "Bearer test") - }.apply { - assertEquals(HttpStatusCode.Accepted, status) - } - } - - @Test - fun `users name following にGETしたらフォロイー一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val followers = listOf( - UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ), - UserResponse( - "1236", - "follower2", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - ) - val userApiService = mock { - onBlocking { findFollowingsByAcct(any()) } doReturn followers - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/test1/following").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(followers, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users name@domain following にGETしたらフォロイー一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val followers = listOf( - UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ), - UserResponse( - "1236", - "follower2", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - ) - val userApiService = mock { - onBlocking { findFollowingsByAcct(any()) } doReturn followers - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/test1@domain/following").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(followers, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } - - @Test - fun `users id following にGETしたらフォロイー一覧を取得できる`() = testApplication { - environment { - config = ApplicationConfig("empty.conf") - } - - val followers = listOf( - UserResponse( - "1235", - "follower1", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ), - UserResponse( - "1236", - "follower2", - "example.com", - "test", - "test User", - "https://example.com/test", - Instant.now().toEpochMilli() - ) - ) - val userApiService = mock { - onBlocking { findFollowings(any()) } doReturn followers - } - application { - configureSerialization() - configureSecurity(mock(), mock()) - routing { - route("/api/internal/v1") { - users(mock(), userApiService) - } - } - } - - client.get("/api/internal/v1/users/1234/following").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals(followers, JsonObjectMapper.objectMapper.readValue(bodyAsText())) - } - } -} From d94b05e50d38bb6cb98221678ef69986e029b4eb Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 23 Sep 2023 00:00:19 +0900 Subject: [PATCH 5/5] =?UTF-8?q?style:=20=E3=82=B9=E3=82=BF=E3=82=A4?= =?UTF-8?q?=E3=83=AB=E3=82=92=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/dev/usbharu/hideout/config/SecurityConfig.kt | 3 --- .../controller/mastodon/MastodonAppsApiController.kt | 1 - .../dev/usbharu/hideout/domain/model/UserDetailsImpl.kt | 6 ------ .../hideout/repository/RegisteredClientRepositoryImpl.kt | 1 - .../hideout/service/api/mastodon/AccountApiService.kt | 2 -- .../hideout/service/api/mastodon/StatusesApiService.kt | 3 --- .../auth/ExposedOAuth2AuthorizationConsentService.kt | 3 --- .../service/auth/ExposedOAuth2AuthorizationService.kt | 2 -- .../hideout/service/auth/SecureTokenGeneratorImpl.kt | 2 -- 9 files changed, 23 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt index 8dc456bc..589dc701 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt @@ -35,7 +35,6 @@ import java.security.interfaces.RSAPrivateKey import java.security.interfaces.RSAPublicKey import java.util.* - @EnableWebSecurity(debug = true) @Configuration class SecurityConfig { @@ -152,8 +151,6 @@ class SecurityConfig { if (OAuth2TokenType.ACCESS_TOKEN == context.tokenType) { val userDetailsImpl = context.getPrincipal().principal as UserDetailsImpl context.claims.claim("uid", userDetailsImpl.id.toString()) - - } } } diff --git a/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonAppsApiController.kt b/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonAppsApiController.kt index 9d538ce6..934b7d79 100644 --- a/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonAppsApiController.kt +++ b/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonAppsApiController.kt @@ -35,5 +35,4 @@ class MastodonAppsApiController(private val appApiService: AppApiService) : AppA HttpStatus.OK ) } - } diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/UserDetailsImpl.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/UserDetailsImpl.kt index b666c5e8..a94547ba 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/UserDetailsImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/UserDetailsImpl.kt @@ -30,8 +30,6 @@ class UserDetailsImpl( @Serial private const val serialVersionUID: Long = -899168205656607781L } - - } @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) @@ -46,11 +44,9 @@ class UserDetailsImpl( @JsonSubTypes abstract class UserDetailsMixin - class UserDetailsDeserializer : JsonDeserializer() { val SIMPLE_GRANTED_AUTHORITY_SET = object : TypeReference>() {} override fun deserialize(p: JsonParser, ctxt: DeserializationContext): UserDetailsImpl { - val mapper = p.codec as ObjectMapper val jsonNode: JsonNode = mapper.readTree(p) println(jsonNode) @@ -70,7 +66,6 @@ class UserDetailsDeserializer : JsonDeserializer() { true, authorities.toMutableList(), ) - } fun JsonNode.readText(field: String, defaultValue: String = ""): String { @@ -79,5 +74,4 @@ class UserDetailsDeserializer : JsonDeserializer() { else -> defaultValue } } - } diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/RegisteredClientRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/RegisteredClientRepositoryImpl.kt index c451639b..d03b302e 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/RegisteredClientRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/RegisteredClientRepositoryImpl.kt @@ -175,7 +175,6 @@ class RegisteredClientRepositoryImpl(private val database: Database) : Registere return builder.build() } - } // org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql diff --git a/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/AccountApiService.kt b/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/AccountApiService.kt index 1e5cab0b..0a18609f 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/AccountApiService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/AccountApiService.kt @@ -13,7 +13,6 @@ interface AccountApiService { suspend fun verifyCredentials(userid: Long): CredentialAccount } - @Service class AccountApiServiceImpl(private val accountService: AccountService, private val transaction: Transaction) : AccountApiService { @@ -59,5 +58,4 @@ class AccountApiServiceImpl(private val accountService: AccountService, private role = Role(0, "Admin", "", 32) ) } - } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt b/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt index 17c8c794..4f0b8dc2 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt @@ -18,7 +18,6 @@ interface StatusesApiService { suspend fun postStatus(statusesRequest: StatusesRequest, user: UserDetailsImpl): Status } - @Service class StatsesApiServiceImpl( private val postService: PostService, @@ -28,7 +27,6 @@ class StatsesApiServiceImpl( ) : StatusesApiService { override suspend fun postStatus(statusesRequest: StatusesRequest, user: UserDetailsImpl): Status { - val visibility = when (statusesRequest.visibility) { StatusesRequest.Visibility.public -> Visibility.PUBLIC StatusesRequest.Visibility.unlisted -> Visibility.UNLISTED @@ -67,7 +65,6 @@ class StatsesApiServiceImpl( null } - return Status( id = post.id.toString(), uri = post.apId, diff --git a/src/main/kotlin/dev/usbharu/hideout/service/auth/ExposedOAuth2AuthorizationConsentService.kt b/src/main/kotlin/dev/usbharu/hideout/service/auth/ExposedOAuth2AuthorizationConsentService.kt index 9fb968e0..b3b0d420 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/auth/ExposedOAuth2AuthorizationConsentService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/auth/ExposedOAuth2AuthorizationConsentService.kt @@ -26,11 +26,9 @@ class ExposedOAuth2AuthorizationConsentService( } } - override fun save(authorizationConsent: AuthorizationConsent?) = runBlocking { requireNotNull(authorizationConsent) transaction.transaction { - val singleOrNull = OAuth2AuthorizationConsent.select { OAuth2AuthorizationConsent.registeredClientId @@ -61,7 +59,6 @@ class ExposedOAuth2AuthorizationConsentService( requireNotNull(registeredClientId) requireNotNull(principalName) transaction.transaction { - OAuth2AuthorizationConsent.select { (OAuth2AuthorizationConsent.registeredClientId eq registeredClientId) .and(OAuth2AuthorizationConsent.principalName eq principalName) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/auth/ExposedOAuth2AuthorizationService.kt b/src/main/kotlin/dev/usbharu/hideout/service/auth/ExposedOAuth2AuthorizationService.kt index c1d4b287..65d0b675 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/auth/ExposedOAuth2AuthorizationService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/auth/ExposedOAuth2AuthorizationService.kt @@ -151,8 +151,6 @@ class ExposedOAuth2AuthorizationService( override fun findByToken(token: String?, tokenType: OAuth2TokenType?): OAuth2Authorization? = runBlocking { requireNotNull(token) transaction.transaction { - - when (tokenType?.value) { null -> { Authorization.select { diff --git a/src/main/kotlin/dev/usbharu/hideout/service/auth/SecureTokenGeneratorImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/auth/SecureTokenGeneratorImpl.kt index 9a36f5e7..4015dfed 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/auth/SecureTokenGeneratorImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/auth/SecureTokenGeneratorImpl.kt @@ -7,12 +7,10 @@ import java.util.* @Component class SecureTokenGeneratorImpl : SecureTokenGenerator { override fun generate(): String { - val byteArray = ByteArray(16) val secureRandom = SecureRandom() secureRandom.nextBytes(byteArray) - return Base64.getUrlEncoder().encodeToString(byteArray) } }