mirror of https://github.com/usbharu/Hideout.git
feat: ローカルユーザーを作成できるように
This commit is contained in:
parent
9c271b8cc8
commit
cf48ae651b
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<URI>,
|
||||
val useRefreshToken: Boolean,
|
||||
val scopes: Set<String>,
|
||||
)
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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<URI>,
|
||||
val clientSecret: String,
|
||||
val clientId: Long,
|
||||
)
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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<HandlerMethodArgumentResolver>) {
|
||||
resolvers.add(jsonOrFormModelMethodProcessor)
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
class JsonOrFormModelMethodProcessorConfig {
|
||||
@Bean
|
||||
fun jsonOrFormModelMethodProcessor(converter: List<HttpMessageConverter<*>>): JsonOrFormModelMethodProcessor {
|
||||
return JsonOrFormModelMethodProcessor(
|
||||
ServletModelAttributeMethodProcessor(true),
|
||||
RequestResponseBodyMethodProcessor(
|
||||
converter
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
||||
}
|
|
@ -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<ActorPublicKey, ActorPrivateKey> {
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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(),
|
||||
|
|
|
@ -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<out GrantedAuthority>,
|
||||
private val password: String,
|
||||
private val username: String,
|
||||
val userDetailsId: Long,
|
||||
) : UserDetails {
|
||||
override fun getAuthorities(): MutableCollection<out GrantedAuthority> {
|
||||
return authorities
|
||||
}
|
||||
|
||||
override fun getPassword(): String {
|
||||
return password
|
||||
}
|
||||
|
||||
override fun getUsername(): String {
|
||||
return username
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
);
|
|
@ -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)
|
||||
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
|
||||
)
|
|
@ -6,9 +6,10 @@
|
|||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="INFO">
|
||||
<Root level="DEBUG">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
<Logger name="dev.usbharu.owl.broker.service.QueuedTaskAssignerImpl" level="TRACE"/>
|
||||
<Logger name="org.mongodb.driver.cluster" level="WARN"/>
|
||||
</Loggers>
|
||||
</Configuration>
|
|
@ -3,23 +3,12 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>SignUp</title>
|
||||
<script th:src="https://www.google.com/recaptcha/api.js?render=${siteKey}"></script>
|
||||
<script th:inline="javascript">
|
||||
grecaptcha.ready(function () {
|
||||
grecaptcha.execute( /*[[${siteKey}]]*/ '', {action: 'homepage'}).then(function (token) {
|
||||
var recaptchaResponse = document.getElementById('recaptchaResponse');
|
||||
recaptchaResponse.value = token;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<form method='post' th:action="@{/dev/usbharu/hideout/core/service/auth/sign_up}"
|
||||
th:disabled="${applicationConfig.private}">
|
||||
<form method='post' th:action="@{/auth/sign_up}">
|
||||
<input name='username' type='text' value=''>
|
||||
<input name='password' type='password'>
|
||||
<input type="hidden" name="recaptchaResponse" id="recaptchaResponse">
|
||||
<input type="submit">
|
||||
</form>
|
||||
</body>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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<Application> {
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue