refactor: 一部の命名を変更。ユーザーを作成できるように

This commit is contained in:
usbharu 2023-04-28 15:04:59 +09:00
parent d369c68d94
commit e0aee75930
12 changed files with 82 additions and 57 deletions

View File

@ -79,7 +79,7 @@ fun Application.parent() {
} }
single<ActivityPubFollowService> { ActivityPubFollowServiceImpl(get(), get(), get(), get()) } single<ActivityPubFollowService> { ActivityPubFollowServiceImpl(get(), get(), get(), get()) }
single<ActivityPubService> { ActivityPubServiceImpl(get(), get()) } single<ActivityPubService> { ActivityPubServiceImpl(get(), get()) }
single<UserService> { UserService(get()) } single<UserService> { UserService(get(),get()) }
single<ActivityPubUserService> { ActivityPubUserServiceImpl(get(), get(), get()) } single<ActivityPubUserService> { ActivityPubUserServiceImpl(get(), get(), get()) }
single<ActivityPubNoteService> { ActivityPubNoteServiceImpl(get(), get(), get()) } single<ActivityPubNoteService> { ActivityPubNoteServiceImpl(get(), get(), get()) }
single<IPostService> { PostService(get(), get()) } single<IPostService> { PostService(get(), get()) }
@ -93,7 +93,7 @@ fun Application.parent() {
configureStaticRouting() configureStaticRouting()
configureMonitoring() configureMonitoring()
configureSerialization() configureSerialization()
register(inject<IUserAuthService>().value) register(inject<UserService>().value)
configureRouting( configureRouting(
inject<HttpSignatureVerifyService>().value, inject<HttpSignatureVerifyService>().value,
inject<ActivityPubService>().value, inject<ActivityPubService>().value,

View File

@ -2,7 +2,6 @@ package dev.usbharu.hideout.domain.model.hideout.dto
data class UserCreateDto( data class UserCreateDto(
val name:String, val name:String,
val domain:String,
val screenName:String, val screenName:String,
val description:String, val description:String,
val password:String val password:String

View File

@ -149,8 +149,8 @@ class KtorKeyMap(private val userAuthRepository: IUserRepository) : KeyMap {
val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey") val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey")
.substringAfterLast("/") .substringAfterLast("/")
val publicBytes = Base64.getDecoder().decode( val publicBytes = Base64.getDecoder().decode(
userAuthRepository.findByName( userAuthRepository.findByNameAndDomain(
username username,Config.configData.domain
)?.publicKey?.replace("-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----")?.replace("", "") )?.publicKey?.replace("-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----")?.replace("", "")
?.replace("\n", "") ?.replace("\n", "")
) )
@ -162,8 +162,8 @@ class KtorKeyMap(private val userAuthRepository: IUserRepository) : KeyMap {
val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey") val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey")
.substringAfterLast("/") .substringAfterLast("/")
val publicBytes = Base64.getDecoder().decode( val publicBytes = Base64.getDecoder().decode(
userAuthRepository.findByName( userAuthRepository.findByNameAndDomain(
username username,Config.configData.domain
)?.privateKey?.replace("-----BEGIN PRIVATE KEY-----", "")?.replace("-----END PRIVATE KEY-----", "") )?.privateKey?.replace("-----BEGIN PRIVATE KEY-----", "")?.replace("-----END PRIVATE KEY-----", "")
?.replace("\n", "") ?.replace("\n", "")
) )

View File

@ -9,7 +9,11 @@ interface IUserRepository {
suspend fun findByIds(ids: List<Long>): List<User> suspend fun findByIds(ids: List<Long>): List<User>
suspend fun findByName(name: String): User? suspend fun findByName(name: String): List<User>
suspend fun findByNameAndDomain(name: String, domain: String): User?
suspend fun findByDomain(domain:String): List<User>
suspend fun findByNameAndDomains(names: List<Pair<String,String>>): List<User> suspend fun findByNameAndDomains(names: List<Pair<String,String>>): List<User>

View File

@ -10,7 +10,8 @@ import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransacti
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import java.time.Instant 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 { init {
transaction(database) { transaction(database) {
SchemaUtils.create(Users) 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<User> {
return query { return query {
Users.select { Users.name eq name }.map { Users.select { Users.name eq name }.map {
it.toUser() 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<User> {
return query {
Users.select { Users.domain eq domain }.map {
it.toUser()
}
} }
} }

View File

@ -1,16 +1,15 @@
package dev.usbharu.hideout.routing package dev.usbharu.hideout.routing
import dev.usbharu.hideout.plugins.UserSession import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
import dev.usbharu.hideout.service.IUserAuthService import dev.usbharu.hideout.service.impl.UserService
import io.ktor.http.* import io.ktor.http.*
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.auth.* import io.ktor.server.auth.*
import io.ktor.server.request.* import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
import io.ktor.server.sessions.*
fun Application.register(userAuthService: IUserAuthService) { fun Application.register(userService: UserService) {
routing { routing {
get("/register") { get("/register") {
@ -39,13 +38,10 @@ fun Application.register(userAuthService: IUserAuthService) {
val parameters = call.receiveParameters() val parameters = call.receiveParameters()
val password = parameters["password"] ?: return@post call.respondRedirect("/register") val password = parameters["password"] ?: return@post call.respondRedirect("/register")
val username = parameters["username"] ?: 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") return@post call.respondRedirect("/register")
} }
userService.createLocalUser(UserCreateDto(username, username, "", password))
val hash = userAuthService.hash(password)
userAuthService.registerAccount(username,hash)
// call.respondRedirect("/login")
call.respondRedirect("/users/$username") call.respondRedirect("/users/$username")
} }
} }

View File

@ -1,5 +1,6 @@
package dev.usbharu.hideout.routing.activitypub package dev.usbharu.hideout.routing.activitypub
import dev.usbharu.hideout.config.Config
import dev.usbharu.hideout.exception.ParameterNotExistException import dev.usbharu.hideout.exception.ParameterNotExistException
import dev.usbharu.hideout.plugins.respondAp import dev.usbharu.hideout.plugins.respondAp
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
@ -24,7 +25,7 @@ fun Routing.usersAP(activityPubUserService: ActivityPubUserService, userService:
) )
} }
get { get {
val userEntity = userService.findByName(call.parameters["name"]!!) val userEntity = userService.findByNameLocalUser(call.parameters["name"]!!)
call.respondText(userEntity.toString() + "\n" + userService.findFollowersById(userEntity.id)) call.respondText(userEntity.toString() + "\n" + userService.findFollowersById(userEntity.id))
} }
} }

View File

@ -25,7 +25,7 @@ fun Routing.webfinger(userService:UserService){
.substringAfter("acct:") .substringAfter("acct:")
.trimStart('@') .trimStart('@')
val userEntity = userService.findByName(accountName) val userEntity = userService.findByNameLocalUser(accountName)
val webFinger = WebFinger( val webFinger = WebFinger(
subject = acct, subject = acct,

View File

@ -1,10 +1,13 @@
package dev.usbharu.hideout.service package dev.usbharu.hideout.service
import java.security.KeyPair
interface IUserAuthService { interface IUserAuthService {
fun hash(password: String): String fun hash(password: String): String
suspend fun usernameAlreadyUse(username: String): Boolean 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 suspend fun verifyAccount(username: String, password: String): Boolean

View File

@ -28,7 +28,7 @@ class ActivityPubUserServiceImpl(
private val logger = LoggerFactory.getLogger(this::class.java) private val logger = LoggerFactory.getLogger(this::class.java)
override suspend fun getPersonByName(name: String): Person { override suspend fun getPersonByName(name: String): Person {
// TODO: JOINで書き直し // TODO: JOINで書き直し
val userEntity = userService.findByName(name) val userEntity = userService.findByNameLocalUser(name)
val userUrl = "${Config.configData.url}/users/$name" val userUrl = "${Config.configData.url}/users/$name"
return Person( return Person(
type = emptyList(), type = emptyList(),

View File

@ -1,15 +1,11 @@
package dev.usbharu.hideout.service.impl package dev.usbharu.hideout.service.impl
import dev.usbharu.hideout.config.Config 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.exception.UserNotFoundException
import dev.usbharu.hideout.repository.IUserRepository import dev.usbharu.hideout.repository.IUserRepository
import dev.usbharu.hideout.service.IUserAuthService import dev.usbharu.hideout.service.IUserAuthService
import io.ktor.util.* import io.ktor.util.*
import java.security.* import java.security.*
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import java.time.Instant
import java.util.* import java.util.*
class UserAuthService( class UserAuthService(
@ -27,37 +23,13 @@ class UserAuthService(
return true 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 { 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") ?: throw UserNotFoundException("$username was not found")
return userEntity.password == hash(password) return userEntity.password == hash(password)
} }
private fun generateKeyPair(): KeyPair { override suspend fun generateKeyPair(): KeyPair {
val keyPairGenerator = KeyPairGenerator.getInstance("RSA") val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
keyPairGenerator.initialize(1024) keyPairGenerator.initialize(1024)
return keyPairGenerator.generateKeyPair() return keyPairGenerator.generateKeyPair()

View File

@ -1,11 +1,15 @@
package dev.usbharu.hideout.service.impl 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.domain.model.hideout.entity.User
import dev.usbharu.hideout.exception.UserNotFoundException import dev.usbharu.hideout.exception.UserNotFoundException
import dev.usbharu.hideout.repository.IUserRepository import dev.usbharu.hideout.repository.IUserRepository
import dev.usbharu.hideout.service.IUserAuthService
import java.lang.Integer.min 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 private val maxLimit = 100
suspend fun findAll(limit: Int? = maxLimit, offset: Long? = 0): List<User> { suspend fun findAll(limit: Int? = maxLimit, offset: Long? = 0): List<User> {
@ -24,12 +28,16 @@ class UserService(private val userRepository: IUserRepository) {
return userRepository.findByIds(ids) return userRepository.findByIds(ids)
} }
suspend fun findByName(name: String): User { suspend fun findByName(name: String): List<User> {
return userRepository.findByName(name) return userRepository.findByName(name)
}
suspend fun findByNameLocalUser(name: String): User {
return userRepository.findByNameAndDomain(name, Config.configData.domain)
?: throw UserNotFoundException("$name was not found.") ?: throw UserNotFoundException("$name was not found.")
} }
suspend fun findByNameAndDomains(names: List<Pair<String,String>>): List<User> { suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User> {
return userRepository.findByNameAndDomains(names) return userRepository.findByNameAndDomains(names)
} }
@ -41,10 +49,37 @@ class UserService(private val userRepository: IUserRepository) {
return userRepository.findByUrls(urls) 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 { suspend fun create(user: User): User {
return userRepository.save(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<User> { suspend fun findFollowersById(id: Long): List<User> {
return userRepository.findFollowersById(id) return userRepository.findFollowersById(id)
} }