From cf48ae651b80427a4dfa9953e6af614da5a36c51 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 6 Jun 2024 23:26:20 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=83=AD=E3=83=BC=E3=82=AB=E3=83=AB?= =?UTF-8?q?=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E3=82=92=E4=BD=9C=E6=88=90?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RegisterLocalActorApplicationService.kt | 6 +- .../application/RegisterApplication.kt | 26 +++ .../RegisterApplicationApplicationService.kt | 93 ++++++++++ .../application/RegisteredApplication.kt | 27 +++ .../InitLocalInstanceApplicationService.kt | 59 +++++++ .../hideout/core/config/SecurityConfig.kt | 111 ++++++++++++ .../hideout/core/config/SpringMvcConfig.kt | 46 +++++ .../domain/model/application/Application.kt | 22 +++ .../domain/model/application/ApplicationId.kt | 20 +++ .../model/application/ApplicationName.kt | 20 +++ .../application/ApplicationRepository.kt | 22 +++ .../local/LocalActorDomainServiceImpl.kt | 2 +- .../ExposedActorRepository.kt | 4 +- .../ExposedApplicationRepository.kt | 57 ++++++ .../factory/ActorFactoryImpl.kt | 2 +- .../oauth2/HideoutUserDetails.kt | 39 +++++ .../oauth2/UserDetailsServiceImpl.kt | 54 ++++++ .../interfaces/api/auth/AuthController.kt | 19 +- .../core/interfaces/api/auth/SignUpForm.kt | 2 +- .../db/migration/V1707799249__Filter.sql | 18 -- .../resources/db/migration/V1__Init_DB.sql | 162 +++--------------- hideout-core/src/main/resources/log4j2.xml | 3 +- .../src/main/resources/templates/sign_up.html | 13 +- .../mastodon/config/MastodonSecurityConfig.kt | 63 +------ .../mastodon/interfaces/api/SpringAppApi.kt | 24 ++- 25 files changed, 674 insertions(+), 240 deletions(-) create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisterApplication.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisterApplicationApplicationService.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisteredApplication.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/instance/InitLocalInstanceApplicationService.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SpringMvcConfig.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/Application.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationId.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationName.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationRepository.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepository.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/HideoutUserDetails.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImpl.kt delete mode 100644 hideout-core/src/main/resources/db/migration/V1707799249__Filter.sql 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 6608a0e2..567bccde 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 @@ -28,6 +28,7 @@ import dev.usbharu.hideout.core.domain.service.userdetail.UserDetailDomainServic import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import dev.usbharu.hideout.core.infrastructure.factory.ActorFactoryImpl import org.springframework.stereotype.Service +import java.net.URI @Service class RegisterLocalActorApplicationService( @@ -41,8 +42,8 @@ class RegisterLocalActorApplicationService( private val userDetailRepository: UserDetailRepository, private val idGenerateService: IdGenerateService, ) { - suspend fun register(registerLocalActor: RegisterLocalActor) { - transaction.transaction { + suspend fun register(registerLocalActor: RegisterLocalActor): URI { + return transaction.transaction { if (actorDomainService.usernameAlreadyUse(registerLocalActor.name)) { // todo 適切な例外を考える throw Exception("Username already exists") @@ -61,6 +62,7 @@ class RegisterLocalActorApplicationService( password = userDetailDomainService.hashPassword(registerLocalActor.password), ) userDetailRepository.save(userDetail) + actor.url } } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisterApplication.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisterApplication.kt new file mode 100644 index 00000000..b1351109 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisterApplication.kt @@ -0,0 +1,26 @@ +/* + * 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.application.application + +import java.net.URI + +data class RegisterApplication( + val name: String, + val redirectUris: Set, + val useRefreshToken: Boolean, + val scopes: Set, +) \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisterApplicationApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisterApplicationApplicationService.kt new file mode 100644 index 00000000..96f5867e --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisterApplicationApplicationService.kt @@ -0,0 +1,93 @@ +/* + * 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.application.application + +import dev.usbharu.hideout.core.application.shared.Transaction +import dev.usbharu.hideout.core.domain.model.application.Application +import dev.usbharu.hideout.core.domain.model.application.ApplicationId +import dev.usbharu.hideout.core.domain.model.application.ApplicationName +import dev.usbharu.hideout.core.domain.model.application.ApplicationRepository +import dev.usbharu.hideout.core.domain.service.userdetail.PasswordEncoder +import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService +import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.SecureTokenGenerator +import org.springframework.security.oauth2.core.AuthorizationGrantType +import org.springframework.security.oauth2.core.ClientAuthenticationMethod +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository +import org.springframework.security.oauth2.server.authorization.settings.ClientSettings +import org.springframework.security.oauth2.server.authorization.settings.TokenSettings +import org.springframework.stereotype.Service +import java.time.Duration + +@Service +class RegisterApplicationApplicationService( + private val idGenerateService: IdGenerateService, + private val passwordEncoder: PasswordEncoder, + private val secureTokenGenerator: SecureTokenGenerator, + private val registeredClientRepository: RegisteredClientRepository, + private val transaction: Transaction, + private val applicationRepository: ApplicationRepository, +) { + suspend fun register(registerApplication: RegisterApplication): RegisteredApplication { + + return transaction.transaction { + + val id = idGenerateService.generateId() + val clientSecret = secureTokenGenerator.generate() + val registeredClient = RegisteredClient + .withId(id.toString()) + .clientId(id.toString()) + .clientSecret(passwordEncoder.encode(clientSecret)) + .clientName(registerApplication.name) + .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) + .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT) + .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) + .apply { + if (registerApplication.useRefreshToken) { + authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) + tokenSettings( + TokenSettings + .builder() + .accessTokenTimeToLive(Duration.ofSeconds(31536000000)) + .build() + ) + } + } + .redirectUris { set -> + set.addAll(registerApplication.redirectUris.map { it.toString() }) + } + .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()) + .scopes { it.addAll(registerApplication.scopes) } + .build() + registeredClientRepository.save(registeredClient) + + val application = Application(ApplicationId(id), ApplicationName(registerApplication.name)) + + applicationRepository.save(application) + RegisteredApplication( + id = id, + name = registerApplication.name, + clientSecret = clientSecret, + clientId = id, + redirectUris = registerApplication.redirectUris + ) + } + + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisteredApplication.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisteredApplication.kt new file mode 100644 index 00000000..280afcf0 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/application/RegisteredApplication.kt @@ -0,0 +1,27 @@ +/* + * 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.application.application + +import java.net.URI + +data class RegisteredApplication( + val id: Long, + val name: String, + val redirectUris: Set, + val clientSecret: String, + val clientId: Long, +) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/instance/InitLocalInstanceApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/instance/InitLocalInstanceApplicationService.kt new file mode 100644 index 00000000..d2123c5d --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/instance/InitLocalInstanceApplicationService.kt @@ -0,0 +1,59 @@ +/* + * 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.application.instance + +import dev.usbharu.hideout.core.application.shared.Transaction +import dev.usbharu.hideout.core.config.ApplicationConfig +import dev.usbharu.hideout.core.domain.model.instance.* +import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService +import org.springframework.boot.context.event.ApplicationReadyEvent +import org.springframework.boot.info.BuildProperties +import org.springframework.context.event.EventListener +import org.springframework.stereotype.Service +import java.time.Instant + +@Service +class InitLocalInstanceApplicationService( + private val applicationConfig: ApplicationConfig, + private val instanceRepository: InstanceRepository, + private val idGenerateService: IdGenerateService, + private val buildProperties: BuildProperties, + private val transaction: Transaction, +) { + @EventListener(ApplicationReadyEvent::class) + suspend fun init() = transaction.transaction { + val findByUrl = instanceRepository.findByUrl(applicationConfig.url.toURI()) + + if (findByUrl == null) { + val instance = Instance( + InstanceId(idGenerateService.generateId()), + InstanceName(applicationConfig.url.host), + InstanceDescription(""), + applicationConfig.url.toURI(), + applicationConfig.url.toURI(), + null, + InstanceSoftware("hideout"), + InstanceVersion(buildProperties.version), + false, + false, + InstanceModerationNote(""), + Instant.now(), + ) + instanceRepository.save(instance) + } + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SecurityConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SecurityConfig.kt index f56f796b..9289f80b 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SecurityConfig.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SecurityConfig.kt @@ -18,13 +18,124 @@ package dev.usbharu.hideout.core.config 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.jdbc.core.JdbcOperations +import org.springframework.security.access.hierarchicalroles.RoleHierarchy +import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl +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.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository +import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration +import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint @Configuration +@EnableWebSecurity(debug = false) class SecurityConfig { @Bean fun passwordEncoder(): PasswordEncoder { return BCryptPasswordEncoder() } + + @Bean + @Order(1) + fun oauth2Provider(http: HttpSecurity): SecurityFilterChain { + OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http) + http { + exceptionHandling { + authenticationEntryPoint = LoginUrlAuthenticationEntryPoint("/login") + } + } + return http.build() + } + + @Bean + @Order(3) + fun httpSecurityFilterChain(http: HttpSecurity): SecurityFilterChain { + http { + authorizeHttpRequests { + authorize("/error", permitAll) + authorize("/login", permitAll) + authorize(GET, "/.well-known/**", permitAll) + authorize(GET, "/nodeinfo/2.0", permitAll) + + authorize(GET, "/auth/sign_up", hasRole("ANONYMOUS")) + authorize(POST, "/auth/sign_up", permitAll) + + authorize(anyRequest, authenticated) + } + formLogin { + + } + } + return http.build() + } + + @Bean + fun registeredClientRepository(jdbcOperations: JdbcOperations): RegisteredClientRepository { + return JdbcRegisteredClientRepository(jdbcOperations) + } + + @Bean + fun roleHierarchy(): RoleHierarchy { + val roleHierarchyImpl = RoleHierarchyImpl.fromHierarchy( + """ + SCOPE_read > SCOPE_read:accounts + SCOPE_read > SCOPE_read:accounts + SCOPE_read > SCOPE_read:blocks + SCOPE_read > SCOPE_read:bookmarks + SCOPE_read > SCOPE_read:favourites + SCOPE_read > SCOPE_read:filters + SCOPE_read > SCOPE_read:follows + SCOPE_read > SCOPE_read:lists + SCOPE_read > SCOPE_read:mutes + SCOPE_read > SCOPE_read:notifications + SCOPE_read > SCOPE_read:search + SCOPE_read > SCOPE_read:statuses + SCOPE_write > SCOPE_write:accounts + SCOPE_write > SCOPE_write:blocks + SCOPE_write > SCOPE_write:bookmarks + SCOPE_write > SCOPE_write:conversations + SCOPE_write > SCOPE_write:favourites + SCOPE_write > SCOPE_write:filters + SCOPE_write > SCOPE_write:follows + SCOPE_write > SCOPE_write:lists + SCOPE_write > SCOPE_write:media + SCOPE_write > SCOPE_write:mutes + SCOPE_write > SCOPE_write:notifications + SCOPE_write > SCOPE_write:reports + SCOPE_write > SCOPE_write:statuses + SCOPE_follow > SCOPE_write:blocks + SCOPE_follow > SCOPE_write:follows + SCOPE_follow > SCOPE_write:mutes + SCOPE_follow > SCOPE_read:blocks + SCOPE_follow > SCOPE_read:follows + SCOPE_follow > SCOPE_read:mutes + SCOPE_admin > SCOPE_admin:read + SCOPE_admin > SCOPE_admin:write + SCOPE_admin:read > SCOPE_admin:read:accounts + SCOPE_admin:read > SCOPE_admin:read:reports + SCOPE_admin:read > SCOPE_admin:read:domain_allows + SCOPE_admin:read > SCOPE_admin:read:domain_blocks + SCOPE_admin:read > SCOPE_admin:read:ip_blocks + SCOPE_admin:read > SCOPE_admin:read:email_domain_blocks + SCOPE_admin:read > SCOPE_admin:read:canonical_email_blocks + SCOPE_admin:write > SCOPE_admin:write:accounts + SCOPE_admin:write > SCOPE_admin:write:reports + SCOPE_admin:write > SCOPE_admin:write:domain_allows + SCOPE_admin:write > SCOPE_admin:write:domain_blocks + SCOPE_admin:write > SCOPE_admin:write:ip_blocks + SCOPE_admin:write > SCOPE_admin:write:email_domain_blocks + SCOPE_admin:write > SCOPE_admin:write:canonical_email_blocks + """.trimIndent() + ) + + return roleHierarchyImpl + } } \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SpringMvcConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SpringMvcConfig.kt new file mode 100644 index 00000000..00b6697d --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SpringMvcConfig.kt @@ -0,0 +1,46 @@ +/* + * 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.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 + ) + ) + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/Application.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/Application.kt new file mode 100644 index 00000000..8cee8422 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/Application.kt @@ -0,0 +1,22 @@ +/* + * 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.domain.model.application + +class Application( + val applicationId: ApplicationId, + val name: ApplicationName, +) \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationId.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationId.kt new file mode 100644 index 00000000..6daadcf0 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationId.kt @@ -0,0 +1,20 @@ +/* + * 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.domain.model.application + +@JvmInline +value class ApplicationId(val id: Long) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationName.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationName.kt new file mode 100644 index 00000000..6b9f9a77 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationName.kt @@ -0,0 +1,20 @@ +/* + * 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.domain.model.application + +@JvmInline +value class ApplicationName(val name: String) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationRepository.kt new file mode 100644 index 00000000..22d41d8f --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/application/ApplicationRepository.kt @@ -0,0 +1,22 @@ +/* + * 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.domain.model.application + +interface ApplicationRepository { + suspend fun save(application: Application): Application + suspend fun delete(application: Application) +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorDomainServiceImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorDomainServiceImpl.kt index f00406e5..ef77d51b 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorDomainServiceImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorDomainServiceImpl.kt @@ -29,7 +29,7 @@ class LocalActorDomainServiceImpl( private val applicationConfig: ApplicationConfig, ) : LocalActorDomainService { override suspend fun usernameAlreadyUse(name: String): Boolean = - actorRepository.findByNameAndDomain(name, applicationConfig.url.host) == null + actorRepository.findByNameAndDomain(name, applicationConfig.url.host) != null override suspend fun generateKeyPair(): Pair { val keyPairGenerator = KeyPairGenerator.getInstance("RSA") 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 14d17c3f..d8f560c9 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 @@ -135,10 +135,10 @@ object Actors : Table("actors") { } } -object ActorsAlsoKnownAs : Table("actor_alsoknwonas") { +object ActorsAlsoKnownAs : Table("actor_alsoknownas") { val actorId = long("actor_id").references(Actors.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE) - val alsoKnownAs = long("alsoKnownAs").references(Actors.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE) + val alsoKnownAs = long("also_known_as").references(Actors.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE) override val primaryKey: PrimaryKey = PrimaryKey(actorId, alsoKnownAs) } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepository.kt new file mode 100644 index 00000000..7c04f9dc --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepository.kt @@ -0,0 +1,57 @@ +/* + * 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.exposedrepository + +import dev.usbharu.hideout.core.domain.model.application.Application +import dev.usbharu.hideout.core.domain.model.application.ApplicationRepository +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.sql.deleteWhere +import org.jetbrains.exposed.sql.upsert +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Repository + +@Repository +class ExposedApplicationRepository : ApplicationRepository, AbstractRepository() { + override suspend fun save(application: Application) = query { + Applications.upsert { + it[id] = application.applicationId.id + it[name] = application.name.name + } + application + } + + override suspend fun delete(application: Application): Unit = query { + Applications.deleteWhere { id eq application.applicationId.id } + } + + override val logger: Logger + get() = Companion.logger + + + companion object { + private val logger = LoggerFactory.getLogger(ExposedApplicationRepository::class.java) + } +} + + +object Applications : Table("applications") { + val id = long("id") + val name = varchar("name", 500) + override val primaryKey: PrimaryKey = PrimaryKey(id) +} \ No newline at end of file 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 d9e56e09..b03e208a 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 @@ -45,7 +45,7 @@ class ActorFactoryImpl( description = ActorDescription(""), inbox = URI.create("$userUrl/inbox"), outbox = URI.create("$userUrl/outbox"), - url = applicationConfig.url.toURI(), + url = URI.create(userUrl), publicKey = keyPair.first, privateKey = keyPair.second, createdAt = Instant.now(), diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/HideoutUserDetails.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/HideoutUserDetails.kt new file mode 100644 index 00000000..2ba083e0 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/HideoutUserDetails.kt @@ -0,0 +1,39 @@ +/* + * 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 org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.userdetails.UserDetails + +class HideoutUserDetails( + private val authorities: MutableList, + private val password: String, + private val username: String, + val userDetailsId: Long, +) : UserDetails { + override fun getAuthorities(): MutableCollection { + return authorities + } + + override fun getPassword(): String { + return password + } + + override fun getUsername(): String { + return username + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImpl.kt new file mode 100644 index 00000000..c7db5d46 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImpl.kt @@ -0,0 +1,54 @@ +/* + * 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 dev.usbharu.hideout.core.config.ApplicationConfig +import dev.usbharu.hideout.core.domain.model.actor.ActorRepository +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository +import kotlinx.coroutines.runBlocking +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.core.userdetails.UsernameNotFoundException +import org.springframework.stereotype.Component + +@Component +class UserDetailsServiceImpl( + private val actorRepository: ActorRepository, + private val userDetailRepository: UserDetailRepository, + private val applicationConfig: ApplicationConfig, + private val transaction: Transaction, +) : UserDetailsService { + override fun loadUserByUsername(username: String?): UserDetails = runBlocking { + if (username == null) { + throw UsernameNotFoundException("Username not found") + } + transaction.transaction { + val actor = actorRepository.findByNameAndDomain(username, applicationConfig.url.host) + ?: throw UsernameNotFoundException("$username not found") + val userDetail = userDetailRepository.findByActorId(actor.id.id) + ?: throw UsernameNotFoundException("${actor.id.id} not found") + HideoutUserDetails( + authorities = mutableListOf(), + password = userDetail.password.password, + actor.name.name, + userDetailsId = userDetail.id.id + ) + } + + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/AuthController.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/AuthController.kt index 7487f8b8..d9dc8331 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/AuthController.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/AuthController.kt @@ -16,16 +16,27 @@ package dev.usbharu.hideout.core.interfaces.api.auth -import org.springframework.ui.Model +import dev.usbharu.hideout.core.application.actor.RegisterLocalActor +import dev.usbharu.hideout.core.application.actor.RegisterLocalActorApplicationService +import jakarta.servlet.http.HttpServletRequest +import org.springframework.stereotype.Controller import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.ModelAttribute import org.springframework.web.bind.annotation.PostMapping -interface AuthController { +@Controller +class AuthController(private val registerLocalActorApplicationService: RegisterLocalActorApplicationService) { @GetMapping("/auth/sign_up") - fun signUp(model: Model): String + fun signUp(): String { + return "sign_up" + } @PostMapping("/auth/sign_up") - suspend fun signUp(@Validated @ModelAttribute signUpForm: SignUpForm): String + suspend fun signUp(@Validated @ModelAttribute signUpForm: SignUpForm, request: HttpServletRequest): String { + val registerLocalActor = RegisterLocalActor(signUpForm.username, signUpForm.password) + val uri = registerLocalActorApplicationService.register(registerLocalActor) + request.login(signUpForm.username, signUpForm.password) + return "redirect:$uri" + } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/SignUpForm.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/SignUpForm.kt index 5c032c5a..d70eb9c2 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/SignUpForm.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/api/auth/SignUpForm.kt @@ -3,5 +3,5 @@ package dev.usbharu.hideout.core.interfaces.api.auth data class SignUpForm( val username: String, val password: String, - val recaptchaResponse: String +// val recaptchaResponse: String ) diff --git a/hideout-core/src/main/resources/db/migration/V1707799249__Filter.sql b/hideout-core/src/main/resources/db/migration/V1707799249__Filter.sql deleted file mode 100644 index 3b05b856..00000000 --- a/hideout-core/src/main/resources/db/migration/V1707799249__Filter.sql +++ /dev/null @@ -1,18 +0,0 @@ -create table if not exists filters -( - id bigint primary key not null, - user_id bigint not null, - name varchar(255) not null, - context varchar(500) not null, - action varchar(255) not null, - constraint fk_filters_user_id__id foreign key (user_id) references actors (id) on delete cascade on update cascade -); - -create table if not exists filter_keywords -( - id bigint primary key not null, - filter_id bigint not null, - keyword varchar(1000) not null, - mode varchar(100) not null, - constraint fk_filter_keywords_filter_id__id foreign key (filter_id) references filters (id) on delete cascade on update cascade -); \ No newline at end of file diff --git a/hideout-core/src/main/resources/db/migration/V1__Init_DB.sql b/hideout-core/src/main/resources/db/migration/V1__Init_DB.sql index 699a3357..03ce40a6 100644 --- a/hideout-core/src/main/resources/db/migration/V1__Init_DB.sql +++ b/hideout-core/src/main/resources/db/migration/V1__Init_DB.sql @@ -55,17 +55,27 @@ create table if not exists actors suspend boolean not null, move_to bigint null default null, emojis varchar(3000) not null default '', + deleted boolean not null default false, unique ("name", "domain"), constraint fk_actors_instance__id foreign key ("instance") references instance (id) on delete restrict on update restrict, constraint fk_actors_actors__move_to foreign key ("move_to") references actors (id) on delete restrict on update restrict ); +create table if not exists actor_alsoknownas +( + actor_id bigint not null, + also_known_as bigint not null, + constraint fk_actor_alsoknownas_actors__actor_id foreign key ("actor_id") references actors (id) on delete cascade on update cascade, + constraint fk_actor_alsoknownas_actors__also_known_as foreign key ("also_known_as") references actors (id) on delete cascade on update cascade +); + create table if not exists user_details ( id bigserial primary key, actor_id bigint not null unique, password varchar(255) not null, auto_accept_followee_follow_request boolean not null, + last_migration timestamp null default null, constraint fk_user_details_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict ); @@ -81,14 +91,6 @@ create table if not exists media mime_type varchar(255) not null, description varchar(4000) null ); -create table if not exists meta_info -( - id bigint primary key, - version varchar(1000) not null, - kid varchar(1000) not null, - jwt_private_key varchar(100000) not null, - jwt_public_key varchar(100000) not null -); create table if not exists posts ( id bigint primary key, @@ -134,100 +136,6 @@ alter table posts_emojis alter table posts_emojis add constraint fk_posts_emojis_emoji_id__id foreign key (emoji_id) references emojis (id) on delete cascade on update cascade; -create table if not exists reactions -( - id bigint primary key, - unicode_emoji varchar(255) null default null, - custom_emoji_id bigint null default null, - post_id bigint not null, - actor_id bigint not null, - unique (post_id, actor_id) -); -alter table reactions - add constraint fk_reactions_post_id__id foreign key (post_id) references posts (id) on delete restrict on update restrict; -alter table reactions - add constraint fk_reactions_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict; -alter table reactions - add constraint fk_reactions_custom_emoji_id__id foreign key (custom_emoji_id) references emojis (id) on delete cascade on update cascade; - -create table if not exists timelines -( - id bigint primary key, - user_id bigint not null, - timeline_id bigint not null, - post_id bigint not null, - post_actor_id bigint not null, - created_at bigint not null, - reply_id bigint null, - repost_id bigint null, - visibility int not null, - "sensitive" boolean not null, - is_local boolean not null, - is_pure_repost boolean not null, - media_ids varchar(255) not null, - emoji_ids varchar(255) not null -); - -create table if not exists application_authorization -( - id varchar(255) primary key, - registered_client_id varchar(255) not null, - principal_name varchar(255) not null, - authorization_grant_type varchar(255) not null, - authorized_scopes varchar(1000) default null null, - "attributes" varchar(4000) default null null, - "state" varchar(500) default null null, - authorization_code_value varchar(4000) default null null, - authorization_code_issued_at timestamp default null null, - authorization_code_expires_at timestamp default null null, - authorization_code_metadata varchar(2000) default null null, - access_token_value varchar(4000) default null null, - access_token_issued_at timestamp default null null, - access_token_expires_at timestamp default null null, - access_token_metadata varchar(2000) default null null, - access_token_type varchar(255) default null null, - access_token_scopes varchar(1000) default null null, - refresh_token_value varchar(4000) default null null, - refresh_token_issued_at timestamp default null null, - refresh_token_expires_at timestamp default null null, - refresh_token_metadata varchar(2000) default null null, - oidc_id_token_value varchar(4000) default null null, - oidc_id_token_issued_at timestamp default null null, - oidc_id_token_expires_at timestamp default null null, - oidc_id_token_metadata varchar(2000) default null null, - oidc_id_token_claims varchar(2000) default null null, - user_code_value varchar(4000) default null null, - user_code_issued_at timestamp default null null, - user_code_expires_at timestamp default null null, - user_code_metadata varchar(2000) default null null, - device_code_value varchar(4000) default null null, - device_code_issued_at timestamp default null null, - device_code_expires_at timestamp default null null, - device_code_metadata varchar(2000) default null null -); -create table if not exists oauth2_authorization_consent -( - registered_client_id varchar(100), - principal_name varchar(200), - authorities varchar(1000) not null, - constraint pk_oauth2_authorization_consent primary key (registered_client_id, principal_name) -); -create table if not exists registered_client -( - id varchar(100) primary key, - client_id varchar(100) not null, - client_id_issued_at timestamp default current_timestamp not null, - client_secret varchar(200) default null null, - client_secret_expires_at timestamp default null null, - client_name varchar(200) not null, - client_authentication_methods varchar(1000) not null, - authorization_grant_types varchar(1000) not null, - redirect_uris varchar(1000) default null null, - post_logout_redirect_uris varchar(1000) default null null, - scopes varchar(1000) not null, - client_settings varchar(2000) not null, - token_settings varchar(2000) not null -); create table if not exists relationships ( @@ -254,40 +162,26 @@ insert into actors (id, name, domain, screen_name, description, inbox, outbox, u values (0, '', '', '', '', '', '', '', '', null, current_timestamp, '', null, null, 0, true, null, null, 0, null, current_timestamp, false, null, ''); -create table if not exists deleted_actors +create table if not exists applications ( - id bigint primary key, - "name" varchar(300) not null, - domain varchar(255) not null, - public_key varchar(10000) not null, - deleted_at timestamp not null, - unique ("name", domain) + id bigint primary key, + name varchar(500) not null ); -create table if not exists notifications +create table if not exists oauth2_registered_client ( - id bigint primary key, - type varchar(100) not null, - user_id bigint not null, - source_actor_id bigint null, - post_id bigint null, - text varchar(3000) null, - reaction_id bigint null, - created_at timestamp not null, - constraint fk_notifications_user_id__id foreign key (user_id) references actors (id) on delete cascade on update cascade, - constraint fk_notifications_source_actor__id foreign key (source_actor_id) references actors (id) on delete cascade on update cascade, - constraint fk_notifications_post_id__id foreign key (post_id) references posts (id) on delete cascade on update cascade, - constraint fk_notifications_reaction_id__id foreign key (reaction_id) references reactions (id) on delete cascade on update cascade + id varchar(100) NOT NULL, + client_id varchar(100) NOT NULL, + client_id_issued_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, + client_secret varchar(200) DEFAULT NULL, + client_secret_expires_at timestamp DEFAULT NULL, + client_name varchar(200) NOT NULL, + client_authentication_methods varchar(1000) NOT NULL, + authorization_grant_types varchar(1000) NOT NULL, + redirect_uris varchar(1000) DEFAULT NULL, + post_logout_redirect_uris varchar(1000) DEFAULT NULL, + scopes varchar(1000) NOT NULL, + client_settings varchar(2000) NOT NULL, + token_settings varchar(2000) NOT NULL, + PRIMARY KEY (id) ); - -create table if not exists mastodon_notifications -( - id bigint primary key, - user_id bigint not null, - type varchar(100) not null, - created_at timestamp not null, - account_id bigint not null, - status_id bigint null, - report_id bigint null, - relationship_serverance_event_id bigint null -) \ No newline at end of file diff --git a/hideout-core/src/main/resources/log4j2.xml b/hideout-core/src/main/resources/log4j2.xml index 7c9b917d..6d467f2d 100644 --- a/hideout-core/src/main/resources/log4j2.xml +++ b/hideout-core/src/main/resources/log4j2.xml @@ -6,9 +6,10 @@ - + + \ No newline at end of file diff --git a/hideout-core/src/main/resources/templates/sign_up.html b/hideout-core/src/main/resources/templates/sign_up.html index 3408bb8a..63f57c5a 100644 --- a/hideout-core/src/main/resources/templates/sign_up.html +++ b/hideout-core/src/main/resources/templates/sign_up.html @@ -3,23 +3,12 @@ SignUp - - -
+ -
diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/config/MastodonSecurityConfig.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/config/MastodonSecurityConfig.kt index 2819b80a..513994b1 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/config/MastodonSecurityConfig.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/config/MastodonSecurityConfig.kt @@ -21,8 +21,6 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.core.annotation.Order import org.springframework.http.HttpMethod.* -import org.springframework.security.access.hierarchicalroles.RoleHierarchy -import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.invoke import org.springframework.security.web.SecurityFilterChain @@ -30,7 +28,7 @@ import org.springframework.security.web.SecurityFilterChain @Configuration class MastodonSecurityConfig { @Bean - @Order(4) + @Order(2) @Suppress("LongMethod") fun mastodonApiSecurityFilterChain( http: HttpSecurity, @@ -111,63 +109,4 @@ class MastodonSecurityConfig { return http.build() } - - @Bean - fun roleHierarchy(): RoleHierarchy { - val roleHierarchyImpl = RoleHierarchyImpl() - - roleHierarchyImpl.setHierarchy( - """ - SCOPE_read > SCOPE_read:accounts - SCOPE_read > SCOPE_read:accounts - SCOPE_read > SCOPE_read:blocks - SCOPE_read > SCOPE_read:bookmarks - SCOPE_read > SCOPE_read:favourites - SCOPE_read > SCOPE_read:filters - SCOPE_read > SCOPE_read:follows - SCOPE_read > SCOPE_read:lists - SCOPE_read > SCOPE_read:mutes - SCOPE_read > SCOPE_read:notifications - SCOPE_read > SCOPE_read:search - SCOPE_read > SCOPE_read:statuses - SCOPE_write > SCOPE_write:accounts - SCOPE_write > SCOPE_write:blocks - SCOPE_write > SCOPE_write:bookmarks - SCOPE_write > SCOPE_write:conversations - SCOPE_write > SCOPE_write:favourites - SCOPE_write > SCOPE_write:filters - SCOPE_write > SCOPE_write:follows - SCOPE_write > SCOPE_write:lists - SCOPE_write > SCOPE_write:media - SCOPE_write > SCOPE_write:mutes - SCOPE_write > SCOPE_write:notifications - SCOPE_write > SCOPE_write:reports - SCOPE_write > SCOPE_write:statuses - SCOPE_follow > SCOPE_write:blocks - SCOPE_follow > SCOPE_write:follows - SCOPE_follow > SCOPE_write:mutes - SCOPE_follow > SCOPE_read:blocks - SCOPE_follow > SCOPE_read:follows - SCOPE_follow > SCOPE_read:mutes - SCOPE_admin > SCOPE_admin:read - SCOPE_admin > SCOPE_admin:write - SCOPE_admin:read > SCOPE_admin:read:accounts - SCOPE_admin:read > SCOPE_admin:read:reports - SCOPE_admin:read > SCOPE_admin:read:domain_allows - SCOPE_admin:read > SCOPE_admin:read:domain_blocks - SCOPE_admin:read > SCOPE_admin:read:ip_blocks - SCOPE_admin:read > SCOPE_admin:read:email_domain_blocks - SCOPE_admin:read > SCOPE_admin:read:canonical_email_blocks - SCOPE_admin:write > SCOPE_admin:write:accounts - SCOPE_admin:write > SCOPE_admin:write:reports - SCOPE_admin:write > SCOPE_admin:write:domain_allows - SCOPE_admin:write > SCOPE_admin:write:domain_blocks - SCOPE_admin:write > SCOPE_admin:write:ip_blocks - SCOPE_admin:write > SCOPE_admin:write:email_domain_blocks - SCOPE_admin:write > SCOPE_admin:write:canonical_email_blocks - """.trimIndent() - ) - - return roleHierarchyImpl - } } \ No newline at end of file diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringAppApi.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringAppApi.kt index 95a03bdc..22d0a4a6 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringAppApi.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringAppApi.kt @@ -16,15 +16,35 @@ package dev.usbharu.hideout.mastodon.interfaces.api +import dev.usbharu.hideout.core.application.application.RegisterApplication +import dev.usbharu.hideout.core.application.application.RegisterApplicationApplicationService import dev.usbharu.hideout.mastodon.interfaces.api.generated.AppApi import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Application import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.AppsRequest import org.springframework.http.ResponseEntity import org.springframework.stereotype.Controller +import java.net.URI @Controller -class SpringAppApi : AppApi { +class SpringAppApi(private val registerApplicationApplicationService: RegisterApplicationApplicationService) : AppApi { override suspend fun apiV1AppsPost(appsRequest: AppsRequest): ResponseEntity { - return super.apiV1AppsPost(appsRequest) + + val registerApplication = RegisterApplication( + appsRequest.clientName, + setOf(URI.create(appsRequest.redirectUris)), + false, + appsRequest.scopes?.split(" ").orEmpty().toSet() + ) + val registeredApplication = registerApplicationApplicationService.register(registerApplication) + return ResponseEntity.ok( + Application( + registeredApplication.name, + "invalid-vapid-key", + null, + registeredApplication.clientId.toString(), + registeredApplication.clientSecret, + appsRequest.redirectUris + ) + ) } } \ No newline at end of file