diff --git a/src/main/kotlin/dev/usbharu/hideout/Application.kt b/src/main/kotlin/dev/usbharu/hideout/Application.kt index d5ecffdc..487dcb65 100644 --- a/src/main/kotlin/dev/usbharu/hideout/Application.kt +++ b/src/main/kotlin/dev/usbharu/hideout/Application.kt @@ -79,7 +79,7 @@ fun Application.parent() { } single { ActivityPubFollowServiceImpl(get(), get(), get(), get()) } single { ActivityPubServiceImpl(get(), get()) } - single { UserService(get()) } + single { UserService(get(),get()) } single { ActivityPubUserServiceImpl(get(), get(), get()) } single { ActivityPubNoteServiceImpl(get(), get(), get()) } single { PostService(get(), get()) } @@ -93,7 +93,7 @@ fun Application.parent() { configureStaticRouting() configureMonitoring() configureSerialization() - register(inject().value) + register(inject().value) configureRouting( inject().value, inject().value, diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/UserCreateDto.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/UserCreateDto.kt index ddab1b2f..e8a59f26 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/UserCreateDto.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/UserCreateDto.kt @@ -2,7 +2,6 @@ package dev.usbharu.hideout.domain.model.hideout.dto data class UserCreateDto( val name:String, - val domain:String, val screenName:String, val description:String, val password:String diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt index 50313a58..cbb6cab4 100644 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt +++ b/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt @@ -149,8 +149,8 @@ class KtorKeyMap(private val userAuthRepository: IUserRepository) : KeyMap { val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey") .substringAfterLast("/") val publicBytes = Base64.getDecoder().decode( - userAuthRepository.findByName( - username + userAuthRepository.findByNameAndDomain( + username,Config.configData.domain )?.publicKey?.replace("-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----")?.replace("", "") ?.replace("\n", "") ) @@ -162,8 +162,8 @@ class KtorKeyMap(private val userAuthRepository: IUserRepository) : KeyMap { val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey") .substringAfterLast("/") val publicBytes = Base64.getDecoder().decode( - userAuthRepository.findByName( - username + userAuthRepository.findByNameAndDomain( + username,Config.configData.domain )?.privateKey?.replace("-----BEGIN PRIVATE KEY-----", "")?.replace("-----END PRIVATE KEY-----", "") ?.replace("\n", "") ) diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/IUserRepository.kt b/src/main/kotlin/dev/usbharu/hideout/repository/IUserRepository.kt index 1f198526..0d19094f 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/IUserRepository.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/IUserRepository.kt @@ -9,7 +9,11 @@ interface IUserRepository { suspend fun findByIds(ids: List): List - suspend fun findByName(name: String): User? + suspend fun findByName(name: String): List + + suspend fun findByNameAndDomain(name: String, domain: String): User? + + suspend fun findByDomain(domain:String): List suspend fun findByNameAndDomains(names: List>): List diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/UserRepository.kt b/src/main/kotlin/dev/usbharu/hideout/repository/UserRepository.kt index 8ab5cce7..9a577a83 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/UserRepository.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/UserRepository.kt @@ -10,7 +10,8 @@ import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransacti import org.jetbrains.exposed.sql.transactions.transaction import java.time.Instant -class UserRepository(private val database: Database,private val idGenerateService: IdGenerateService) : IUserRepository { +class UserRepository(private val database: Database, private val idGenerateService: IdGenerateService) : + IUserRepository { init { transaction(database) { SchemaUtils.create(Users) @@ -85,11 +86,25 @@ class UserRepository(private val database: Database,private val idGenerateServic } } - override suspend fun findByName(name: String): User? { + override suspend fun findByName(name: String): List { return query { Users.select { Users.name eq name }.map { it.toUser() - }.singleOrNull() + } + } + } + + override suspend fun findByNameAndDomain(name: String, domain: String): User? { + return query { + Users.select { Users.name eq name and (Users.domain eq domain) }.singleOrNull()?.toUser() + } + } + + override suspend fun findByDomain(domain: String): List { + return query { + Users.select { Users.domain eq domain }.map { + it.toUser() + } } } diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/RegisterRouting.kt b/src/main/kotlin/dev/usbharu/hideout/routing/RegisterRouting.kt index a6ba6d4c..b0e2f47e 100644 --- a/src/main/kotlin/dev/usbharu/hideout/routing/RegisterRouting.kt +++ b/src/main/kotlin/dev/usbharu/hideout/routing/RegisterRouting.kt @@ -1,16 +1,15 @@ package dev.usbharu.hideout.routing -import dev.usbharu.hideout.plugins.UserSession -import dev.usbharu.hideout.service.IUserAuthService +import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto +import dev.usbharu.hideout.service.impl.UserService import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.auth.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import io.ktor.server.sessions.* -fun Application.register(userAuthService: IUserAuthService) { +fun Application.register(userService: UserService) { routing { get("/register") { @@ -39,13 +38,10 @@ fun Application.register(userAuthService: IUserAuthService) { val parameters = call.receiveParameters() val password = parameters["password"] ?: return@post call.respondRedirect("/register") val username = parameters["username"] ?: return@post call.respondRedirect("/register") - if (userAuthService.usernameAlreadyUse(username)) { + if (userService.usernameAlreadyUse(username)) { return@post call.respondRedirect("/register") } - - val hash = userAuthService.hash(password) - userAuthService.registerAccount(username,hash) -// call.respondRedirect("/login") + userService.createLocalUser(UserCreateDto(username, username, "", password)) call.respondRedirect("/users/$username") } } diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/UserRouting.kt b/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/UserRouting.kt index 66fc511c..d25fca2a 100644 --- a/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/UserRouting.kt +++ b/src/main/kotlin/dev/usbharu/hideout/routing/activitypub/UserRouting.kt @@ -1,5 +1,6 @@ package dev.usbharu.hideout.routing.activitypub +import dev.usbharu.hideout.config.Config import dev.usbharu.hideout.exception.ParameterNotExistException import dev.usbharu.hideout.plugins.respondAp import dev.usbharu.hideout.service.activitypub.ActivityPubUserService @@ -24,7 +25,7 @@ fun Routing.usersAP(activityPubUserService: ActivityPubUserService, userService: ) } get { - val userEntity = userService.findByName(call.parameters["name"]!!) + val userEntity = userService.findByNameLocalUser(call.parameters["name"]!!) call.respondText(userEntity.toString() + "\n" + userService.findFollowersById(userEntity.id)) } } diff --git a/src/main/kotlin/dev/usbharu/hideout/routing/wellknown/WebfingerRouting.kt b/src/main/kotlin/dev/usbharu/hideout/routing/wellknown/WebfingerRouting.kt index f862f745..36948523 100644 --- a/src/main/kotlin/dev/usbharu/hideout/routing/wellknown/WebfingerRouting.kt +++ b/src/main/kotlin/dev/usbharu/hideout/routing/wellknown/WebfingerRouting.kt @@ -25,7 +25,7 @@ fun Routing.webfinger(userService:UserService){ .substringAfter("acct:") .trimStart('@') - val userEntity = userService.findByName(accountName) + val userEntity = userService.findByNameLocalUser(accountName) val webFinger = WebFinger( subject = acct, diff --git a/src/main/kotlin/dev/usbharu/hideout/service/IUserAuthService.kt b/src/main/kotlin/dev/usbharu/hideout/service/IUserAuthService.kt index 1702c41b..5c792ec8 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/IUserAuthService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/IUserAuthService.kt @@ -1,10 +1,13 @@ package dev.usbharu.hideout.service +import java.security.KeyPair + interface IUserAuthService { fun hash(password: String): String suspend fun usernameAlreadyUse(username: String): Boolean - suspend fun registerAccount(username: String, hash: String) + + suspend fun generateKeyPair():KeyPair suspend fun verifyAccount(username: String, password: String): Boolean diff --git a/src/main/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubUserServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubUserServiceImpl.kt index 71e10238..57d73d39 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubUserServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubUserServiceImpl.kt @@ -28,7 +28,7 @@ class ActivityPubUserServiceImpl( private val logger = LoggerFactory.getLogger(this::class.java) override suspend fun getPersonByName(name: String): Person { // TODO: JOINで書き直し - val userEntity = userService.findByName(name) + val userEntity = userService.findByNameLocalUser(name) val userUrl = "${Config.configData.url}/users/$name" return Person( type = emptyList(), diff --git a/src/main/kotlin/dev/usbharu/hideout/service/impl/UserAuthService.kt b/src/main/kotlin/dev/usbharu/hideout/service/impl/UserAuthService.kt index cd2d6ccb..41a38a41 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/impl/UserAuthService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/impl/UserAuthService.kt @@ -1,15 +1,11 @@ package dev.usbharu.hideout.service.impl import dev.usbharu.hideout.config.Config -import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.exception.UserNotFoundException import dev.usbharu.hideout.repository.IUserRepository import dev.usbharu.hideout.service.IUserAuthService import io.ktor.util.* import java.security.* -import java.security.interfaces.RSAPrivateKey -import java.security.interfaces.RSAPublicKey -import java.time.Instant import java.util.* class UserAuthService( @@ -27,37 +23,13 @@ class UserAuthService( return true } - @Deprecated("") - override suspend fun registerAccount(username: String, hash: String) { - val url = "${Config.configData.url}/users/$username" - val registerUser = User( - id = 0L, - name = username, - domain = Config.configData.domain, - screenName = username, - description = "", - inbox = "$url/inbox", - outbox = "$url/outbox", - url = url, - publicKey = "", - createdAt = Instant.now(), - ) - val createdUser = userRepository.save(registerUser) - - val keyPair = generateKeyPair() - val privateKey = keyPair.private as RSAPrivateKey - val publicKey = keyPair.public as RSAPublicKey - - TODO() - } - override suspend fun verifyAccount(username: String, password: String): Boolean { - val userEntity = userRepository.findByName(username) + val userEntity = userRepository.findByNameAndDomain(username, Config.configData.domain) ?: throw UserNotFoundException("$username was not found") return userEntity.password == hash(password) } - private fun generateKeyPair(): KeyPair { + override suspend fun generateKeyPair(): KeyPair { val keyPairGenerator = KeyPairGenerator.getInstance("RSA") keyPairGenerator.initialize(1024) return keyPairGenerator.generateKeyPair() diff --git a/src/main/kotlin/dev/usbharu/hideout/service/impl/UserService.kt b/src/main/kotlin/dev/usbharu/hideout/service/impl/UserService.kt index 7c426341..c67d8ecf 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/impl/UserService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/impl/UserService.kt @@ -1,11 +1,15 @@ package dev.usbharu.hideout.service.impl +import dev.usbharu.hideout.config.Config +import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.exception.UserNotFoundException import dev.usbharu.hideout.repository.IUserRepository +import dev.usbharu.hideout.service.IUserAuthService import java.lang.Integer.min +import java.time.Instant -class UserService(private val userRepository: IUserRepository) { +class UserService(private val userRepository: IUserRepository, private val userAuthService: IUserAuthService) { private val maxLimit = 100 suspend fun findAll(limit: Int? = maxLimit, offset: Long? = 0): List { @@ -24,12 +28,16 @@ class UserService(private val userRepository: IUserRepository) { return userRepository.findByIds(ids) } - suspend fun findByName(name: String): User { + suspend fun findByName(name: String): List { return userRepository.findByName(name) + } + + suspend fun findByNameLocalUser(name: String): User { + return userRepository.findByNameAndDomain(name, Config.configData.domain) ?: throw UserNotFoundException("$name was not found.") } - suspend fun findByNameAndDomains(names: List>): List { + suspend fun findByNameAndDomains(names: List>): List { return userRepository.findByNameAndDomains(names) } @@ -41,10 +49,37 @@ class UserService(private val userRepository: IUserRepository) { return userRepository.findByUrls(urls) } + suspend fun usernameAlreadyUse(username: String): Boolean { + val findByNameAndDomain = userRepository.findByNameAndDomain(username, Config.configData.domain) + return findByNameAndDomain != null + } + + @Deprecated("") suspend fun create(user: User): User { return userRepository.save(user) } + suspend fun createLocalUser(user: UserCreateDto): User { + val nextId = userRepository.nextId() + val HashedPassword = userAuthService.hash(user.password) + val keyPair = userAuthService.generateKeyPair() + val userEntity = User( + id = nextId, + name = user.name, + domain = Config.configData.domain, + screenName = user.screenName, + description = user.description, + password = HashedPassword, + inbox = "${Config.configData.url}/users/$nextId/inbox", + outbox = "${Config.configData.url}/users/$nextId/outbox", + url = "${Config.configData.url}/users/$nextId", + publicKey = keyPair.public.toPem(), + privateKey = keyPair.private.toString(), + Instant.now() + ) + return userRepository.save(userEntity) + } + suspend fun findFollowersById(id: Long): List { return userRepository.findFollowersById(id) }