From 71eeb47169d0ec67fd55a8de49ccaf56a23104ad Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:18:45 +0900 Subject: [PATCH] wip --- .../intTest/kotlin/mastodon/apps/AppTest.kt | 2 +- .../hideout/application/config/AwsConfig.kt | 38 -- .../application/config/CaptchaConfig.kt | 9 - .../application/config/HttpClientConfig.kt | 44 -- .../application/config/HttpSignatureConfig.kt | 36 -- .../application/config/MdcXrequestIdFilter.kt | 45 -- .../hideout/application/config/MediaConfig.kt | 24 -- .../application/config/MvcConfigurer.kt | 46 -- .../hideout/application/config/OwlConfig.kt | 89 ---- .../application/config/SecurityConfig.kt | 319 -------------- .../application/config/SpringConfig.kt | 105 ----- .../application/external/OwlProducerRunner.kt | 42 -- .../exposed/ExposedPaginationExtension.kt | 35 -- .../infrastructure/exposed/Page.kt | 63 --- .../infrastructure/exposed/PaginationList.kt | 38 -- ...oleHierarchyAuthorizationManagerFactory.kt | 32 -- .../RegisterLocalActorApplicationService.kt | 2 +- .../config/HtmlSanitizeConfig.kt | 2 +- .../post/DefaultPostContentFormatter.kt} | 14 +- .../service/post/PostContentFormatter.kt} | 12 +- .../domain/shared}/id/IdGenerateService.kt | 5 +- .../exposed/ActorQueryMapper.kt | 2 - .../exposed/ActorResultRowMapper.kt | 1 - .../exposed/ExposedTransaction.kt | 17 +- .../infrastructure/exposed/QueryMapper.kt | 2 +- .../infrastructure/exposed/ResultRowMapper.kt | 2 +- .../ExposedActorRepository.kt | 2 +- .../factory/ActorFactoryImpl.kt | 2 +- .../factory/PostContentFactoryImpl.kt | 2 +- .../infrastructure/factory/PostFactoryImpl.kt | 2 +- .../httpsignature/HttpRequestMixIn.kt | 45 -- .../other}/SnowflakeIdGenerateService.kt | 5 +- .../TwitterSnowflakeIdGenerateService.kt | 2 +- ...xposedOAuth2AuthorizationConsentService.kt | 97 ----- .../ExposedOAuth2AuthorizationService.kt | 393 ------------------ .../oauth2/RegisteredClientRepositoryImpl.kt | 206 --------- .../springframework/oauth2/UserDetailsImpl.kt | 120 ------ .../OAuth2JwtLoginUserContextHolder.kt | 39 -- .../hideout/generate/JsonOrFormBind.kt | 22 - .../JsonOrFormModelMethodProcessor.kt | 78 ---- .../domain/model/actor/TestActor2Factory.kt | 2 +- hideout-mastodon/src/main/kotlin/Main.kt | 5 - 42 files changed, 33 insertions(+), 2015 deletions(-) delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/AwsConfig.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/CaptchaConfig.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HttpClientConfig.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HttpSignatureConfig.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MdcXrequestIdFilter.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MediaConfig.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MvcConfigurer.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/OwlConfig.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SpringConfig.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/external/OwlProducerRunner.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedPaginationExtension.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/Page.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PaginationList.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/springframework/RoleHierarchyAuthorizationManagerFactory.kt rename hideout-core/src/main/kotlin/dev/usbharu/hideout/{application => core}/config/HtmlSanitizeConfig.kt (96%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/core/{service/post/PostContentFormatter.kt => domain/service/post/DefaultPostContentFormatter.kt} (94%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/core/{infrastructure/springframework/security/LoginUserContextHolder.kt => domain/service/post/PostContentFormatter.kt} (73%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/{application/service => core/domain/shared}/id/IdGenerateService.kt (86%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/{application => core}/infrastructure/exposed/ExposedTransaction.kt (78%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/{application => core}/infrastructure/exposed/QueryMapper.kt (91%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/{application => core}/infrastructure/exposed/ResultRowMapper.kt (91%) delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/httpsignature/HttpRequestMixIn.kt rename hideout-core/src/main/kotlin/dev/usbharu/hideout/{application/service/id => core/infrastructure/other}/SnowflakeIdGenerateService.kt (92%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/{application/service/id => core/infrastructure/other}/TwitterSnowflakeIdGenerateService.kt (94%) delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/ExposedOAuth2AuthorizationConsentService.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/ExposedOAuth2AuthorizationService.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/RegisteredClientRepositoryImpl.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsImpl.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/security/OAuth2JwtLoginUserContextHolder.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/generate/JsonOrFormBind.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/generate/JsonOrFormModelMethodProcessor.kt delete mode 100644 hideout-mastodon/src/main/kotlin/Main.kt diff --git a/hideout-core/src/intTest/kotlin/mastodon/apps/AppTest.kt b/hideout-core/src/intTest/kotlin/mastodon/apps/AppTest.kt index 8ce170eb..8b8ff123 100644 --- a/hideout-core/src/intTest/kotlin/mastodon/apps/AppTest.kt +++ b/hideout-core/src/intTest/kotlin/mastodon/apps/AppTest.kt @@ -17,7 +17,6 @@ package mastodon.apps import dev.usbharu.hideout.SpringApplication -import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.RegisteredClient import dev.usbharu.owl.producer.api.OwlProducer import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat @@ -30,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest import org.springframework.http.MediaType +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient import org.springframework.security.test.context.support.WithAnonymousUser import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers import org.springframework.test.web.servlet.MockMvc diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/AwsConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/AwsConfig.kt deleted file mode 100644 index 2356b3d4..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/AwsConfig.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials -import software.amazon.awssdk.regions.Region -import software.amazon.awssdk.services.s3.S3Client -import java.net.URI - -@Configuration -class AwsConfig { - @Bean - @ConditionalOnProperty("hideout.storage.type", havingValue = "s3") - fun s3Client(awsConfig: S3StorageConfig): S3Client { - return S3Client.builder() - .endpointOverride(URI.create(awsConfig.endpoint)) - .region(Region.of(awsConfig.region)) - .credentialsProvider { AwsBasicCredentials.create(awsConfig.accessKey, awsConfig.secretKey) } - .build() - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/CaptchaConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/CaptchaConfig.kt deleted file mode 100644 index ac8237f6..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/CaptchaConfig.kt +++ /dev/null @@ -1,9 +0,0 @@ -package dev.usbharu.hideout.application.config - -import org.springframework.boot.context.properties.ConfigurationProperties - -@ConfigurationProperties("hideout.security") -data class CaptchaConfig( - val reCaptchaSiteKey: String?, - val reCaptchaSecretKey: String? -) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HttpClientConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HttpClientConfig.kt deleted file mode 100644 index 2f783282..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HttpClientConfig.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import io.ktor.client.* -import io.ktor.client.engine.cio.* -import io.ktor.client.plugins.* -import io.ktor.client.plugins.cache.* -import io.ktor.client.plugins.logging.* -import org.springframework.boot.info.BuildProperties -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -@Configuration -class HttpClientConfig { - @Bean - fun httpClient(buildProperties: BuildProperties, applicationConfig: ApplicationConfig): HttpClient = - HttpClient(CIO).config { - install(Logging) { - logger = Logger.DEFAULT - level = LogLevel.ALL - } - install(HttpCache) { - } - expectSuccess = true - install(UserAgent) { - agent = "Hideout/${buildProperties.version} (${applicationConfig.url})" - } - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HttpSignatureConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HttpSignatureConfig.kt deleted file mode 100644 index 9935c53b..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HttpSignatureConfig.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import dev.usbharu.httpsignature.sign.RsaSha256HttpSignatureSigner -import dev.usbharu.httpsignature.verify.DefaultSignatureHeaderParser -import dev.usbharu.httpsignature.verify.RsaSha256HttpSignatureVerifier -import dev.usbharu.httpsignature.verify.SignatureHeaderParser -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -@Configuration -class HttpSignatureConfig { - @Bean - fun defaultSignatureHeaderParser(): DefaultSignatureHeaderParser = DefaultSignatureHeaderParser() - - @Bean - fun rsaSha256HttpSignatureVerifier( - signatureHeaderParser: SignatureHeaderParser, - signatureSigner: RsaSha256HttpSignatureSigner - ): RsaSha256HttpSignatureVerifier = RsaSha256HttpSignatureVerifier(signatureHeaderParser, signatureSigner) -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MdcXrequestIdFilter.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MdcXrequestIdFilter.kt deleted file mode 100644 index 188251de..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MdcXrequestIdFilter.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import jakarta.servlet.Filter -import jakarta.servlet.FilterChain -import jakarta.servlet.ServletRequest -import jakarta.servlet.ServletResponse -import org.slf4j.MDC -import org.springframework.boot.autoconfigure.security.SecurityProperties -import org.springframework.core.annotation.Order -import org.springframework.stereotype.Component -import java.util.* - -@Component -@Order(SecurityProperties.DEFAULT_FILTER_ORDER - 1) -class MdcXrequestIdFilter : Filter { - override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain) { - val uuid = UUID.randomUUID() - try { - MDC.put(KEY, uuid.toString()) - chain.doFilter(request, response) - } finally { - MDC.remove(KEY) - } - } - - companion object { - private const val KEY = "x-request-id" - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MediaConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MediaConfig.kt deleted file mode 100644 index 43d7cbf9..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MediaConfig.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import org.springframework.boot.context.properties.ConfigurationProperties - -@ConfigurationProperties("hideout.media") -data class MediaConfig( - val remoteMediaFileSizeLimit: Long = 3000000L -) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MvcConfigurer.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MvcConfigurer.kt deleted file mode 100644 index 05c1898c..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/MvcConfigurer.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import dev.usbharu.hideout.generate.JsonOrFormModelMethodProcessor -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.http.converter.HttpMessageConverter -import org.springframework.web.method.support.HandlerMethodArgumentResolver -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer -import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor -import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor - -@Configuration -class MvcConfigurer(private val jsonOrFormModelMethodProcessor: JsonOrFormModelMethodProcessor) : WebMvcConfigurer { - override fun addArgumentResolvers(resolvers: MutableList) { - resolvers.add(jsonOrFormModelMethodProcessor) - } -} - -@Configuration -class JsonOrFormModelMethodProcessorConfig { - @Bean - fun jsonOrFormModelMethodProcessor(converter: List>): JsonOrFormModelMethodProcessor { - return JsonOrFormModelMethodProcessor( - ServletModelAttributeMethodProcessor(true), - RequestResponseBodyMethodProcessor( - converter - ) - ) - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/OwlConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/OwlConfig.kt deleted file mode 100644 index e5454e23..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/OwlConfig.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import com.fasterxml.jackson.databind.ObjectMapper -import dev.usbharu.owl.broker.ModuleContext -import dev.usbharu.owl.common.property.* -import dev.usbharu.owl.common.retry.RetryPolicyFactory -import dev.usbharu.owl.producer.api.OWL -import dev.usbharu.owl.producer.api.OwlProducer -import dev.usbharu.owl.producer.defaultimpl.DEFAULT -import dev.usbharu.owl.producer.embedded.EMBEDDED -import dev.usbharu.owl.producer.embedded.EMBEDDED_GRPC -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import java.util.* - -@Configuration -class OwlConfig(private val producerConfig: ProducerConfig) { - @Bean - fun producer( - @Autowired(required = false) retryPolicyFactory: RetryPolicyFactory? = null, - @Qualifier("activitypub") objectMapper: ObjectMapper, - ): OwlProducer { - return when (producerConfig.mode) { - ProducerMode.EMBEDDED -> { - OWL(EMBEDDED) { - if (retryPolicyFactory != null) { - this.retryPolicyFactory = retryPolicyFactory - } - if (producerConfig.port != null) { - this.port = producerConfig.port.toString() - } - val moduleContext = ServiceLoader.load(ModuleContext::class.java).firstOrNull() - if (moduleContext != null) { - this.moduleContext = moduleContext - } - this.propertySerializerFactory = CustomPropertySerializerFactory( - setOf( - IntegerPropertySerializer(), - StringPropertyValueSerializer(), - DoublePropertySerializer(), - BooleanPropertySerializer(), - LongPropertySerializer(), - FloatPropertySerializer(), - ObjectPropertySerializer(objectMapper), - ) - ) - } - } - - ProducerMode.GRPC -> { - OWL(EMBEDDED_GRPC) { - } - } - - ProducerMode.EMBEDDED_GRPC -> { - OWL(DEFAULT) { - } - } - } - } -} - -@ConfigurationProperties("hideout.owl.producer") -data class ProducerConfig(val mode: ProducerMode = ProducerMode.EMBEDDED, val port: Int? = null) - -enum class ProducerMode { - GRPC, - EMBEDDED, - EMBEDDED_GRPC -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt deleted file mode 100644 index 0730dfb7..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import com.nimbusds.jose.jwk.JWKSet -import com.nimbusds.jose.jwk.RSAKey -import com.nimbusds.jose.jwk.source.ImmutableJWKSet -import com.nimbusds.jose.jwk.source.JWKSource -import com.nimbusds.jose.proc.SecurityContext -import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.UserDetailsImpl -import dev.usbharu.hideout.util.RsaUtil -import jakarta.annotation.PostConstruct -import jakarta.servlet.* -import org.springframework.beans.factory.support.BeanDefinitionRegistry -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty -import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.core.annotation.Order -import org.springframework.http.HttpMethod.GET -import org.springframework.http.HttpMethod.POST -import org.springframework.http.HttpStatus -import org.springframework.security.authentication.AuthenticationManager -import org.springframework.security.authentication.dao.DaoAuthenticationProvider -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration -import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity -import org.springframework.security.config.annotation.web.invoke -import org.springframework.security.config.http.SessionCreationPolicy -import org.springframework.security.core.Authentication -import org.springframework.security.core.context.SecurityContextHolderStrategy -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.security.oauth2.core.AuthorizationGrantType -import org.springframework.security.oauth2.jwt.JwtDecoder -import org.springframework.security.oauth2.server.authorization.OAuth2TokenType -import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration -import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings -import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer -import org.springframework.security.web.FilterChainProxy -import org.springframework.security.web.SecurityFilterChain -import org.springframework.security.web.authentication.HttpStatusEntryPoint -import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider -import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer -import org.springframework.security.web.debug.DebugFilter -import org.springframework.security.web.firewall.HttpFirewall -import org.springframework.security.web.firewall.RequestRejectedHandler -import org.springframework.security.web.util.matcher.AnyRequestMatcher -import org.springframework.web.filter.CompositeFilter -import java.io.IOException -import java.security.KeyPairGenerator -import java.security.interfaces.RSAPrivateKey -import java.security.interfaces.RSAPublicKey -import java.util.* - -@EnableWebSecurity(debug = false) -@Configuration -@Suppress("FunctionMaxLength", "TooManyFunctions", "LongMethod") -class SecurityConfig { - - @Bean - fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? = - authenticationConfiguration.authenticationManager - - @Bean - @Order(1) - fun httpSignatureFilterChain( - http: HttpSecurity, - ): SecurityFilterChain { - http { - securityMatcher("/users/*/posts/*") - authorizeHttpRequests { - authorize(anyRequest, permitAll) - } - exceptionHandling { - authenticationEntryPoint = HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED) - defaultAuthenticationEntryPointFor( - HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), - AnyRequestMatcher.INSTANCE - ) - } - sessionManagement { - sessionCreationPolicy = SessionCreationPolicy.STATELESS - } - } - return http.build() - } - - - @Bean - @Order(2) - fun oauth2SecurityFilterChain(http: HttpSecurity): SecurityFilterChain { - OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http) - http { - exceptionHandling { - authenticationEntryPoint = LoginUrlAuthenticationEntryPoint("/login") - } - oauth2ResourceServer { - jwt { - } - } - } - return http.build() - } - - @Bean - @Order(5) - fun defaultSecurityFilterChain( - http: HttpSecurity, - ): SecurityFilterChain { - http { - authorizeHttpRequests { - authorize("/error", permitAll) - authorize("/login", permitAll) - authorize(GET, "/.well-known/**", permitAll) - authorize(GET, "/nodeinfo/2.0", permitAll) - - authorize(POST, "/inbox", permitAll) - authorize(POST, "/users/*/inbox", permitAll) - authorize(GET, "/users/*", permitAll) - authorize(GET, "/users/*/posts/*", permitAll) - - authorize("/dev/usbharu/hideout/core/service/auth/sign_up", hasRole("ANONYMOUS")) - authorize(GET, "/files/*", permitAll) - authorize(GET, "/users/*/icon.jpg", permitAll) - authorize(GET, "/users/*/header.jpg", permitAll) - - authorize(anyRequest, authenticated) - } - - oauth2ResourceServer { - jwt { } - } - - formLogin { - } - - csrf { - ignoringRequestMatchers("/users/*/inbox", "/inbox", "/api/v1/apps") - } - - headers { - frameOptions { - sameOrigin = true - } - } - } - return http.build() - } - - @Bean - fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder() - - @Bean - @ConditionalOnProperty(name = ["hideout.security.jwt.generate"], havingValue = "false", matchIfMissing = true) - fun genJwkSource(): JWKSource { - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(2048) - val generateKeyPair = keyPairGenerator.generateKeyPair() - val rsaPublicKey = generateKeyPair.public as RSAPublicKey - val rsaPrivateKey = generateKeyPair.private as RSAPrivateKey - val rsaKey = RSAKey.Builder(rsaPublicKey).privateKey(rsaPrivateKey).keyID(UUID.randomUUID().toString()).build() - - val jwkSet = JWKSet(rsaKey) - return ImmutableJWKSet(jwkSet) - } - - @Bean - @ConditionalOnProperty(name = ["hideout.security.jwt.generate"], havingValue = "") - fun loadJwkSource(jwkConfig: JwkConfig): JWKSource { - val rsaKey = RSAKey.Builder(RsaUtil.decodeRsaPublicKey(jwkConfig.publicKey)) - .privateKey(RsaUtil.decodeRsaPrivateKey(jwkConfig.privateKey)).keyID(jwkConfig.keyId).build() - return ImmutableJWKSet(JWKSet(rsaKey)) - } - - @Bean - fun jwtDecoder(jwkSource: JWKSource): JwtDecoder = - OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource) - - @Bean - fun authorizationServerSettings(): AuthorizationServerSettings { - return AuthorizationServerSettings.builder().authorizationEndpoint("/oauth/authorize") - .tokenEndpoint("/oauth/token").tokenRevocationEndpoint("/oauth/revoke").build() - } - - @Bean - fun jwtTokenCustomizer(): OAuth2TokenCustomizer { - return OAuth2TokenCustomizer { context: JwtEncodingContext -> - - if (OAuth2TokenType.ACCESS_TOKEN == context.tokenType && - context.authorization?.authorizationGrantType == AuthorizationGrantType.AUTHORIZATION_CODE - ) { - val userDetailsImpl = context.getPrincipal().principal as UserDetailsImpl - context.claims.claim("uid", userDetailsImpl.id.toString()) - } - } - } - - - // Spring Security 3.2.1 に存在する EnableWebSecurity(debug = true)にすると発生するエラーに対処するためのコード - // trueにしないときはコメントアウト - - // @Bean - fun beanDefinitionRegistryPostProcessor(): BeanDefinitionRegistryPostProcessor { - return BeanDefinitionRegistryPostProcessor { registry: BeanDefinitionRegistry -> - registry.getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME).beanClassName = - CompositeFilterChainProxy::class.java.name - } - } - - @Suppress("ExpressionBodySyntax") - internal class CompositeFilterChainProxy(filters: List) : FilterChainProxy() { - private val doFilterDelegate: Filter - - private val springSecurityFilterChain: FilterChainProxy - - init { - this.doFilterDelegate = createDoFilterDelegate(filters) - this.springSecurityFilterChain = findFilterChainProxy(filters) - } - - override fun afterPropertiesSet() { - springSecurityFilterChain.afterPropertiesSet() - } - - @Throws(IOException::class, ServletException::class) - override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) { - doFilterDelegate.doFilter(request, response, chain) - } - - override fun getFilters(url: String): List { - return springSecurityFilterChain.getFilters(url) - } - - override fun getFilterChains(): List { - return springSecurityFilterChain.filterChains - } - - override fun setSecurityContextHolderStrategy(securityContextHolderStrategy: SecurityContextHolderStrategy) { - springSecurityFilterChain.setSecurityContextHolderStrategy(securityContextHolderStrategy) - } - - override fun setFilterChainValidator(filterChainValidator: FilterChainValidator) { - springSecurityFilterChain.setFilterChainValidator(filterChainValidator) - } - - override fun setFilterChainDecorator(filterChainDecorator: FilterChainDecorator) { - springSecurityFilterChain.setFilterChainDecorator(filterChainDecorator) - } - - override fun setFirewall(firewall: HttpFirewall) { - springSecurityFilterChain.setFirewall(firewall) - } - - override fun setRequestRejectedHandler(requestRejectedHandler: RequestRejectedHandler) { - springSecurityFilterChain.setRequestRejectedHandler(requestRejectedHandler) - } - - companion object { - private fun createDoFilterDelegate(filters: List): Filter { - val delegate: CompositeFilter = CompositeFilter() - delegate.setFilters(filters) - return delegate - } - - private fun findFilterChainProxy(filters: List): FilterChainProxy { - for (filter in filters) { - if (filter is FilterChainProxy) { - return filter - } - if (filter is DebugFilter) { - return filter.filterChainProxy - } - } - throw IllegalStateException("Couldn't find FilterChainProxy in $filters") - } - } - } -} - -@ConfigurationProperties("hideout.security.jwt") -@ConditionalOnProperty(name = ["hideout.security.jwt.generate"], havingValue = "") -data class JwkConfig( - val keyId: String, - val publicKey: String, - val privateKey: String, -) - -@Configuration -class PostSecurityConfig( - val auth: AuthenticationManagerBuilder, - val daoAuthenticationProvider: DaoAuthenticationProvider, - val httpSignatureAuthenticationProvider: PreAuthenticatedAuthenticationProvider, -) { - - @PostConstruct - fun config() { - auth.authenticationProvider(daoAuthenticationProvider) - auth.authenticationProvider(httpSignatureAuthenticationProvider) - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SpringConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SpringConfig.kt deleted file mode 100644 index 8f1b97ce..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SpringConfig.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty -import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.web.filter.CommonsRequestLoggingFilter -import java.net.URL - -@Configuration -class SpringConfig { - - @Autowired - lateinit var config: ApplicationConfig - - @Bean - fun requestLoggingFilter(): CommonsRequestLoggingFilter { - val loggingFilter = CommonsRequestLoggingFilter() - loggingFilter.setIncludeHeaders(true) - loggingFilter.setIncludeClientInfo(true) - loggingFilter.setIncludeQueryString(true) - loggingFilter.setIncludePayload(true) - loggingFilter.setMaxPayloadLength(64000) - return loggingFilter - } -} - -@ConfigurationProperties("hideout") -data class ApplicationConfig( - val url: URL, - val private: Boolean = true, -) - -@ConfigurationProperties("hideout.storage.s3") -@ConditionalOnProperty("hideout.storage.type", havingValue = "s3") -data class S3StorageConfig( - val endpoint: String, - val publicUrl: String, - val bucket: String, - val region: String, - val accessKey: String, - val secretKey: String -) - -/** - * メディアの保存にローカルファイルシステムを使用する際のコンフィグ - * - * @property path フォゾンする場所へのパス。 /から始めると絶対パスとなります。 - * @property publicUrl 公開用URL 省略可能 指定するとHideoutがファイルを配信しなくなります。 - */ -@ConfigurationProperties("hideout.storage.local") -@ConditionalOnProperty("hideout.storage.type", havingValue = "local", matchIfMissing = true) -data class LocalStorageConfig( - val path: String = "files", - val publicUrl: String? -) - -@ConfigurationProperties("hideout.character-limit") -data class CharacterLimit( - val general: General = General(), - val post: Post = Post(), - val account: Account = Account(), - val instance: Instance = Instance() -) { - - data class General( - val url: Int = 1000, - val domain: Int = 1000, - val publicKey: Int = 10000, - val privateKey: Int = 10000 - ) - - data class Post( - val text: Int = 3000, - val overview: Int = 3000 - ) - - data class Account( - val id: Int = 300, - val name: Int = 300, - val description: Int = 10000 - ) - - data class Instance( - val name: Int = 600, - val description: Int = 10000 - ) -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/external/OwlProducerRunner.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/external/OwlProducerRunner.kt deleted file mode 100644 index 5df20246..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/external/OwlProducerRunner.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.external - -import dev.usbharu.owl.common.task.TaskDefinition -import dev.usbharu.owl.producer.api.OwlProducer -import kotlinx.coroutines.runBlocking -import org.springframework.beans.factory.DisposableBean -import org.springframework.boot.ApplicationArguments -import org.springframework.boot.ApplicationRunner -import org.springframework.stereotype.Component - -@Component -class OwlProducerRunner(private val owlProducer: OwlProducer, private val taskDefinitions: List>) : - ApplicationRunner, DisposableBean { - override fun run(args: ApplicationArguments?) { - runBlocking { - owlProducer.start() - taskDefinitions.forEach { taskDefinition -> owlProducer.registerTask(taskDefinition) } - } - } - - override fun destroy() { - runBlocking { - owlProducer.stop() - } - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedPaginationExtension.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedPaginationExtension.kt deleted file mode 100644 index 1f8dad8a..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedPaginationExtension.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.infrastructure.exposed - -import org.jetbrains.exposed.sql.* - -fun Query.withPagination(page: Page, exp: ExpressionWithColumnType): PaginationList { - page.limit?.let { limit(it) } - val resultRows = if (page.minId != null) { - page.maxId?.let { it: Long -> andWhere { exp.less(it) } } - andWhere { exp.greater(page.minId!!) } - reversed() - } else { - page.maxId?.let { andWhere { exp.less(it) } } - page.sinceId?.let { andWhere { exp.greater(it) } } - orderBy(exp, SortOrder.DESC) - toList() - } - - return PaginationList(resultRows, resultRows.firstOrNull()?.getOrNull(exp), resultRows.lastOrNull()?.getOrNull(exp)) -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/Page.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/Page.kt deleted file mode 100644 index c6178261..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/Page.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.infrastructure.exposed - -sealed class Page { - abstract val maxId: Long? - abstract val sinceId: Long? - abstract val minId: Long? - abstract val limit: Int? - - data class PageByMaxId( - override val maxId: Long?, - override val sinceId: Long?, - override val limit: Int? - ) : Page() { - override val minId: Long? = null - } - - data class PageByMinId( - override val maxId: Long?, - override val minId: Long?, - override val limit: Int? - ) : Page() { - override val sinceId: Long? = null - } - - companion object { - @Suppress("FunctionMinLength") - fun of( - maxId: Long? = null, - sinceId: Long? = null, - minId: Long? = null, - limit: Int? = null - ): Page = - if (minId != null) { - PageByMinId( - maxId, - minId, - limit - ) - } else { - PageByMaxId( - maxId, - sinceId, - limit - ) - } - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PaginationList.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PaginationList.kt deleted file mode 100644 index d796e48c..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PaginationList.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.infrastructure.exposed - -class PaginationList(list: List, val next: ID?, val prev: ID?) : List by list - -fun PaginationList.toHttpHeader( - nextBlock: (string: String) -> String, - prevBlock: (string: String) -> String -): String? { - val mutableListOf = mutableListOf() - if (next != null) { - mutableListOf.add("<${nextBlock(this.next.toString())}>; rel=\"next\"") - } - if (prev != null) { - mutableListOf.add("<${prevBlock(this.prev.toString())}>; rel=\"prev\"") - } - - if (mutableListOf.isEmpty()) { - return null - } - - return mutableListOf.joinToString(", ") -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/springframework/RoleHierarchyAuthorizationManagerFactory.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/springframework/RoleHierarchyAuthorizationManagerFactory.kt deleted file mode 100644 index 99976547..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/springframework/RoleHierarchyAuthorizationManagerFactory.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.infrastructure.springframework - -import org.springframework.security.access.hierarchicalroles.RoleHierarchy -import org.springframework.security.authorization.AuthorityAuthorizationManager -import org.springframework.security.authorization.AuthorizationManager -import org.springframework.security.web.access.intercept.RequestAuthorizationContext -import org.springframework.stereotype.Component - -@Component -class RoleHierarchyAuthorizationManagerFactory(private val roleHierarchy: RoleHierarchy) { - fun hasScope(role: String): AuthorizationManager { - val hasAuthority = AuthorityAuthorizationManager.hasAuthority("SCOPE_$role") - hasAuthority.setRoleHierarchy(roleHierarchy) - return hasAuthority - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt index f924330e..e52af918 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt @@ -17,7 +17,6 @@ package dev.usbharu.hideout.core.application.actor import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.application.service.id.IdGenerateService import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.domain.model.actor.ActorRepository import dev.usbharu.hideout.core.domain.model.instance.InstanceRepository @@ -26,6 +25,7 @@ import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository import dev.usbharu.hideout.core.domain.service.actor.local.LocalActorDomainService import dev.usbharu.hideout.core.domain.service.userdetail.UserDetailDomainService +import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import dev.usbharu.hideout.core.infrastructure.factory.ActorFactoryImpl import org.springframework.stereotype.Service diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HtmlSanitizeConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/HtmlSanitizeConfig.kt similarity index 96% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HtmlSanitizeConfig.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/HtmlSanitizeConfig.kt index 10d5b076..e55bc8fe 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/HtmlSanitizeConfig.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/HtmlSanitizeConfig.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package dev.usbharu.hideout.application.config +package dev.usbharu.hideout.core.config import org.owasp.html.HtmlPolicyBuilder import org.owasp.html.PolicyFactory diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostContentFormatter.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/post/DefaultPostContentFormatter.kt similarity index 94% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostContentFormatter.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/post/DefaultPostContentFormatter.kt index 5819c47b..9054f12b 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostContentFormatter.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/post/DefaultPostContentFormatter.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package dev.usbharu.hideout.core.service.post +package dev.usbharu.hideout.core.domain.service.post import org.jsoup.Jsoup import org.jsoup.nodes.Document @@ -24,11 +24,6 @@ import org.jsoup.select.Elements import org.owasp.html.PolicyFactory import org.springframework.stereotype.Service - -interface PostContentFormatter { - fun format(content: String): FormattedPostContent -} - @Service class DefaultPostContentFormatter(private val policyFactory: PolicyFactory) : PostContentFormatter { override fun format(content: String): FormattedPostContent { @@ -101,9 +96,4 @@ class DefaultPostContentFormatter(private val policyFactory: PolicyFactory) : Po } } } -} - -data class FormattedPostContent( - val html: String, - val content: String, -) \ No newline at end of file +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/security/LoginUserContextHolder.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/post/PostContentFormatter.kt similarity index 73% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/security/LoginUserContextHolder.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/post/PostContentFormatter.kt index fc6a3c42..a0004b39 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/security/LoginUserContextHolder.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/post/PostContentFormatter.kt @@ -14,10 +14,14 @@ * limitations under the License. */ -package dev.usbharu.hideout.core.infrastructure.springframework.security +package dev.usbharu.hideout.core.domain.service.post -interface LoginUserContextHolder { - fun getLoginUserId(): Long - fun getLoginUserIdOrNull(): Long? +interface PostContentFormatter { + fun format(content: String): FormattedPostContent } + +data class FormattedPostContent( + val html: String, + val content: String, +) \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/IdGenerateService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/shared/id/IdGenerateService.kt similarity index 86% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/IdGenerateService.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/shared/id/IdGenerateService.kt index ef2686e8..91991d71 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/IdGenerateService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/shared/id/IdGenerateService.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -package dev.usbharu.hideout.application.service.id +package dev.usbharu.hideout.core.domain.shared.id -import org.springframework.stereotype.Service - -@Service interface IdGenerateService { suspend fun generateId(): Long } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorQueryMapper.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorQueryMapper.kt index f1c99847..8b8e46e8 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorQueryMapper.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorQueryMapper.kt @@ -16,8 +16,6 @@ package dev.usbharu.hideout.core.infrastructure.exposed -import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper -import dev.usbharu.hideout.application.infrastructure.exposed.ResultRowMapper import dev.usbharu.hideout.core.domain.model.actor.Actor import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorResultRowMapper.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorResultRowMapper.kt index a75c148d..639bd216 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorResultRowMapper.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorResultRowMapper.kt @@ -16,7 +16,6 @@ package dev.usbharu.hideout.core.infrastructure.exposed -import dev.usbharu.hideout.application.infrastructure.exposed.ResultRowMapper import dev.usbharu.hideout.core.domain.model.actor.* import dev.usbharu.hideout.core.domain.model.emoji.EmojiId import dev.usbharu.hideout.core.domain.model.instance.InstanceId diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedTransaction.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ExposedTransaction.kt similarity index 78% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedTransaction.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ExposedTransaction.kt index 8e380cb6..7dc419f3 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedTransaction.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ExposedTransaction.kt @@ -14,28 +14,27 @@ * limitations under the License. */ -package dev.usbharu.hideout.application.infrastructure.exposed +package dev.usbharu.hideout.core.infrastructure.exposed import dev.usbharu.hideout.core.application.shared.Transaction -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.slf4j.MDCContext import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger import org.jetbrains.exposed.sql.addLogger import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.transactions.transaction -import org.springframework.stereotype.Service +import org.springframework.stereotype.Component import java.sql.Connection -@Service +@Component class ExposedTransaction : Transaction { override suspend fun transaction(block: suspend () -> T): T { - return transaction(transactionIsolation = Connection.TRANSACTION_READ_COMMITTED) { + return newSuspendedTransaction( + transactionIsolation = Connection.TRANSACTION_READ_COMMITTED, + context = MDCContext() + ) { debug = true warnLongQueriesDuration = 1000 addLogger(Slf4jSqlDebugLogger) - runBlocking(MDCContext()) { - block() - } + block() } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/QueryMapper.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/QueryMapper.kt similarity index 91% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/QueryMapper.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/QueryMapper.kt index 078fdd65..a817b9b2 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/QueryMapper.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/QueryMapper.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package dev.usbharu.hideout.application.infrastructure.exposed +package dev.usbharu.hideout.core.infrastructure.exposed import org.jetbrains.exposed.sql.Query diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ResultRowMapper.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ResultRowMapper.kt similarity index 91% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ResultRowMapper.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ResultRowMapper.kt index cc7737ff..7f4b3261 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ResultRowMapper.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ResultRowMapper.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package dev.usbharu.hideout.application.infrastructure.exposed +package dev.usbharu.hideout.core.infrastructure.exposed import org.jetbrains.exposed.sql.ResultRow diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt index 466cf138..9b16788f 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt @@ -1,10 +1,10 @@ package dev.usbharu.hideout.core.infrastructure.exposedrepository -import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper import dev.usbharu.hideout.core.domain.model.actor.* import dev.usbharu.hideout.core.domain.model.shared.Domain import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher import dev.usbharu.hideout.core.domain.shared.repository.DomainEventPublishableRepository +import dev.usbharu.hideout.core.infrastructure.exposed.QueryMapper import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.javatime.timestamp diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/ActorFactoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/ActorFactoryImpl.kt index 1273b68c..3e610e53 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/ActorFactoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/ActorFactoryImpl.kt @@ -17,10 +17,10 @@ package dev.usbharu.hideout.core.infrastructure.factory import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.application.service.id.IdGenerateService import dev.usbharu.hideout.core.domain.model.actor.* import dev.usbharu.hideout.core.domain.model.instance.InstanceId import dev.usbharu.hideout.core.domain.model.shared.Domain +import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import org.springframework.stereotype.Component import java.net.URI import java.time.Instant diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostContentFactoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostContentFactoryImpl.kt index b901f6a6..7a18fa29 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostContentFactoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostContentFactoryImpl.kt @@ -17,7 +17,7 @@ package dev.usbharu.hideout.core.infrastructure.factory import dev.usbharu.hideout.core.domain.model.post.PostContent -import dev.usbharu.hideout.core.service.post.PostContentFormatter +import dev.usbharu.hideout.core.domain.service.post.PostContentFormatter import org.springframework.stereotype.Component @Component diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostFactoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostFactoryImpl.kt index f28dd0d1..822035d9 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostFactoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostFactoryImpl.kt @@ -17,7 +17,6 @@ package dev.usbharu.hideout.core.infrastructure.factory import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.application.service.id.IdGenerateService import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.domain.model.actor.ActorName import dev.usbharu.hideout.core.domain.model.media.MediaId @@ -25,6 +24,7 @@ import dev.usbharu.hideout.core.domain.model.post.Post import dev.usbharu.hideout.core.domain.model.post.PostId import dev.usbharu.hideout.core.domain.model.post.PostOverview import dev.usbharu.hideout.core.domain.model.post.Visibility +import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import org.springframework.stereotype.Component import java.net.URI import java.time.Instant diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/httpsignature/HttpRequestMixIn.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/httpsignature/HttpRequestMixIn.kt deleted file mode 100644 index 5219c983..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/httpsignature/HttpRequestMixIn.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.httpsignature - -import com.fasterxml.jackson.annotation.JsonSubTypes -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.databind.DeserializationContext -import com.fasterxml.jackson.databind.JsonDeserializer -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import dev.usbharu.httpsignature.common.HttpHeaders -import dev.usbharu.httpsignature.common.HttpMethod -import dev.usbharu.httpsignature.common.HttpRequest -import java.net.URL - -@JsonDeserialize(using = HttpRequestDeserializer::class) -@JsonSubTypes -@Suppress("UnnecessaryAbstractClass") -abstract class HttpRequestMixIn - -class HttpRequestDeserializer : JsonDeserializer() { - override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): HttpRequest { - val readTree: JsonNode = p.codec.readTree(p) - - return HttpRequest( - URL(readTree["url"].textValue()), - HttpHeaders(emptyMap()), - HttpMethod.valueOf(readTree["method"].textValue()) - ) - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/SnowflakeIdGenerateService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/other/SnowflakeIdGenerateService.kt similarity index 92% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/SnowflakeIdGenerateService.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/other/SnowflakeIdGenerateService.kt index d0748acb..3b82b1cc 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/SnowflakeIdGenerateService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/other/SnowflakeIdGenerateService.kt @@ -14,15 +14,16 @@ * limitations under the License. */ -package dev.usbharu.hideout.application.service.id +package dev.usbharu.hideout.core.infrastructure.other +import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import kotlinx.coroutines.delay import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import java.time.Instant @Suppress("MagicNumber") -class SnowflakeIdGenerateService(private val baseTime: Long) : IdGenerateService { +open class SnowflakeIdGenerateService(private val baseTime: Long) : IdGenerateService { var lastTimeStamp: Long = -1 var sequenceId: Int = 0 val mutex = Mutex() diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/TwitterSnowflakeIdGenerateService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/other/TwitterSnowflakeIdGenerateService.kt similarity index 94% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/TwitterSnowflakeIdGenerateService.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/other/TwitterSnowflakeIdGenerateService.kt index a23d92d5..dcefc995 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/id/TwitterSnowflakeIdGenerateService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/other/TwitterSnowflakeIdGenerateService.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package dev.usbharu.hideout.application.service.id +package dev.usbharu.hideout.core.infrastructure.other import org.springframework.context.annotation.Primary import org.springframework.stereotype.Service diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/ExposedOAuth2AuthorizationConsentService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/ExposedOAuth2AuthorizationConsentService.kt deleted file mode 100644 index 7c5126e9..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/ExposedOAuth2AuthorizationConsentService.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.oauth2 - -import dev.usbharu.hideout.core.application.shared.Transaction -import kotlinx.coroutines.runBlocking -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.springframework.security.core.authority.SimpleGrantedAuthority -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService -import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository -import org.springframework.stereotype.Service -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent as AuthorizationConsent - -@Service -class ExposedOAuth2AuthorizationConsentService( - private val registeredClientRepository: RegisteredClientRepository, - private val transaction: Transaction, -) : - OAuth2AuthorizationConsentService { - - override fun save(authorizationConsent: AuthorizationConsent?): Unit = runBlocking { - requireNotNull(authorizationConsent) - transaction.transaction { - val singleOrNull = - OAuth2AuthorizationConsent.selectAll().where { - OAuth2AuthorizationConsent.registeredClientId - .eq(authorizationConsent.registeredClientId) - .and(OAuth2AuthorizationConsent.principalName.eq(authorizationConsent.principalName)) - } - .singleOrNull() - if (singleOrNull == null) { - OAuth2AuthorizationConsent.insert { - it[registeredClientId] = authorizationConsent.registeredClientId - it[principalName] = authorizationConsent.principalName - it[authorities] = authorizationConsent.authorities.joinToString(",") - } - } - } - } - - override fun remove(authorizationConsent: AuthorizationConsent?) { - if (authorizationConsent == null) { - return - } - OAuth2AuthorizationConsent.deleteWhere { - registeredClientId eq authorizationConsent.registeredClientId and (principalName eq principalName) - } - } - - override fun findById(registeredClientId: String?, principalName: String?): AuthorizationConsent? = runBlocking { - requireNotNull(registeredClientId) - requireNotNull(principalName) - transaction.transaction { - OAuth2AuthorizationConsent.selectAll().where { - (OAuth2AuthorizationConsent.registeredClientId eq registeredClientId) - .and(OAuth2AuthorizationConsent.principalName eq principalName) - } - .singleOrNull()?.toAuthorizationConsent() - } - } - - fun ResultRow.toAuthorizationConsent(): AuthorizationConsent { - val registeredClientId = this[OAuth2AuthorizationConsent.registeredClientId] - registeredClientRepository.findById(registeredClientId) - - val principalName = this[OAuth2AuthorizationConsent.principalName] - val builder = AuthorizationConsent.withId(registeredClientId, principalName) - - this[OAuth2AuthorizationConsent.authorities].split(",").forEach { - builder.authority(SimpleGrantedAuthority(it)) - } - - return builder.build() - } -} - -object OAuth2AuthorizationConsent : Table("oauth2_authorization_consent") { - val registeredClientId: Column = varchar("registered_client_id", 100) - val principalName: Column = varchar("principal_name", 200) - val authorities: Column = varchar("authorities", 1000) - override val primaryKey: PrimaryKey = PrimaryKey(registeredClientId, principalName) -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/ExposedOAuth2AuthorizationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/ExposedOAuth2AuthorizationService.kt deleted file mode 100644 index b6689829..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/ExposedOAuth2AuthorizationService.kt +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.oauth2 - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.core.application.shared.Transaction -import kotlinx.coroutines.runBlocking -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.javatime.timestamp -import org.springframework.security.jackson2.CoreJackson2Module -import org.springframework.security.jackson2.SecurityJackson2Modules -import org.springframework.security.oauth2.core.* -import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames -import org.springframework.security.oauth2.core.oidc.OidcIdToken -import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames -import org.springframework.security.oauth2.server.authorization.OAuth2Authorization -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService -import org.springframework.security.oauth2.server.authorization.OAuth2TokenType -import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository -import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module -import org.springframework.stereotype.Service -import java.time.Instant - -@Service -class ExposedOAuth2AuthorizationService( - private val registeredClientRepository: RegisteredClientRepository, - private val transaction: Transaction, -) : - OAuth2AuthorizationService { - - @Suppress("LongMethod", "CyclomaticComplexMethod") - override fun save(authorization: OAuth2Authorization?): Unit = runBlocking { - requireNotNull(authorization) - transaction.transaction { - val singleOrNull = Authorization.selectAll().where { Authorization.id eq authorization.id }.singleOrNull() - if (singleOrNull == null) { - val authorizationCodeToken = authorization.getToken(OAuth2AuthorizationCode::class.java) - val accessToken = authorization.getToken(OAuth2AccessToken::class.java) - val refreshToken = authorization.getToken(OAuth2RefreshToken::class.java) - val oidcIdToken = authorization.getToken(OidcIdToken::class.java) - val userCode = authorization.getToken(OAuth2UserCode::class.java) - val deviceCode = authorization.getToken(OAuth2DeviceCode::class.java) - Authorization.insert { - it[id] = authorization.id - it[registeredClientId] = authorization.registeredClientId - it[principalName] = authorization.principalName - it[authorizationGrantType] = authorization.authorizationGrantType.value - it[authorizedScopes] = - authorization.authorizedScopes.joinToString(",").takeIf { s -> s.isNotEmpty() } - it[attributes] = mapToJson(authorization.attributes) - it[state] = authorization.getAttribute(OAuth2ParameterNames.STATE) - it[authorizationCodeValue] = authorizationCodeToken?.token?.tokenValue - it[authorizationCodeIssuedAt] = authorizationCodeToken?.token?.issuedAt - it[authorizationCodeExpiresAt] = authorizationCodeToken?.token?.expiresAt - it[authorizationCodeMetadata] = - authorizationCodeToken?.metadata?.let { it1 -> mapToJson(it1) } - it[accessTokenValue] = accessToken?.token?.tokenValue - it[accessTokenIssuedAt] = accessToken?.token?.issuedAt - it[accessTokenExpiresAt] = accessToken?.token?.expiresAt - it[accessTokenMetadata] = accessToken?.metadata?.let { it1 -> mapToJson(it1) } - it[accessTokenType] = accessToken?.token?.tokenType?.value - it[accessTokenScopes] = - accessToken?.run { token.scopes.joinToString(",").takeIf { s -> s.isNotEmpty() } } - it[refreshTokenValue] = refreshToken?.token?.tokenValue - it[refreshTokenIssuedAt] = refreshToken?.token?.issuedAt - it[refreshTokenExpiresAt] = refreshToken?.token?.expiresAt - it[refreshTokenMetadata] = refreshToken?.metadata?.let { it1 -> mapToJson(it1) } - it[oidcIdTokenValue] = oidcIdToken?.token?.tokenValue - it[oidcIdTokenIssuedAt] = oidcIdToken?.token?.issuedAt - it[oidcIdTokenExpiresAt] = oidcIdToken?.token?.expiresAt - it[oidcIdTokenMetadata] = oidcIdToken?.metadata?.let { it1 -> mapToJson(it1) } - it[userCodeValue] = userCode?.token?.tokenValue - it[userCodeIssuedAt] = userCode?.token?.issuedAt - it[userCodeExpiresAt] = userCode?.token?.expiresAt - it[userCodeMetadata] = userCode?.metadata?.let { it1 -> mapToJson(it1) } - it[deviceCodeValue] = deviceCode?.token?.tokenValue - it[deviceCodeIssuedAt] = deviceCode?.token?.issuedAt - it[deviceCodeExpiresAt] = deviceCode?.token?.expiresAt - it[deviceCodeMetadata] = deviceCode?.metadata?.let { it1 -> mapToJson(it1) } - } - } else { - val authorizationCodeToken = authorization.getToken(OAuth2AuthorizationCode::class.java) - val accessToken = authorization.getToken(OAuth2AccessToken::class.java) - val refreshToken = authorization.getToken(OAuth2RefreshToken::class.java) - val oidcIdToken = authorization.getToken(OidcIdToken::class.java) - val userCode = authorization.getToken(OAuth2UserCode::class.java) - val deviceCode = authorization.getToken(OAuth2DeviceCode::class.java) - Authorization.update({ Authorization.id eq authorization.id }) { - it[registeredClientId] = authorization.registeredClientId - it[principalName] = authorization.principalName - it[authorizationGrantType] = authorization.authorizationGrantType.value - it[authorizedScopes] = - authorization.authorizedScopes.joinToString(",").takeIf { s -> s.isNotEmpty() } - it[attributes] = mapToJson(authorization.attributes) - it[state] = authorization.getAttribute(OAuth2ParameterNames.STATE) - it[authorizationCodeValue] = authorizationCodeToken?.token?.tokenValue - it[authorizationCodeIssuedAt] = authorizationCodeToken?.token?.issuedAt - it[authorizationCodeExpiresAt] = authorizationCodeToken?.token?.expiresAt - it[authorizationCodeMetadata] = - authorizationCodeToken?.metadata?.let { it1 -> mapToJson(it1) } - it[accessTokenValue] = accessToken?.token?.tokenValue - it[accessTokenIssuedAt] = accessToken?.token?.issuedAt - it[accessTokenExpiresAt] = accessToken?.token?.expiresAt - it[accessTokenMetadata] = accessToken?.metadata?.let { it1 -> mapToJson(it1) } - it[accessTokenType] = accessToken?.run { token.tokenType.value } - it[accessTokenScopes] = - accessToken?.run { token.scopes.joinToString(",").takeIf { s -> s.isNotEmpty() } } - it[refreshTokenValue] = refreshToken?.token?.tokenValue - it[refreshTokenIssuedAt] = refreshToken?.token?.issuedAt - it[refreshTokenExpiresAt] = refreshToken?.token?.expiresAt - it[refreshTokenMetadata] = refreshToken?.metadata?.let { it1 -> mapToJson(it1) } - it[oidcIdTokenValue] = oidcIdToken?.token?.tokenValue - it[oidcIdTokenIssuedAt] = oidcIdToken?.token?.issuedAt - it[oidcIdTokenExpiresAt] = oidcIdToken?.token?.expiresAt - it[oidcIdTokenMetadata] = oidcIdToken?.metadata?.let { it1 -> mapToJson(it1) } - it[userCodeValue] = userCode?.token?.tokenValue - it[userCodeIssuedAt] = userCode?.token?.issuedAt - it[userCodeExpiresAt] = userCode?.token?.expiresAt - it[userCodeMetadata] = userCode?.metadata?.let { it1 -> mapToJson(it1) } - it[deviceCodeValue] = deviceCode?.token?.tokenValue - it[deviceCodeIssuedAt] = deviceCode?.token?.issuedAt - it[deviceCodeExpiresAt] = deviceCode?.token?.expiresAt - it[deviceCodeMetadata] = deviceCode?.metadata?.let { it1 -> mapToJson(it1) } - } - } - } - } - - override fun remove(authorization: OAuth2Authorization?) { - if (authorization == null) { - return - } - Authorization.deleteWhere { id eq authorization.id } - } - - override fun findById(id: String?): OAuth2Authorization? { - if (id == null) { - return null - } - return Authorization.selectAll().where { Authorization.id eq id }.singleOrNull()?.toAuthorization() - } - - override fun findByToken(token: String?, tokenType: OAuth2TokenType?): OAuth2Authorization? = runBlocking { - requireNotNull(token) - transaction.transaction { - when (tokenType?.value) { - null -> { - Authorization.selectAll().where { Authorization.authorizationCodeValue eq token }.orWhere { - Authorization.accessTokenValue eq token - }.orWhere { - Authorization.oidcIdTokenValue eq token - }.orWhere { - Authorization.refreshTokenValue eq token - }.orWhere { - Authorization.userCodeValue eq token - }.orWhere { - Authorization.deviceCodeValue eq token - } - } - - OAuth2ParameterNames.STATE -> { - Authorization.selectAll().where { Authorization.state eq token } - } - - OAuth2ParameterNames.CODE -> { - Authorization.selectAll().where { Authorization.authorizationCodeValue eq token } - } - - OAuth2ParameterNames.ACCESS_TOKEN -> { - Authorization.selectAll().where { Authorization.accessTokenValue eq token } - } - - OidcParameterNames.ID_TOKEN -> { - Authorization.selectAll().where { Authorization.oidcIdTokenValue eq token } - } - - OAuth2ParameterNames.REFRESH_TOKEN -> { - Authorization.selectAll().where { Authorization.refreshTokenValue eq token } - } - - OAuth2ParameterNames.USER_CODE -> { - Authorization.selectAll().where { Authorization.userCodeValue eq token } - } - - OAuth2ParameterNames.DEVICE_CODE -> { - Authorization.selectAll().where { Authorization.deviceCodeValue eq token } - } - - else -> { - null - } - }?.singleOrNull()?.toAuthorization() - } - } - - @Suppress("LongMethod", "CyclomaticComplexMethod", "CastToNullableType", "UNCHECKED_CAST") - fun ResultRow.toAuthorization(): OAuth2Authorization { - val registeredClientId = this[Authorization.registeredClientId] - - val registeredClient = registeredClientRepository.findById(registeredClientId) - - val builder = OAuth2Authorization.withRegisteredClient(registeredClient) - val id = this[Authorization.id] - val principalName = this[Authorization.principalName] - val authorizationGrantType = this[Authorization.authorizationGrantType] - val authorizedScopes = this[Authorization.authorizedScopes]?.split(",").orEmpty().toSet() - val attributes = this[Authorization.attributes]?.let { jsonToMap(it) }.orEmpty() - - builder.id(id).principalName(principalName) - .authorizationGrantType(AuthorizationGrantType(authorizationGrantType)).authorizedScopes(authorizedScopes) - .attributes { it.putAll(attributes) } - - val state = this[Authorization.state].orEmpty() - if (state.isNotBlank()) { - builder.attribute(OAuth2ParameterNames.STATE, state) - } - - val authorizationCodeValue = this[Authorization.authorizationCodeValue].orEmpty() - if (authorizationCodeValue.isNotBlank()) { - val authorizationCodeIssuedAt = this[Authorization.authorizationCodeIssuedAt] - val authorizationCodeExpiresAt = this[Authorization.authorizationCodeExpiresAt] - val authorizationCodeMetadata = this[Authorization.authorizationCodeMetadata]?.let { - jsonToMap( - it - ) - }.orEmpty() - val oAuth2AuthorizationCode = - OAuth2AuthorizationCode(authorizationCodeValue, authorizationCodeIssuedAt, authorizationCodeExpiresAt) - builder.token(oAuth2AuthorizationCode) { - it.putAll(authorizationCodeMetadata) - } - } - - val accessTokenValue = this[Authorization.accessTokenValue].orEmpty() - if (accessTokenValue.isNotBlank()) { - val accessTokenIssuedAt = this[Authorization.accessTokenIssuedAt] - val accessTokenExpiresAt = this[Authorization.accessTokenExpiresAt] - val accessTokenMetadata = - this[Authorization.accessTokenMetadata]?.let { jsonToMap(it) }.orEmpty() - val accessTokenType = - if (this[Authorization.accessTokenType].equals(OAuth2AccessToken.TokenType.BEARER.value, true)) { - OAuth2AccessToken.TokenType.BEARER - } else { - null - } - - val accessTokenScope = this[Authorization.accessTokenScopes]?.split(",").orEmpty().toSet() - - val oAuth2AccessToken = OAuth2AccessToken( - accessTokenType, - accessTokenValue, - accessTokenIssuedAt, - accessTokenExpiresAt, - accessTokenScope - ) - - builder.token(oAuth2AccessToken) { it.putAll(accessTokenMetadata) } - } - - val oidcIdTokenValue = this[Authorization.oidcIdTokenValue].orEmpty() - if (oidcIdTokenValue.isNotBlank()) { - val oidcTokenIssuedAt = this[Authorization.oidcIdTokenIssuedAt] - val oidcTokenExpiresAt = this[Authorization.oidcIdTokenExpiresAt] - val oidcTokenMetadata = - this[Authorization.oidcIdTokenMetadata]?.let { jsonToMap(it) }.orEmpty() - - val oidcIdToken = OidcIdToken( - oidcIdTokenValue, - oidcTokenIssuedAt, - oidcTokenExpiresAt, - oidcTokenMetadata.getValue(OAuth2Authorization.Token.CLAIMS_METADATA_NAME) - as MutableMap? - ) - - builder.token(oidcIdToken) { it.putAll(oidcTokenMetadata) } - } - - val refreshTokenValue = this[Authorization.refreshTokenValue].orEmpty() - if (refreshTokenValue.isNotBlank()) { - val refreshTokenIssuedAt = this[Authorization.refreshTokenIssuedAt] - val refreshTokenExpiresAt = this[Authorization.refreshTokenExpiresAt] - val refreshTokenMetadata = - this[Authorization.refreshTokenMetadata]?.let { jsonToMap(it) }.orEmpty() - - val oAuth2RefreshToken = OAuth2RefreshToken(refreshTokenValue, refreshTokenIssuedAt, refreshTokenExpiresAt) - - builder.token(oAuth2RefreshToken) { it.putAll(refreshTokenMetadata) } - } - - val userCodeValue = this[Authorization.userCodeValue].orEmpty() - if (userCodeValue.isNotBlank()) { - val userCodeIssuedAt = this[Authorization.userCodeIssuedAt] - val userCodeExpiresAt = this[Authorization.userCodeExpiresAt] - val userCodeMetadata = - this[Authorization.userCodeMetadata]?.let { jsonToMap(it) }.orEmpty() - val oAuth2UserCode = OAuth2UserCode(userCodeValue, userCodeIssuedAt, userCodeExpiresAt) - builder.token(oAuth2UserCode) { it.putAll(userCodeMetadata) } - } - - val deviceCodeValue = this[Authorization.deviceCodeValue].orEmpty() - if (deviceCodeValue.isNotBlank()) { - val deviceCodeIssuedAt = this[Authorization.deviceCodeIssuedAt] - val deviceCodeExpiresAt = this[Authorization.deviceCodeExpiresAt] - val deviceCodeMetadata = - this[Authorization.deviceCodeMetadata]?.let { jsonToMap(it) }.orEmpty() - - val oAuth2DeviceCode = OAuth2DeviceCode(deviceCodeValue, deviceCodeIssuedAt, deviceCodeExpiresAt) - builder.token(oAuth2DeviceCode) { it.putAll(deviceCodeMetadata) } - } - - return builder.build() - } - - private fun mapToJson(map: Map<*, *>): String = objectMapper.writeValueAsString(map) - - private fun jsonToMap(json: String): Map = objectMapper.readValue(json) - - companion object { - val objectMapper: ObjectMapper = ObjectMapper() - - init { - - val classLoader = ExposedOAuth2AuthorizationService::class.java.classLoader - val modules = SecurityJackson2Modules.getModules(classLoader) - objectMapper.registerModules(JavaTimeModule()) - objectMapper.registerModules(modules) - objectMapper.registerModules(OAuth2AuthorizationServerJackson2Module()) - objectMapper.registerModules(CoreJackson2Module()) - objectMapper.addMixIn(UserDetailsImpl::class.java, UserDetailsMixin::class.java) - } - } -} - -object Authorization : Table("application_authorization") { - val id: Column = varchar("id", 255) - val registeredClientId: Column = varchar("registered_client_id", 255) - val principalName: Column = varchar("principal_name", 255) - val authorizationGrantType: Column = varchar("authorization_grant_type", 255) - val authorizedScopes: Column = varchar("authorized_scopes", 1000).nullable().default(null) - val attributes: Column = varchar("attributes", 4000).nullable().default(null) - val state: Column = varchar("state", 500).nullable().default(null) - val authorizationCodeValue: Column = varchar("authorization_code_value", 4000).nullable().default(null) - val authorizationCodeIssuedAt: Column = timestamp("authorization_code_issued_at").nullable().default(null) - val authorizationCodeExpiresAt: Column = timestamp("authorization_code_expires_at").nullable().default( - null - ) - val authorizationCodeMetadata: Column = varchar("authorization_code_metadata", 2000).nullable().default( - null - ) - val accessTokenValue: Column = varchar("access_token_value", 4000).nullable().default(null) - val accessTokenIssuedAt: Column = timestamp("access_token_issued_at").nullable().default(null) - val accessTokenExpiresAt: Column = timestamp("access_token_expires_at").nullable().default(null) - val accessTokenMetadata: Column = varchar("access_token_metadata", 2000).nullable().default(null) - val accessTokenType: Column = varchar("access_token_type", 255).nullable().default(null) - val accessTokenScopes: Column = varchar("access_token_scopes", 1000).nullable().default(null) - val refreshTokenValue: Column = varchar("refresh_token_value", 4000).nullable().default(null) - val refreshTokenIssuedAt: Column = timestamp("refresh_token_issued_at").nullable().default(null) - val refreshTokenExpiresAt: Column = timestamp("refresh_token_expires_at").nullable().default(null) - val refreshTokenMetadata: Column = varchar("refresh_token_metadata", 2000).nullable().default(null) - val oidcIdTokenValue: Column = varchar("oidc_id_token_value", 4000).nullable().default(null) - val oidcIdTokenIssuedAt: Column = timestamp("oidc_id_token_issued_at").nullable().default(null) - val oidcIdTokenExpiresAt: Column = timestamp("oidc_id_token_expires_at").nullable().default(null) - val oidcIdTokenMetadata: Column = varchar("oidc_id_token_metadata", 2000).nullable().default(null) - val oidcIdTokenClaims: Column = varchar("oidc_id_token_claims", 2000).nullable().default(null) - val userCodeValue: Column = varchar("user_code_value", 4000).nullable().default(null) - val userCodeIssuedAt: Column = timestamp("user_code_issued_at").nullable().default(null) - val userCodeExpiresAt: Column = timestamp("user_code_expires_at").nullable().default(null) - val userCodeMetadata: Column = varchar("user_code_metadata", 2000).nullable().default(null) - val deviceCodeValue: Column = varchar("device_code_value", 4000).nullable().default(null) - val deviceCodeIssuedAt: Column = timestamp("device_code_issued_at").nullable().default(null) - val deviceCodeExpiresAt: Column = timestamp("device_code_expires_at").nullable().default(null) - val deviceCodeMetadata: Column = varchar("device_code_metadata", 2000).nullable().default(null) - - override val primaryKey: PrimaryKey = PrimaryKey(id) -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/RegisteredClientRepositoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/RegisteredClientRepositoryImpl.kt deleted file mode 100644 index 68a3177d..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/RegisteredClientRepositoryImpl.kt +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.oauth2 - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.RegisteredClient.clientId -import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.RegisteredClient.clientSettings -import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.RegisteredClient.tokenSettings -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.javatime.CurrentTimestamp -import org.jetbrains.exposed.sql.javatime.timestamp -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.security.jackson2.SecurityJackson2Modules -import org.springframework.security.oauth2.core.AuthorizationGrantType -import org.springframework.security.oauth2.core.ClientAuthenticationMethod -import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository -import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module -import org.springframework.security.oauth2.server.authorization.settings.ClientSettings -import org.springframework.security.oauth2.server.authorization.settings.ConfigurationSettingNames -import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat -import org.springframework.security.oauth2.server.authorization.settings.TokenSettings -import org.springframework.stereotype.Repository -import org.springframework.transaction.annotation.Transactional -import java.time.Instant -import org.springframework.security.oauth2.server.authorization.client.RegisteredClient as SpringRegisteredClient - -@Repository -class RegisteredClientRepositoryImpl : RegisteredClientRepository { - - override fun save(registeredClient: SpringRegisteredClient?) { - requireNotNull(registeredClient) - val singleOrNull = - RegisteredClient.selectAll().where { RegisteredClient.id eq registeredClient.id }.singleOrNull() - if (singleOrNull == null) { - RegisteredClient.insert { - it[id] = registeredClient.id - it[clientId] = registeredClient.clientId - it[clientIdIssuedAt] = registeredClient.clientIdIssuedAt ?: Instant.now() - it[clientSecret] = registeredClient.clientSecret - it[clientSecretExpiresAt] = registeredClient.clientSecretExpiresAt - it[clientName] = registeredClient.clientName - it[clientAuthenticationMethods] = - registeredClient.clientAuthenticationMethods.joinToString(",") { method -> method.value } - it[authorizationGrantTypes] = - registeredClient.authorizationGrantTypes.joinToString(",") { type -> type.value } - it[redirectUris] = registeredClient.redirectUris.joinToString(",") - it[postLogoutRedirectUris] = registeredClient.postLogoutRedirectUris.joinToString(",") - it[scopes] = registeredClient.scopes.joinToString(",") - it[clientSettings] = mapToJson(registeredClient.clientSettings.settings) - it[tokenSettings] = mapToJson(registeredClient.tokenSettings.settings) - } - } else { - RegisteredClient.update({ RegisteredClient.id eq registeredClient.id }) { - it[clientId] = registeredClient.clientId - it[clientIdIssuedAt] = registeredClient.clientIdIssuedAt ?: Instant.now() - it[clientSecret] = registeredClient.clientSecret - it[clientSecretExpiresAt] = registeredClient.clientSecretExpiresAt - it[clientName] = registeredClient.clientName - it[clientAuthenticationMethods] = registeredClient.clientAuthenticationMethods.joinToString(",") - it[authorizationGrantTypes] = registeredClient.authorizationGrantTypes.joinToString(",") - it[redirectUris] = registeredClient.redirectUris.joinToString(",") - it[postLogoutRedirectUris] = registeredClient.postLogoutRedirectUris.joinToString(",") - it[scopes] = registeredClient.scopes.joinToString(",") - it[clientSettings] = mapToJson(registeredClient.clientSettings.settings) - it[tokenSettings] = mapToJson(registeredClient.tokenSettings.settings) - } - } - } - - override fun findById(id: String?): SpringRegisteredClient? { - if (id == null) { - return null - } - return RegisteredClient.selectAll().where { RegisteredClient.id eq id }.singleOrNull()?.toRegisteredClient() - } - - @Transactional - override fun findByClientId(clientId: String?): SpringRegisteredClient? { - if (clientId == null) { - return null - } - val toRegisteredClient = - RegisteredClient.selectAll().where { RegisteredClient.clientId eq clientId }.singleOrNull() - ?.toRegisteredClient() - LOGGER.trace("findByClientId: {}", toRegisteredClient) - return toRegisteredClient - } - - private fun mapToJson(map: Map<*, *>): String = objectMapper.writeValueAsString(map) - - private fun jsonToMap(json: String): Map = objectMapper.readValue(json) - - @Suppress("CyclomaticComplexMethod") - fun ResultRow.toRegisteredClient(): SpringRegisteredClient { - fun resolveClientAuthenticationMethods(string: String): ClientAuthenticationMethod { - return when (string) { - ClientAuthenticationMethod.CLIENT_SECRET_BASIC.value -> ClientAuthenticationMethod.CLIENT_SECRET_BASIC - ClientAuthenticationMethod.CLIENT_SECRET_JWT.value -> ClientAuthenticationMethod.CLIENT_SECRET_JWT - ClientAuthenticationMethod.CLIENT_SECRET_POST.value -> ClientAuthenticationMethod.CLIENT_SECRET_POST - ClientAuthenticationMethod.NONE.value -> ClientAuthenticationMethod.NONE - else -> { - ClientAuthenticationMethod(string) - } - } - } - - fun resolveAuthorizationGrantType(string: String): AuthorizationGrantType { - return when (string) { - AuthorizationGrantType.AUTHORIZATION_CODE.value -> AuthorizationGrantType.AUTHORIZATION_CODE - AuthorizationGrantType.CLIENT_CREDENTIALS.value -> AuthorizationGrantType.CLIENT_CREDENTIALS - AuthorizationGrantType.REFRESH_TOKEN.value -> AuthorizationGrantType.REFRESH_TOKEN - else -> { - AuthorizationGrantType(string) - } - } - } - - val clientAuthenticationMethods = this[RegisteredClient.clientAuthenticationMethods].split(",").toSet() - val authorizationGrantTypes = this[RegisteredClient.authorizationGrantTypes].split(",").toSet() - val redirectUris = this[RegisteredClient.redirectUris]?.split(",").orEmpty().toSet() - val postLogoutRedirectUris = this[RegisteredClient.postLogoutRedirectUris]?.split(",").orEmpty().toSet() - val clientScopes = this[RegisteredClient.scopes].split(",").toSet() - - val builder = SpringRegisteredClient - .withId(this[RegisteredClient.id]) - .clientId(this[clientId]) - .clientIdIssuedAt(this[RegisteredClient.clientIdIssuedAt]) - .clientSecret(this[RegisteredClient.clientSecret]) - .clientSecretExpiresAt(this[RegisteredClient.clientSecretExpiresAt]) - .clientName(this[RegisteredClient.clientName]) - .clientAuthenticationMethods { - clientAuthenticationMethods.forEach { s -> - it.add(resolveClientAuthenticationMethods(s)) - } - } - .authorizationGrantTypes { - authorizationGrantTypes.forEach { s -> - it.add(resolveAuthorizationGrantType(s)) - } - } - .redirectUris { it.addAll(redirectUris) } - .postLogoutRedirectUris { it.addAll(postLogoutRedirectUris) } - .scopes { it.addAll(clientScopes) } - .clientSettings(ClientSettings.withSettings(jsonToMap(this[clientSettings])).build()) - - val tokenSettingsMap = jsonToMap(this[tokenSettings]) - val withSettings = TokenSettings.withSettings(tokenSettingsMap) - if (tokenSettingsMap.containsKey(ConfigurationSettingNames.Token.ACCESS_TOKEN_FORMAT)) { - withSettings.accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED) - } - builder.tokenSettings(withSettings.build()) - - return builder.build() - } - - companion object { - val objectMapper: ObjectMapper = ObjectMapper() - val LOGGER: Logger = LoggerFactory.getLogger(RegisteredClientRepositoryImpl::class.java) - - init { - - val classLoader = ExposedOAuth2AuthorizationService::class.java.classLoader - val modules = SecurityJackson2Modules.getModules(classLoader) - objectMapper.registerModules(JavaTimeModule()) - objectMapper.registerModules(modules) - objectMapper.registerModules(OAuth2AuthorizationServerJackson2Module()) - } - } -} - -// org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql -object RegisteredClient : Table("registered_client") { - val id: Column = varchar("id", 100) - val clientId: Column = varchar("client_id", 100) - val clientIdIssuedAt: Column = timestamp("client_id_issued_at").defaultExpression(CurrentTimestamp) - val clientSecret: Column = varchar("client_secret", 200).nullable().default(null) - val clientSecretExpiresAt: Column = timestamp("client_secret_expires_at").nullable().default(null) - val clientName: Column = varchar("client_name", 200) - val clientAuthenticationMethods: Column = varchar("client_authentication_methods", 1000) - val authorizationGrantTypes: Column = varchar("authorization_grant_types", 1000) - val redirectUris: Column = varchar("redirect_uris", 1000).nullable().default(null) - val postLogoutRedirectUris: Column = varchar("post_logout_redirect_uris", 1000).nullable().default(null) - val scopes: Column = varchar("scopes", 1000) - val clientSettings: Column = varchar("client_settings", 2000) - val tokenSettings: Column = varchar("token_settings", 2000) - - override val primaryKey: PrimaryKey = PrimaryKey(id) -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsImpl.kt deleted file mode 100644 index abb9846e..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsImpl.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.oauth2 - -import com.fasterxml.jackson.annotation.JsonAutoDetect -import com.fasterxml.jackson.annotation.JsonIgnoreProperties -import com.fasterxml.jackson.annotation.JsonSubTypes -import com.fasterxml.jackson.annotation.JsonTypeInfo -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.core.type.TypeReference -import com.fasterxml.jackson.databind.DeserializationContext -import com.fasterxml.jackson.databind.JsonDeserializer -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.SimpleGrantedAuthority -import org.springframework.security.core.userdetails.User -import java.io.Serial - -class UserDetailsImpl( - val id: Long, - username: String?, - password: String?, - enabled: Boolean, - accountNonExpired: Boolean, - credentialsNonExpired: Boolean, - accountNonLocked: Boolean, - authorities: MutableCollection? -) : User(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities) { - override fun toString(): String { - return "UserDetailsImpl(" + - "id=$id" + - ")" + - " ${super.toString()}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - if (!super.equals(other)) return false - - other as UserDetailsImpl - - return id == other.id - } - - override fun hashCode(): Int { - var result = super.hashCode() - result = 31 * result + id.hashCode() - return result - } - - companion object { - @Serial - private const val serialVersionUID: Long = -899168205656607781L - } -} - -@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) -@JsonDeserialize(using = UserDetailsDeserializer::class) -@JsonAutoDetect( - fieldVisibility = JsonAutoDetect.Visibility.ANY, - getterVisibility = JsonAutoDetect.Visibility.NONE, - isGetterVisibility = JsonAutoDetect.Visibility.NONE, - creatorVisibility = JsonAutoDetect.Visibility.NONE -) -@JsonIgnoreProperties(ignoreUnknown = true) -@JsonSubTypes -@Suppress("UnnecessaryAbstractClass") -abstract class UserDetailsMixin - -class UserDetailsDeserializer : JsonDeserializer() { - - override fun deserialize(p: JsonParser, ctxt: DeserializationContext): UserDetailsImpl { - val mapper = p.codec as ObjectMapper - val jsonNode: JsonNode = mapper.readTree(p) - val authorities: Set = mapper.convertValue( - jsonNode["authorities"], - SIMPLE_GRANTED_AUTHORITY_SET - ) - - val password = jsonNode.readText("password") - return UserDetailsImpl( - id = jsonNode["id"].longValue(), - username = jsonNode.readText("username"), - password = password, - enabled = true, - accountNonExpired = true, - credentialsNonExpired = true, - accountNonLocked = true, - authorities = authorities.toMutableList(), - ) - } - - fun JsonNode.readText(field: String, defaultValue: String = ""): String { - return when { - has(field) -> get(field).asText(defaultValue) - else -> defaultValue - } - } - - companion object { - private val SIMPLE_GRANTED_AUTHORITY_SET = object : TypeReference>() {} - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/security/OAuth2JwtLoginUserContextHolder.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/security/OAuth2JwtLoginUserContextHolder.kt deleted file mode 100644 index 29746d90..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/security/OAuth2JwtLoginUserContextHolder.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.security - -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.oauth2.jwt.Jwt -import org.springframework.stereotype.Component - -@Component -class OAuth2JwtLoginUserContextHolder : LoginUserContextHolder { - override fun getLoginUserId(): Long { - val principal = SecurityContextHolder.getContext().authentication.principal as Jwt - - return principal.getClaim("uid").toLong() - } - - override fun getLoginUserIdOrNull(): Long? { - val principal = SecurityContextHolder.getContext()?.authentication?.principal - if (principal !is Jwt) { - return null - } - - return principal.getClaim("uid").toLongOrNull() - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/generate/JsonOrFormBind.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/generate/JsonOrFormBind.kt deleted file mode 100644 index 4a74319e..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/generate/JsonOrFormBind.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.generate - -@MustBeDocumented -@Retention(AnnotationRetention.RUNTIME) -@Target(AnnotationTarget.VALUE_PARAMETER) -annotation class JsonOrFormBind diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/generate/JsonOrFormModelMethodProcessor.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/generate/JsonOrFormModelMethodProcessor.kt deleted file mode 100644 index 98febb98..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/generate/JsonOrFormModelMethodProcessor.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.generate - -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.core.MethodParameter -import org.springframework.validation.BindException -import org.springframework.web.bind.support.WebDataBinderFactory -import org.springframework.web.context.request.NativeWebRequest -import org.springframework.web.method.annotation.ModelAttributeMethodProcessor -import org.springframework.web.method.support.HandlerMethodArgumentResolver -import org.springframework.web.method.support.ModelAndViewContainer -import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - -@Suppress("TooGenericExceptionCaught") -class JsonOrFormModelMethodProcessor( - private val modelAttributeMethodProcessor: ModelAttributeMethodProcessor, - private val requestResponseBodyMethodProcessor: RequestResponseBodyMethodProcessor -) : HandlerMethodArgumentResolver { - private val isJsonRegex = Regex("application/((\\w*)\\+)?json") - - override fun supportsParameter(parameter: MethodParameter): Boolean = - parameter.hasParameterAnnotation(JsonOrFormBind::class.java) - - override fun resolveArgument( - parameter: MethodParameter, - mavContainer: ModelAndViewContainer?, - webRequest: NativeWebRequest, - binderFactory: WebDataBinderFactory? - ): Any? { - val contentType = webRequest.getHeader("Content-Type").orEmpty() - logger.trace("ContentType is {}", contentType) - if (contentType.contains(isJsonRegex)) { - logger.trace("Determine content type as json.") - return requestResponseBodyMethodProcessor.resolveArgument( - parameter, - mavContainer, - webRequest, - binderFactory - ) - } - - return try { - modelAttributeMethodProcessor.resolveArgument(parameter, mavContainer, webRequest, binderFactory) - } catch (e: BindException) { - throw e - } catch (exception: Exception) { - try { - requestResponseBodyMethodProcessor.resolveArgument(parameter, mavContainer, webRequest, binderFactory) - } catch (e: BindException) { - throw e - } catch (e: Exception) { - logger.warn("Failed to bind request (1)", exception) - logger.warn("Failed to bind request (2)", e) - throw IllegalArgumentException("Failed to bind request.") - } - } - } - - companion object { - val logger: Logger = LoggerFactory.getLogger(JsonOrFormModelMethodProcessor::class.java) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActor2Factory.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActor2Factory.kt index 217fb36b..fa0662c9 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActor2Factory.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActor2Factory.kt @@ -1,9 +1,9 @@ package dev.usbharu.hideout.core.domain.model.actor -import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService import dev.usbharu.hideout.core.domain.model.emoji.EmojiId import dev.usbharu.hideout.core.domain.model.instance.InstanceId import dev.usbharu.hideout.core.domain.model.shared.Domain +import dev.usbharu.hideout.core.infrastructure.other.TwitterSnowflakeIdGenerateService import kotlinx.coroutines.runBlocking import java.net.URI import java.time.Instant diff --git a/hideout-mastodon/src/main/kotlin/Main.kt b/hideout-mastodon/src/main/kotlin/Main.kt deleted file mode 100644 index 27f6ee1a..00000000 --- a/hideout-mastodon/src/main/kotlin/Main.kt +++ /dev/null @@ -1,5 +0,0 @@ -package dev.usbharu - -fun main() { - println("Hello World!") -} \ No newline at end of file