Merge pull request #55 from usbharu/feature/mastodon-register-account

Feature/mastodon register account
This commit is contained in:
usbharu 2023-09-26 14:20:31 +09:00 committed by GitHub
commit b5a8c0ff35
8 changed files with 121 additions and 4 deletions

View File

@ -93,6 +93,7 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
implementation("jakarta.validation:jakarta.validation-api")

View File

@ -72,6 +72,9 @@ class SecurityConfig {
builder.pattern("/error"),
builder.pattern("/nodeinfo/2.0")
).permitAll()
it.requestMatchers(
builder.pattern("/auth/**")
).anonymous()
it.requestMatchers(builder.pattern("/change-password")).authenticated()
it.requestMatchers(builder.pattern("/api/v1/accounts/verify_credentials"))
.hasAnyAuthority("SCOPE_read", "SCOPE_read:accounts")
@ -84,7 +87,6 @@ class SecurityConfig {
.passwordManagement { }
.formLogin(Customizer.withDefaults())
.csrf {
it.ignoringRequestMatchers(builder.pattern("/api/**"))
it.ignoringRequestMatchers(builder.pattern("/users/*/inbox"))
it.ignoringRequestMatchers(builder.pattern("/inbox"))
it.ignoringRequestMatchers(PathRequest.toH2Console())

View File

@ -0,0 +1,10 @@
package dev.usbharu.hideout.controller
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
@Controller
class AuthController {
@GetMapping("/auth/sign_up")
fun signUp(): String = "sign_up"
}

View File

@ -2,16 +2,23 @@ package dev.usbharu.hideout.controller.mastodon
import dev.usbharu.hideout.controller.mastodon.generated.AccountApi
import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
import dev.usbharu.hideout.service.api.mastodon.AccountApiService
import dev.usbharu.hideout.service.core.Transaction
import kotlinx.coroutines.runBlocking
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.stereotype.Controller
import java.net.URI
@Controller
class MastodonAccountApiController(private val accountApiService: AccountApiService) : AccountApi {
class MastodonAccountApiController(
private val accountApiService: AccountApiService,
private val transaction: Transaction
) : AccountApi {
override fun apiV1AccountsVerifyCredentialsGet(): ResponseEntity<CredentialAccount> = runBlocking {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt
@ -20,4 +27,21 @@ class MastodonAccountApiController(private val accountApiService: AccountApiServ
HttpStatus.OK
)
}
override fun apiV1AccountsPost(
username: String,
password: String,
email: String?,
agreement: Boolean?,
locale: Boolean?,
reason: String?
): ResponseEntity<Unit> = runBlocking {
transaction.transaction {
accountApiService.registerAccount(UserCreateDto(username, username, "", password))
}
val httpHeaders = HttpHeaders()
httpHeaders.location = URI("/users/$username")
ResponseEntity(Unit, httpHeaders, HttpStatus.FOUND)
}
}

View File

@ -4,23 +4,34 @@ import dev.usbharu.hideout.domain.mastodon.model.generated.Account
import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount
import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccountSource
import dev.usbharu.hideout.domain.mastodon.model.generated.Role
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
import dev.usbharu.hideout.service.core.Transaction
import dev.usbharu.hideout.service.mastodon.AccountService
import dev.usbharu.hideout.service.user.UserService
import org.springframework.stereotype.Service
@Service
interface AccountApiService {
suspend fun verifyCredentials(userid: Long): CredentialAccount
suspend fun registerAccount(userCreateDto: UserCreateDto): Unit
}
@Service
class AccountApiServiceImpl(private val accountService: AccountService, private val transaction: Transaction) :
class AccountApiServiceImpl(
private val accountService: AccountService,
private val transaction: Transaction,
private val userService: UserService
) :
AccountApiService {
override suspend fun verifyCredentials(userid: Long): CredentialAccount = transaction.transaction {
val account = accountService.findById(userid)
from(account)
}
override suspend fun registerAccount(userCreateDto: UserCreateDto) {
userService.createLocalUser(UserCreateDto(userCreateDto.name, userCreateDto.name, "", userCreateDto.password))
}
private fun from(account: Account): CredentialAccount {
return CredentialAccount(
id = account.id,

View File

@ -182,8 +182,57 @@ paths:
schema:
$ref: "#/components/schemas/CredentialAccount"
/api/v1/accounts:
post:
tags:
- account
security:
- OAuth2:
- "write:accounts"
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
$ref: "#/components/schemas/AccountsCreateRequest"
responses:
200:
description: 成功
components:
schemas:
AccountsCreateRequest:
type: object
properties:
username:
type: string
email:
type: string
password:
type: string
agreement:
type: boolean
locale:
type: boolean
reason:
type: string
required:
- username
- password
Token:
type: object
properties:
access_token:
type: string
token_type:
type: string
scope:
type: string
created_at:
type: integer
format: int64
Account:
type: object
properties:

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>SignUp</title>
</head>
<body>
<form method='post' th:action="@{/api/v1/accounts}">
<input name='username' type='text' value=''>
<input name='password' type='password'>
<input type="submit">
</form>
</body>
</html>

View File

@ -36,7 +36,12 @@ class APReceiveFollowServiceImplTest {
}
val activityPubFollowService =
APReceiveFollowServiceImpl(
jobQueueParentService, mock(), mock(), mock(), mock(), TestTransaction,
jobQueueParentService,
mock(),
mock(),
mock(),
mock(),
TestTransaction,
objectMapper
)
activityPubFollowService.receiveFollow(