mirror of https://github.com/usbharu/Hideout.git
feat: 起動からユーザー作成、ログインまでのトランザクションを修正
This commit is contained in:
parent
de79c91710
commit
3f96397768
|
@ -14,14 +14,13 @@ import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
||||||
import dev.usbharu.hideout.plugins.*
|
import dev.usbharu.hideout.plugins.*
|
||||||
import dev.usbharu.hideout.query.FollowerQueryService
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
import dev.usbharu.hideout.query.UserQueryService
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
|
||||||
import dev.usbharu.hideout.routing.register
|
import dev.usbharu.hideout.routing.register
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||||
import dev.usbharu.hideout.service.api.IPostApiService
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import dev.usbharu.hideout.service.api.IUserApiService
|
import dev.usbharu.hideout.service.api.IUserApiService
|
||||||
|
import dev.usbharu.hideout.service.api.UserAuthApiService
|
||||||
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
||||||
import dev.usbharu.hideout.service.auth.IJwtService
|
|
||||||
import dev.usbharu.hideout.service.core.IMetaService
|
import dev.usbharu.hideout.service.core.IMetaService
|
||||||
import dev.usbharu.hideout.service.core.IServerInitialiseService
|
import dev.usbharu.hideout.service.core.IServerInitialiseService
|
||||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
import dev.usbharu.hideout.service.core.IdGenerateService
|
||||||
|
@ -29,7 +28,6 @@ import dev.usbharu.hideout.service.core.TwitterSnowflakeIdGenerateService
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.job.KJobJobQueueParentService
|
import dev.usbharu.hideout.service.job.KJobJobQueueParentService
|
||||||
import dev.usbharu.hideout.service.reaction.IReactionService
|
import dev.usbharu.hideout.service.reaction.IReactionService
|
||||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import dev.usbharu.kjob.exposed.ExposedKJob
|
import dev.usbharu.kjob.exposed.ExposedKJob
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
@ -97,6 +95,7 @@ fun Application.parent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
configureKoin(module, HideoutModule().module)
|
configureKoin(module, HideoutModule().module)
|
||||||
|
configureStatusPages()
|
||||||
runBlocking {
|
runBlocking {
|
||||||
inject<IServerInitialiseService>().value.init()
|
inject<IServerInitialiseService>().value.init()
|
||||||
}
|
}
|
||||||
|
@ -105,7 +104,7 @@ fun Application.parent() {
|
||||||
configureStaticRouting()
|
configureStaticRouting()
|
||||||
configureMonitoring()
|
configureMonitoring()
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
register(inject<IUserService>().value)
|
register(inject<IUserApiService>().value)
|
||||||
configureSecurity(
|
configureSecurity(
|
||||||
|
|
||||||
inject<JwkProvider>().value,
|
inject<JwkProvider>().value,
|
||||||
|
@ -119,11 +118,9 @@ fun Application.parent() {
|
||||||
postService = inject<IPostApiService>().value,
|
postService = inject<IPostApiService>().value,
|
||||||
userApiService = inject<IUserApiService>().value,
|
userApiService = inject<IUserApiService>().value,
|
||||||
reactionService = inject<IReactionService>().value,
|
reactionService = inject<IReactionService>().value,
|
||||||
userAuthService = inject<IUserAuthService>().value,
|
|
||||||
userRepository = inject<IUserRepository>().value,
|
|
||||||
jwtService = inject<IJwtService>().value,
|
|
||||||
userQueryService = inject<UserQueryService>().value,
|
userQueryService = inject<UserQueryService>().value,
|
||||||
followerQueryService = inject<FollowerQueryService>().value
|
followerQueryService = inject<FollowerQueryService>().value,
|
||||||
|
userAuthApiService = inject<UserAuthApiService>().value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package dev.usbharu.hideout.exception
|
||||||
|
|
||||||
|
class InvalidUsernameOrPasswordException : Exception {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package dev.usbharu.hideout.exception
|
||||||
|
|
||||||
|
class UsernameAlreadyExistException : Exception {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package dev.usbharu.hideout.plugins
|
||||||
|
|
||||||
import dev.usbharu.hideout.query.FollowerQueryService
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
import dev.usbharu.hideout.query.UserQueryService
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
|
||||||
import dev.usbharu.hideout.routing.activitypub.inbox
|
import dev.usbharu.hideout.routing.activitypub.inbox
|
||||||
import dev.usbharu.hideout.routing.activitypub.outbox
|
import dev.usbharu.hideout.routing.activitypub.outbox
|
||||||
import dev.usbharu.hideout.routing.activitypub.usersAP
|
import dev.usbharu.hideout.routing.activitypub.usersAP
|
||||||
|
@ -14,10 +13,9 @@ import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||||
import dev.usbharu.hideout.service.api.IPostApiService
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import dev.usbharu.hideout.service.api.IUserApiService
|
import dev.usbharu.hideout.service.api.IUserApiService
|
||||||
|
import dev.usbharu.hideout.service.api.UserAuthApiService
|
||||||
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
||||||
import dev.usbharu.hideout.service.auth.IJwtService
|
|
||||||
import dev.usbharu.hideout.service.reaction.IReactionService
|
import dev.usbharu.hideout.service.reaction.IReactionService
|
||||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.plugins.autohead.*
|
import io.ktor.server.plugins.autohead.*
|
||||||
|
@ -32,11 +30,9 @@ fun Application.configureRouting(
|
||||||
postService: IPostApiService,
|
postService: IPostApiService,
|
||||||
userApiService: IUserApiService,
|
userApiService: IUserApiService,
|
||||||
reactionService: IReactionService,
|
reactionService: IReactionService,
|
||||||
userAuthService: IUserAuthService,
|
|
||||||
userRepository: IUserRepository,
|
|
||||||
jwtService: IJwtService,
|
|
||||||
userQueryService: UserQueryService,
|
userQueryService: UserQueryService,
|
||||||
followerQueryService: FollowerQueryService
|
followerQueryService: FollowerQueryService,
|
||||||
|
userAuthApiService: UserAuthApiService
|
||||||
) {
|
) {
|
||||||
install(AutoHeadResponse)
|
install(AutoHeadResponse)
|
||||||
routing {
|
routing {
|
||||||
|
@ -47,7 +43,7 @@ fun Application.configureRouting(
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, reactionService)
|
posts(postService, reactionService)
|
||||||
users(userService, userApiService)
|
users(userService, userApiService)
|
||||||
auth(userAuthService, jwtService, userQueryService)
|
auth(userAuthApiService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.plugins
|
package dev.usbharu.hideout.plugins
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.exception.InvalidUsernameOrPasswordException
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.plugins.statuspages.*
|
import io.ktor.server.plugins.statuspages.*
|
||||||
|
@ -10,8 +11,12 @@ fun Application.configureStatusPages() {
|
||||||
exception<IllegalArgumentException> { call, cause ->
|
exception<IllegalArgumentException> { call, cause ->
|
||||||
call.respondText(text = "400: $cause", status = HttpStatusCode.BadRequest)
|
call.respondText(text = "400: $cause", status = HttpStatusCode.BadRequest)
|
||||||
}
|
}
|
||||||
|
exception<InvalidUsernameOrPasswordException> { call, _ ->
|
||||||
|
call.respond(401)
|
||||||
|
}
|
||||||
exception<Throwable> { call, cause ->
|
exception<Throwable> { call, cause ->
|
||||||
call.respondText(text = "500: $cause", status = HttpStatusCode.InternalServerError)
|
call.respondText(text = "500: ${cause.stackTraceToString()}", status = HttpStatusCode.InternalServerError)
|
||||||
|
cause.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,5 @@ interface UserQueryService {
|
||||||
suspend fun findByNameAndDomain(name: String, domain: String): User
|
suspend fun findByNameAndDomain(name: String, domain: String): User
|
||||||
suspend fun findByUrl(url: String): User
|
suspend fun findByUrl(url: String): User
|
||||||
suspend fun findByIds(ids: List<Long>): List<User>
|
suspend fun findByIds(ids: List<Long>): List<User>
|
||||||
|
suspend fun existByNameAndDomain(name: String, domain: String): Boolean
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,4 +24,8 @@ class UserQueryServiceImpl : UserQueryService {
|
||||||
|
|
||||||
override suspend fun findByIds(ids: List<Long>): List<User> =
|
override suspend fun findByIds(ids: List<Long>): List<User> =
|
||||||
Users.select { Users.id inList ids }.map { it.toUser() }
|
Users.select { Users.id inList ids }.map { it.toUser() }
|
||||||
|
|
||||||
|
override suspend fun existByNameAndDomain(name: String, domain: String): Boolean {
|
||||||
|
return Users.select { Users.name eq name and (Users.domain eq domain) }.empty().not()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.usbharu.hideout.routing
|
package dev.usbharu.hideout.routing
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
import dev.usbharu.hideout.service.api.IUserApiService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
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.*
|
||||||
|
@ -9,7 +8,7 @@ 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.*
|
||||||
|
|
||||||
fun Application.register(userService: IUserService) {
|
fun Application.register(userApiService: IUserApiService) {
|
||||||
routing {
|
routing {
|
||||||
get("/register") {
|
get("/register") {
|
||||||
val principal = call.principal<UserIdPrincipal>()
|
val principal = call.principal<UserIdPrincipal>()
|
||||||
|
@ -37,10 +36,7 @@ fun Application.register(userService: IUserService) {
|
||||||
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 (userService.usernameAlreadyUse(username)) {
|
userApiService.createUser(username, password)
|
||||||
return@post call.respondRedirect("/register")
|
|
||||||
}
|
|
||||||
userService.createLocalUser(UserCreateDto(username, username, "", password))
|
|
||||||
call.respondRedirect("/users/$username")
|
call.respondRedirect("/users/$username")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import io.ktor.server.application.*
|
||||||
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 org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
|
|
||||||
fun Routing.usersAP(
|
fun Routing.usersAP(
|
||||||
activityPubUserService: ActivityPubUserService,
|
activityPubUserService: ActivityPubUserService,
|
||||||
|
@ -32,11 +33,18 @@ fun Routing.usersAP(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
get {
|
get {
|
||||||
val userEntity = userQueryService.findByNameAndDomain(
|
|
||||||
call.parameters["name"] ?: throw ParameterNotExistException("Parameter(name='name') does not exist."),
|
|
||||||
Config.configData.domain
|
// TODO: 暫定処置なので治す
|
||||||
)
|
newSuspendedTransaction {
|
||||||
call.respondText(userEntity.toString() + "\n" + followerQueryService.findFollowersById(userEntity.id))
|
|
||||||
|
val userEntity = userQueryService.findByNameAndDomain(
|
||||||
|
call.parameters["name"]
|
||||||
|
?: throw ParameterNotExistException("Parameter(name='name') does not exist."),
|
||||||
|
Config.configData.domain
|
||||||
|
)
|
||||||
|
call.respondText(userEntity.toString() + "\n" + followerQueryService.findFollowersById(userEntity.id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +54,7 @@ class ContentTypeRouteSelector(private vararg val contentType: ContentType) : Ro
|
||||||
context.call.application.log.debug("Accept: ${context.call.request.accept()}")
|
context.call.application.log.debug("Accept: ${context.call.request.accept()}")
|
||||||
val requestContentType = context.call.request.accept() ?: return RouteSelectorEvaluation.FailedParameter
|
val requestContentType = context.call.request.accept() ?: return RouteSelectorEvaluation.FailedParameter
|
||||||
return if (requestContentType.split(",")
|
return if (requestContentType.split(",")
|
||||||
.any { contentType.any { contentType -> contentType.match(it) } }
|
.any { contentType.any { contentType -> contentType.match(it) } }
|
||||||
) {
|
) {
|
||||||
RouteSelectorEvaluation.Constant
|
RouteSelectorEvaluation.Constant
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
package dev.usbharu.hideout.routing.api.internal.v1
|
package dev.usbharu.hideout.routing.api.internal.v1
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
||||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||||
import dev.usbharu.hideout.query.UserQueryService
|
import dev.usbharu.hideout.service.api.UserAuthApiService
|
||||||
import dev.usbharu.hideout.service.auth.IJwtService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
|
||||||
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.auth.jwt.*
|
import io.ktor.server.auth.jwt.*
|
||||||
|
@ -15,26 +11,15 @@ 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.*
|
||||||
|
|
||||||
fun Route.auth(
|
fun Route.auth(userAuthApiService: UserAuthApiService) {
|
||||||
userAuthService: IUserAuthService,
|
|
||||||
jwtService: IJwtService,
|
|
||||||
userQueryService: UserQueryService
|
|
||||||
) {
|
|
||||||
post("/login") {
|
post("/login") {
|
||||||
val loginUser = call.receive<UserLogin>()
|
val loginUser = call.receive<UserLogin>()
|
||||||
val check = userAuthService.verifyAccount(loginUser.username, loginUser.password)
|
return@post call.respond(userAuthApiService.login(loginUser.username, loginUser.password))
|
||||||
if (check.not()) {
|
|
||||||
return@post call.respond(HttpStatusCode.Unauthorized)
|
|
||||||
}
|
|
||||||
|
|
||||||
val user = userQueryService.findByNameAndDomain(loginUser.username, Config.configData.domain)
|
|
||||||
|
|
||||||
return@post call.respond(jwtService.createToken(user))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
post("/refresh-token") {
|
post("/refresh-token") {
|
||||||
val refreshToken = call.receive<RefreshToken>()
|
val refreshToken = call.receive<RefreshToken>()
|
||||||
return@post call.respond(jwtService.refreshToken(refreshToken))
|
return@post call.respond(userAuthApiService.refreshToken(refreshToken))
|
||||||
}
|
}
|
||||||
authenticate(TOKEN_AUTH) {
|
authenticate(TOKEN_AUTH) {
|
||||||
get("/auth-check") {
|
get("/auth-check") {
|
||||||
|
|
|
@ -19,4 +19,6 @@ interface IUserApiService {
|
||||||
suspend fun findFollowersByAcct(acct: Acct): List<UserResponse>
|
suspend fun findFollowersByAcct(acct: Acct): List<UserResponse>
|
||||||
|
|
||||||
suspend fun findFollowingsByAcct(acct: Acct): List<UserResponse>
|
suspend fun findFollowingsByAcct(acct: Acct): List<UserResponse>
|
||||||
|
|
||||||
|
suspend fun createUser(username: String, password: String): UserResponse
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,20 @@ class PostApiServiceImpl(
|
||||||
private val postResponseQueryService: PostResponseQueryService
|
private val postResponseQueryService: PostResponseQueryService
|
||||||
) : IPostApiService {
|
) : IPostApiService {
|
||||||
override suspend fun createPost(postForm: FormPost, userId: Long): PostResponse {
|
override suspend fun createPost(postForm: FormPost, userId: Long): PostResponse {
|
||||||
val createdPost = postService.createLocal(
|
return newSuspendedTransaction {
|
||||||
PostCreateDto(
|
val createdPost = postService.createLocal(
|
||||||
text = postForm.text,
|
PostCreateDto(
|
||||||
overview = postForm.overview,
|
text = postForm.text,
|
||||||
visibility = postForm.visibility,
|
overview = postForm.overview,
|
||||||
repostId = postForm.repostId,
|
visibility = postForm.visibility,
|
||||||
repolyId = postForm.replyId,
|
repostId = postForm.repostId,
|
||||||
userId = userId
|
repolyId = postForm.replyId,
|
||||||
|
userId = userId
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
val creator = userRepository.findById(userId)
|
||||||
val creator = userRepository.findById(userId)
|
PostResponse.from(createdPost, creator!!)
|
||||||
return PostResponse.from(createdPost, creator!!)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
@Suppress("InjectDispatcher")
|
||||||
|
@ -47,8 +49,16 @@ class PostApiServiceImpl(
|
||||||
maxId: Long?,
|
maxId: Long?,
|
||||||
limit: Int?,
|
limit: Int?,
|
||||||
userId: Long?
|
userId: Long?
|
||||||
): List<PostResponse> =
|
): List<PostResponse> = newSuspendedTransaction {
|
||||||
postResponseQueryService.findAll(since?.toEpochMilli(), until?.toEpochMilli(), minId, maxId, limit, userId)
|
postResponseQueryService.findAll(
|
||||||
|
since?.toEpochMilli(),
|
||||||
|
until?.toEpochMilli(),
|
||||||
|
minId,
|
||||||
|
maxId,
|
||||||
|
limit,
|
||||||
|
userId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getByUser(
|
override suspend fun getByUser(
|
||||||
nameOrId: String,
|
nameOrId: String,
|
||||||
|
|
|
@ -2,16 +2,21 @@ package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.Acct
|
import dev.usbharu.hideout.domain.model.Acct
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse
|
import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse
|
||||||
|
import dev.usbharu.hideout.exception.UsernameAlreadyExistException
|
||||||
import dev.usbharu.hideout.query.FollowerQueryService
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
import dev.usbharu.hideout.query.UserQueryService
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
|
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class UserApiServiceImpl(
|
class UserApiServiceImpl(
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val followerQueryService: FollowerQueryService
|
private val followerQueryService: FollowerQueryService,
|
||||||
|
private val userService: IUserService
|
||||||
) : IUserApiService {
|
) : IUserApiService {
|
||||||
override suspend fun findAll(limit: Int?, offset: Long): List<UserResponse> =
|
override suspend fun findAll(limit: Int?, offset: Long): List<UserResponse> =
|
||||||
userQueryService.findAll(min(limit ?: 100, 100), offset).map { UserResponse.from(it) }
|
userQueryService.findAll(min(limit ?: 100, 100), offset).map { UserResponse.from(it) }
|
||||||
|
@ -37,4 +42,13 @@ class UserApiServiceImpl(
|
||||||
override suspend fun findFollowingsByAcct(acct: Acct): List<UserResponse> =
|
override suspend fun findFollowingsByAcct(acct: Acct): List<UserResponse> =
|
||||||
followerQueryService.findFollowingByNameAndDomain(acct.username, acct.domain ?: Config.configData.domain)
|
followerQueryService.findFollowingByNameAndDomain(acct.username, acct.domain ?: Config.configData.domain)
|
||||||
.map { UserResponse.from(it) }
|
.map { UserResponse.from(it) }
|
||||||
|
|
||||||
|
override suspend fun createUser(username: String, password: String): UserResponse {
|
||||||
|
return newSuspendedTransaction {
|
||||||
|
if (userQueryService.existByNameAndDomain(username, Config.configData.domain)) {
|
||||||
|
throw UsernameAlreadyExistException()
|
||||||
|
}
|
||||||
|
UserResponse.from(userService.createLocalUser(UserCreateDto(username, username, "", password)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.JwtToken
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
|
|
||||||
|
interface UserAuthApiService {
|
||||||
|
suspend fun login(username: String, password: String): JwtToken
|
||||||
|
suspend fun refreshToken(refreshToken: RefreshToken): JwtToken
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.config.Config
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.JwtToken
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
|
import dev.usbharu.hideout.exception.InvalidUsernameOrPasswordException
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.auth.IJwtService
|
||||||
|
import dev.usbharu.hideout.service.user.UserAuthService
|
||||||
|
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class UserAuthApiServiceImpl(
|
||||||
|
private val userAuthService: UserAuthService,
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val jwtService: IJwtService
|
||||||
|
) : UserAuthApiService {
|
||||||
|
override suspend fun login(username: String, password: String): JwtToken {
|
||||||
|
return newSuspendedTransaction {
|
||||||
|
if (userAuthService.verifyAccount(username, password).not()) {
|
||||||
|
throw InvalidUsernameOrPasswordException()
|
||||||
|
}
|
||||||
|
val user = userQueryService.findByNameAndDomain(username, Config.configData.domain)
|
||||||
|
jwtService.createToken(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun refreshToken(refreshToken: RefreshToken): JwtToken {
|
||||||
|
return newSuspendedTransaction {
|
||||||
|
jwtService.refreshToken(refreshToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,9 +13,7 @@ import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.IJwtRefreshTokenRepository
|
import dev.usbharu.hideout.repository.IJwtRefreshTokenRepository
|
||||||
import dev.usbharu.hideout.service.core.IMetaService
|
import dev.usbharu.hideout.service.core.IMetaService
|
||||||
import dev.usbharu.hideout.util.RsaUtil
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.temporal.ChronoUnit
|
import java.time.temporal.ChronoUnit
|
||||||
|
@ -30,23 +28,16 @@ class JwtServiceImpl(
|
||||||
private val refreshTokenQueryService: JwtRefreshTokenQueryService
|
private val refreshTokenQueryService: JwtRefreshTokenQueryService
|
||||||
) : IJwtService {
|
) : IJwtService {
|
||||||
|
|
||||||
private val privateKey by lazy {
|
private val privateKey = runBlocking {
|
||||||
CoroutineScope(Dispatchers.IO).async {
|
RsaUtil.decodeRsaPrivateKey(metaService.getJwtMeta().privateKey)
|
||||||
RsaUtil.decodeRsaPrivateKey(metaService.getJwtMeta().privateKey)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val publicKey by lazy {
|
private val publicKey = runBlocking {
|
||||||
CoroutineScope(Dispatchers.IO).async {
|
RsaUtil.decodeRsaPublicKey(metaService.getJwtMeta().publicKey)
|
||||||
RsaUtil.decodeRsaPublicKey(metaService.getJwtMeta().publicKey)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val keyId by lazy {
|
private val keyId = runBlocking { metaService.getJwtMeta().kid }
|
||||||
CoroutineScope(Dispatchers.IO).async {
|
|
||||||
metaService.getJwtMeta().kid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
override suspend fun createToken(user: User): JwtToken {
|
override suspend fun createToken(user: User): JwtToken {
|
||||||
|
@ -54,10 +45,10 @@ class JwtServiceImpl(
|
||||||
val token = JWT.create()
|
val token = JWT.create()
|
||||||
.withAudience("${Config.configData.url}/users/${user.name}")
|
.withAudience("${Config.configData.url}/users/${user.name}")
|
||||||
.withIssuer(Config.configData.url)
|
.withIssuer(Config.configData.url)
|
||||||
.withKeyId(keyId.await().toString())
|
.withKeyId(keyId.toString())
|
||||||
.withClaim("uid", user.id)
|
.withClaim("uid", user.id)
|
||||||
.withExpiresAt(now.plus(30, ChronoUnit.MINUTES))
|
.withExpiresAt(now.plus(30, ChronoUnit.MINUTES))
|
||||||
.sign(Algorithm.RSA256(publicKey.await(), privateKey.await()))
|
.sign(Algorithm.RSA256(publicKey, privateKey))
|
||||||
|
|
||||||
val jwtRefreshToken = JwtRefreshToken(
|
val jwtRefreshToken = JwtRefreshToken(
|
||||||
id = refreshTokenRepository.generateId(),
|
id = refreshTokenRepository.generateId(),
|
||||||
|
|
|
@ -4,13 +4,15 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Jwt
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Meta
|
import dev.usbharu.hideout.domain.model.hideout.entity.Meta
|
||||||
import dev.usbharu.hideout.exception.NotInitException
|
import dev.usbharu.hideout.exception.NotInitException
|
||||||
import dev.usbharu.hideout.repository.IMetaRepository
|
import dev.usbharu.hideout.repository.IMetaRepository
|
||||||
|
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class MetaServiceImpl(private val metaRepository: IMetaRepository) : IMetaService {
|
class MetaServiceImpl(private val metaRepository: IMetaRepository) : IMetaService {
|
||||||
override suspend fun getMeta(): Meta = metaRepository.get() ?: throw NotInitException("Meta is null")
|
override suspend fun getMeta(): Meta =
|
||||||
|
newSuspendedTransaction { metaRepository.get() ?: throw NotInitException("Meta is null") }
|
||||||
|
|
||||||
override suspend fun updateMeta(meta: Meta) {
|
override suspend fun updateMeta(meta: Meta) = newSuspendedTransaction {
|
||||||
metaRepository.save(meta)
|
metaRepository.save(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Jwt
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Meta
|
import dev.usbharu.hideout.domain.model.hideout.entity.Meta
|
||||||
import dev.usbharu.hideout.repository.IMetaRepository
|
import dev.usbharu.hideout.repository.IMetaRepository
|
||||||
import dev.usbharu.hideout.util.ServerUtil
|
import dev.usbharu.hideout.util.ServerUtil
|
||||||
|
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
@ -16,18 +17,20 @@ class ServerInitialiseServiceImpl(private val metaRepository: IMetaRepository) :
|
||||||
val logger: Logger = LoggerFactory.getLogger(ServerInitialiseServiceImpl::class.java)
|
val logger: Logger = LoggerFactory.getLogger(ServerInitialiseServiceImpl::class.java)
|
||||||
|
|
||||||
override suspend fun init() {
|
override suspend fun init() {
|
||||||
val savedMeta = metaRepository.get()
|
newSuspendedTransaction {
|
||||||
val implementationVersion = ServerUtil.getImplementationVersion()
|
val savedMeta = metaRepository.get()
|
||||||
if (wasInitialised(savedMeta).not()) {
|
val implementationVersion = ServerUtil.getImplementationVersion()
|
||||||
logger.info("Start Initialise")
|
if (wasInitialised(savedMeta).not()) {
|
||||||
initialise(implementationVersion)
|
logger.info("Start Initialise")
|
||||||
logger.info("Finish Initialise")
|
initialise(implementationVersion)
|
||||||
return
|
logger.info("Finish Initialise")
|
||||||
}
|
return@newSuspendedTransaction
|
||||||
|
}
|
||||||
|
|
||||||
if (isVersionChanged(requireNotNull(savedMeta))) {
|
if (isVersionChanged(requireNotNull(savedMeta))) {
|
||||||
logger.info("Version changed!! (${savedMeta.version} -> $implementationVersion)")
|
logger.info("Version changed!! (${savedMeta.version} -> $implementationVersion)")
|
||||||
updateVersion(savedMeta, implementationVersion)
|
updateVersion(savedMeta, implementationVersion)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue