mirror of https://github.com/usbharu/Hideout.git
Merge pull request #54 from usbharu/feature/fix-jobqueue
fix: ジョブキュー等を修正
This commit is contained in:
commit
a0cd5cd75a
|
@ -2,6 +2,7 @@ build:
|
||||||
maxIssues: 20
|
maxIssues: 20
|
||||||
weights:
|
weights:
|
||||||
Indentation: 0
|
Indentation: 0
|
||||||
|
MagicNumber: 0
|
||||||
|
|
||||||
style:
|
style:
|
||||||
ClassOrdering:
|
ClassOrdering:
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package dev.usbharu.hideout
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.job.HideoutJob
|
||||||
|
import dev.usbharu.hideout.service.ap.APService
|
||||||
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
|
import dev.usbharu.hideout.service.job.JobQueueWorkerService
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.boot.ApplicationArguments
|
||||||
|
import org.springframework.boot.ApplicationRunner
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class JobQueueRunner(private val jobQueueParentService: JobQueueParentService, private val jobs: List<HideoutJob>) :
|
||||||
|
ApplicationRunner {
|
||||||
|
override fun run(args: ApplicationArguments?) {
|
||||||
|
LOGGER.info("Init job queue. ${jobs.size}")
|
||||||
|
jobQueueParentService.init(jobs)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val LOGGER = LoggerFactory.getLogger(JobQueueRunner::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class JobQueueWorkerRunner(
|
||||||
|
private val jobQueueWorkerService: JobQueueWorkerService,
|
||||||
|
private val jobs: List<HideoutJob>,
|
||||||
|
private val apService: APService
|
||||||
|
) : ApplicationRunner {
|
||||||
|
override fun run(args: ApplicationArguments?) {
|
||||||
|
LOGGER.info("Init job queue worker.")
|
||||||
|
jobQueueWorkerService.init(
|
||||||
|
jobs.map {
|
||||||
|
it to {
|
||||||
|
execute {
|
||||||
|
LOGGER.debug("excute job ${it.name}")
|
||||||
|
apService.processActivity(
|
||||||
|
job = this,
|
||||||
|
hideoutJob = it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val LOGGER = LoggerFactory.getLogger(JobQueueWorkerRunner::class.java)
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import org.springframework.boot.runApplication
|
||||||
@ConfigurationPropertiesScan
|
@ConfigurationPropertiesScan
|
||||||
class SpringApplication
|
class SpringApplication
|
||||||
|
|
||||||
|
@Suppress("SpreadOperator")
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
runApplication<SpringApplication>(*args)
|
runApplication<SpringApplication>(*args)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package dev.usbharu.hideout.config
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class ActivityPubConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Qualifier("activitypub")
|
||||||
|
fun objectMapper(): ObjectMapper {
|
||||||
|
val objectMapper = jacksonObjectMapper()
|
||||||
|
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||||
|
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
|
||||||
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||||
|
return objectMapper
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,40 @@
|
||||||
package dev.usbharu.hideout.config
|
package dev.usbharu.hideout.config
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.plugins.KtorKeyMap
|
||||||
|
import dev.usbharu.hideout.plugins.httpSignaturePlugin
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.engine.cio.*
|
import io.ktor.client.engine.cio.*
|
||||||
|
import io.ktor.client.plugins.logging.*
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import tech.barbero.http.message.signing.KeyMap
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
class HttpClientConfig {
|
class HttpClientConfig {
|
||||||
@Bean
|
@Bean
|
||||||
fun httpClient(): HttpClient = HttpClient(CIO)
|
fun httpClient(keyMap: KeyMap): HttpClient = HttpClient(CIO).config {
|
||||||
|
install(httpSignaturePlugin) {
|
||||||
|
this.keyMap = keyMap
|
||||||
|
}
|
||||||
|
install(Logging) {
|
||||||
|
logger = Logger.DEFAULT
|
||||||
|
level = LogLevel.ALL
|
||||||
|
}
|
||||||
|
expectSuccess = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun keyMap(
|
||||||
|
userQueryService: UserQueryService,
|
||||||
|
transaction: Transaction,
|
||||||
|
applicationConfig: ApplicationConfig
|
||||||
|
): KtorKeyMap {
|
||||||
|
return KtorKeyMap(
|
||||||
|
userQueryService,
|
||||||
|
transaction,
|
||||||
|
applicationConfig
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import java.security.interfaces.RSAPrivateKey
|
||||||
import java.security.interfaces.RSAPublicKey
|
import java.security.interfaces.RSAPublicKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@EnableWebSecurity(debug = true)
|
@EnableWebSecurity(debug = false)
|
||||||
@Configuration
|
@Configuration
|
||||||
class SecurityConfig {
|
class SecurityConfig {
|
||||||
|
|
||||||
|
@ -55,7 +55,6 @@ class SecurityConfig {
|
||||||
return http.build()
|
return http.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Order(2)
|
@Order(2)
|
||||||
fun defaultSecurityFilterChain(http: HttpSecurity, introspector: HandlerMappingIntrospector): SecurityFilterChain {
|
fun defaultSecurityFilterChain(http: HttpSecurity, introspector: HandlerMappingIntrospector): SecurityFilterChain {
|
||||||
|
@ -66,6 +65,7 @@ class SecurityConfig {
|
||||||
it.requestMatchers(PathRequest.toH2Console()).permitAll()
|
it.requestMatchers(PathRequest.toH2Console()).permitAll()
|
||||||
it.requestMatchers(
|
it.requestMatchers(
|
||||||
builder.pattern("/inbox"),
|
builder.pattern("/inbox"),
|
||||||
|
builder.pattern("/users/*/inbox"),
|
||||||
builder.pattern("/api/v1/apps"),
|
builder.pattern("/api/v1/apps"),
|
||||||
builder.pattern("/api/v1/instance/**"),
|
builder.pattern("/api/v1/instance/**"),
|
||||||
builder.pattern("/.well-known/**"),
|
builder.pattern("/.well-known/**"),
|
||||||
|
@ -85,6 +85,8 @@ class SecurityConfig {
|
||||||
.formLogin(Customizer.withDefaults())
|
.formLogin(Customizer.withDefaults())
|
||||||
.csrf {
|
.csrf {
|
||||||
it.ignoringRequestMatchers(builder.pattern("/api/**"))
|
it.ignoringRequestMatchers(builder.pattern("/api/**"))
|
||||||
|
it.ignoringRequestMatchers(builder.pattern("/users/*/inbox"))
|
||||||
|
it.ignoringRequestMatchers(builder.pattern("/inbox"))
|
||||||
it.ignoringRequestMatchers(PathRequest.toH2Console())
|
it.ignoringRequestMatchers(PathRequest.toH2Console())
|
||||||
}
|
}
|
||||||
.headers {
|
.headers {
|
||||||
|
@ -96,9 +98,7 @@ class SecurityConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun passwordEncoder(): PasswordEncoder {
|
fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder()
|
||||||
return BCryptPasswordEncoder()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun genJwkSource(): JWKSource<SecurityContext> {
|
fun genJwkSource(): JWKSource<SecurityContext> {
|
||||||
|
@ -128,9 +128,8 @@ class SecurityConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun jwtDecoder(jwkSource: JWKSource<SecurityContext>): JwtDecoder {
|
fun jwtDecoder(jwkSource: JWKSource<SecurityContext>): JwtDecoder =
|
||||||
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource)
|
OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource)
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun authorizationServerSettings(): AuthorizationServerSettings {
|
fun authorizationServerSettings(): AuthorizationServerSettings {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
class SpringConfig {
|
class SpringConfig {
|
||||||
|
@ -28,7 +29,7 @@ class SpringConfig {
|
||||||
|
|
||||||
@ConfigurationProperties("hideout")
|
@ConfigurationProperties("hideout")
|
||||||
data class ApplicationConfig(
|
data class ApplicationConfig(
|
||||||
val url: String
|
val url: URL
|
||||||
)
|
)
|
||||||
|
|
||||||
@ConfigurationProperties("hideout.database")
|
@ConfigurationProperties("hideout.database")
|
||||||
|
|
|
@ -12,7 +12,6 @@ import javax.sql.DataSource
|
||||||
@EnableTransactionManagement
|
@EnableTransactionManagement
|
||||||
class SpringTransactionConfig(val datasource: DataSource) : TransactionManagementConfigurer {
|
class SpringTransactionConfig(val datasource: DataSource) : TransactionManagementConfigurer {
|
||||||
@Bean
|
@Bean
|
||||||
override fun annotationDrivenTransactionManager(): PlatformTransactionManager {
|
override fun annotationDrivenTransactionManager(): PlatformTransactionManager =
|
||||||
return SpringTransactionManager(datasource)
|
SpringTransactionManager(datasource)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,11 @@ interface InboxController {
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
"/inbox",
|
"/inbox",
|
||||||
"/users/{username}/inbox",
|
"/users/{username}/inbox",
|
||||||
produces = ["application/activity+json", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""],
|
produces = [
|
||||||
|
"application/activity+json",
|
||||||
|
"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
|
||||||
|
],
|
||||||
method = [RequestMethod.GET, RequestMethod.POST]
|
method = [RequestMethod.GET, RequestMethod.POST]
|
||||||
)
|
)
|
||||||
suspend fun inbox(@RequestBody string: String): ResponseEntity<Unit> {
|
fun inbox(@RequestBody string: String): ResponseEntity<Unit> = ResponseEntity(HttpStatus.ACCEPTED)
|
||||||
return ResponseEntity(HttpStatus.ACCEPTED)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.controller
|
package dev.usbharu.hideout.controller
|
||||||
|
|
||||||
import dev.usbharu.hideout.service.ap.APService
|
import dev.usbharu.hideout.service.ap.APService
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.web.bind.annotation.RequestBody
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
|
@ -8,9 +9,9 @@ import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
class InboxControllerImpl(private val apService: APService) : InboxController {
|
class InboxControllerImpl(private val apService: APService) : InboxController {
|
||||||
override suspend fun inbox(@RequestBody string: String): ResponseEntity<Unit> {
|
override fun inbox(@RequestBody string: String): ResponseEntity<Unit> = runBlocking {
|
||||||
val parseActivity = apService.parseActivity(string)
|
val parseActivity = apService.parseActivity(string)
|
||||||
apService.processActivity(string, parseActivity)
|
apService.processActivity(string, parseActivity)
|
||||||
return ResponseEntity(HttpStatus.ACCEPTED)
|
ResponseEntity(HttpStatus.ACCEPTED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,5 @@ import org.springframework.web.bind.annotation.RestController
|
||||||
@RestController
|
@RestController
|
||||||
interface OutboxController {
|
interface OutboxController {
|
||||||
@RequestMapping("/outbox", "/users/{username}/outbox", method = [RequestMethod.POST, RequestMethod.GET])
|
@RequestMapping("/outbox", "/users/{username}/outbox", method = [RequestMethod.POST, RequestMethod.GET])
|
||||||
fun outbox(@RequestBody string: String): ResponseEntity<Unit> {
|
fun outbox(@RequestBody string: String): ResponseEntity<Unit> = ResponseEntity(HttpStatus.ACCEPTED)
|
||||||
return ResponseEntity(HttpStatus.ACCEPTED)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,5 @@ import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
class OutboxControllerImpl : OutboxController {
|
class OutboxControllerImpl : OutboxController {
|
||||||
override fun outbox(@RequestBody string: String): ResponseEntity<Unit> {
|
override fun outbox(@RequestBody string: String): ResponseEntity<Unit> = ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
|
||||||
return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,5 @@ import org.springframework.web.bind.annotation.RestController
|
||||||
@RestController
|
@RestController
|
||||||
interface UserAPController {
|
interface UserAPController {
|
||||||
@GetMapping("/users/{username}")
|
@GetMapping("/users/{username}")
|
||||||
suspend fun userAp(@PathVariable("username") username: String): ResponseEntity<Person>
|
fun userAp(@PathVariable("username") username: String): ResponseEntity<Person>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,16 @@ package dev.usbharu.hideout.controller
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.ap.Person
|
import dev.usbharu.hideout.domain.model.ap.Person
|
||||||
import dev.usbharu.hideout.service.ap.APUserService
|
import dev.usbharu.hideout.service.ap.APUserService
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
class UserAPControllerImpl(private val apUserService: APUserService) : UserAPController {
|
class UserAPControllerImpl(private val apUserService: APUserService) : UserAPController {
|
||||||
override suspend fun userAp(username: String): ResponseEntity<Person> {
|
override fun userAp(username: String): ResponseEntity<Person> = runBlocking {
|
||||||
val person = apUserService.getPersonByName(username)
|
val person = apUserService.getPersonByName(username)
|
||||||
return ResponseEntity(person, HttpStatus.OK)
|
person.context += listOf("https://www.w3.org/ns/activitystreams")
|
||||||
|
ResponseEntity(person, HttpStatus.OK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,14 +29,8 @@ class HostMetaController(private val applicationConfig: ApplicationConfig) {
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
@GetMapping("/.well-known/host-meta", produces = ["application/xml"])
|
@GetMapping("/.well-known/host-meta", produces = ["application/xml"])
|
||||||
fun hostmeta(): ResponseEntity<String> {
|
fun hostmeta(): ResponseEntity<String> = ResponseEntity(xml, HttpStatus.OK)
|
||||||
return ResponseEntity(xml, HttpStatus.OK)
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/.well-known/host-meta.json", produces = ["application/json"])
|
@GetMapping("/.well-known/host-meta.json", produces = ["application/json"])
|
||||||
fun hostmetJson(): ResponseEntity<String> {
|
fun hostmetJson(): ResponseEntity<String> = ResponseEntity(json, HttpStatus.OK)
|
||||||
return ResponseEntity(json, HttpStatus.OK)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,13 @@ class NodeinfoController(private val applicationConfig: ApplicationConfig) {
|
||||||
"${applicationConfig.url}/nodeinfo/2.0"
|
"${applicationConfig.url}/nodeinfo/2.0"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
), HttpStatus.OK
|
),
|
||||||
|
HttpStatus.OK
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/nodeinfo/2.0")
|
@GetMapping("/nodeinfo/2.0")
|
||||||
|
@Suppress("FunctionNaming")
|
||||||
fun nodeinfo2_0(): ResponseEntity<Nodeinfo2_0> {
|
fun nodeinfo2_0(): ResponseEntity<Nodeinfo2_0> {
|
||||||
return ResponseEntity(
|
return ResponseEntity(
|
||||||
Nodeinfo2_0(
|
Nodeinfo2_0(
|
||||||
|
|
|
@ -10,7 +10,6 @@ import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.RequestParam
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
class WebFingerController(
|
class WebFingerController(
|
||||||
|
@ -21,14 +20,14 @@ class WebFingerController(
|
||||||
fun webfinger(@RequestParam("resource") resource: String): ResponseEntity<WebFinger> = runBlocking {
|
fun webfinger(@RequestParam("resource") resource: String): ResponseEntity<WebFinger> = runBlocking {
|
||||||
val acct = AcctUtil.parse(resource.replace("acct:", ""))
|
val acct = AcctUtil.parse(resource.replace("acct:", ""))
|
||||||
val user =
|
val user =
|
||||||
webFingerApiService.findByNameAndDomain(acct.username, acct.domain ?: URL(applicationConfig.url).host)
|
webFingerApiService.findByNameAndDomain(acct.username, acct.domain ?: applicationConfig.url.host)
|
||||||
val webFinger = WebFinger(
|
val webFinger = WebFinger(
|
||||||
"acct:${user.name}@${user.domain}",
|
"acct:${user.name}@${user.domain}",
|
||||||
listOf(
|
listOf(
|
||||||
WebFinger.Link(
|
WebFinger.Link(
|
||||||
"self",
|
"self",
|
||||||
"application/activity+json",
|
"application/activity+json",
|
||||||
applicationConfig.url + "/users/" + user.id
|
user.url
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -42,10 +42,12 @@ class UserDetailsImpl(
|
||||||
)
|
)
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@JsonSubTypes
|
@JsonSubTypes
|
||||||
|
@Suppress("UnnecessaryAbstractClass")
|
||||||
abstract class UserDetailsMixin
|
abstract class UserDetailsMixin
|
||||||
|
|
||||||
class UserDetailsDeserializer : JsonDeserializer<UserDetailsImpl>() {
|
class UserDetailsDeserializer : JsonDeserializer<UserDetailsImpl>() {
|
||||||
val SIMPLE_GRANTED_AUTHORITY_SET = object : TypeReference<Set<SimpleGrantedAuthority>>() {}
|
|
||||||
|
private val SIMPLE_GRANTED_AUTHORITY_SET = object : TypeReference<Set<SimpleGrantedAuthority>>() {}
|
||||||
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): UserDetailsImpl {
|
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): UserDetailsImpl {
|
||||||
val mapper = p.codec as ObjectMapper
|
val mapper = p.codec as ObjectMapper
|
||||||
val jsonNode: JsonNode = mapper.readTree(p)
|
val jsonNode: JsonNode = mapper.readTree(p)
|
||||||
|
@ -57,14 +59,14 @@ class UserDetailsDeserializer : JsonDeserializer<UserDetailsImpl>() {
|
||||||
|
|
||||||
val password = jsonNode.readText("password")
|
val password = jsonNode.readText("password")
|
||||||
return UserDetailsImpl(
|
return UserDetailsImpl(
|
||||||
jsonNode["id"].longValue(),
|
id = jsonNode["id"].longValue(),
|
||||||
jsonNode.readText("username"),
|
username = jsonNode.readText("username"),
|
||||||
password,
|
password = password,
|
||||||
true,
|
enabled = true,
|
||||||
true,
|
accountNonExpired = true,
|
||||||
true,
|
credentialsNonExpired = true,
|
||||||
true,
|
accountNonLocked = true,
|
||||||
authorities.toMutableList(),
|
authorities = authorities.toMutableList(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
package dev.usbharu.hideout.domain.model.job
|
package dev.usbharu.hideout.domain.model.job
|
||||||
|
|
||||||
import kjob.core.Job
|
import kjob.core.Job
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
sealed class HideoutJob(name: String = "") : Job(name)
|
sealed class HideoutJob(name: String = "") : Job(name)
|
||||||
|
|
||||||
|
@Component
|
||||||
object ReceiveFollowJob : HideoutJob("ReceiveFollowJob") {
|
object ReceiveFollowJob : HideoutJob("ReceiveFollowJob") {
|
||||||
val actor = string("actor")
|
val actor = string("actor")
|
||||||
val follow = string("follow")
|
val follow = string("follow")
|
||||||
val targetActor = string("targetActor")
|
val targetActor = string("targetActor")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
object DeliverPostJob : HideoutJob("DeliverPostJob") {
|
object DeliverPostJob : HideoutJob("DeliverPostJob") {
|
||||||
val post = string("post")
|
val post = string("post")
|
||||||
val actor = string("actor")
|
val actor = string("actor")
|
||||||
val inbox = string("inbox")
|
val inbox = string("inbox")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
object DeliverReactionJob : HideoutJob("DeliverReactionJob") {
|
object DeliverReactionJob : HideoutJob("DeliverReactionJob") {
|
||||||
val reaction = string("reaction")
|
val reaction = string("reaction")
|
||||||
val postUrl = string("postUrl")
|
val postUrl = string("postUrl")
|
||||||
|
@ -24,6 +28,7 @@ object DeliverReactionJob : HideoutJob("DeliverReactionJob") {
|
||||||
val id = string("id")
|
val id = string("id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
object DeliverRemoveReactionJob : HideoutJob("DeliverRemoveReactionJob") {
|
object DeliverRemoveReactionJob : HideoutJob("DeliverRemoveReactionJob") {
|
||||||
val id = string("id")
|
val id = string("id")
|
||||||
val inbox = string("inbox")
|
val inbox = string("inbox")
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package dev.usbharu.hideout.domain.model.wellknown
|
package dev.usbharu.hideout.domain.model.wellknown
|
||||||
|
|
||||||
|
|
||||||
data class Nodeinfo(
|
data class Nodeinfo(
|
||||||
val links: List<Links>
|
val links: List<Links>
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.domain.model.wellknown
|
package dev.usbharu.hideout.domain.model.wellknown
|
||||||
|
|
||||||
|
@Suppress("ClassNaming")
|
||||||
data class Nodeinfo2_0(
|
data class Nodeinfo2_0(
|
||||||
val version: String,
|
val version: String,
|
||||||
val software: Software,
|
val software: Software,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.plugins
|
package dev.usbharu.hideout.plugins
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import dev.usbharu.hideout.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.domain.model.ap.JsonLd
|
import dev.usbharu.hideout.domain.model.ap.JsonLd
|
||||||
import dev.usbharu.hideout.query.UserQueryService
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.core.Transaction
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
|
@ -26,13 +27,18 @@ import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.crypto.SecretKey
|
import javax.crypto.SecretKey
|
||||||
|
|
||||||
suspend fun HttpClient.postAp(urlString: String, username: String, jsonLd: JsonLd): HttpResponse {
|
suspend fun HttpClient.postAp(
|
||||||
|
urlString: String,
|
||||||
|
username: String,
|
||||||
|
jsonLd: JsonLd,
|
||||||
|
objectMapper: ObjectMapper
|
||||||
|
): HttpResponse {
|
||||||
jsonLd.context += "https://www.w3.org/ns/activitystreams"
|
jsonLd.context += "https://www.w3.org/ns/activitystreams"
|
||||||
return this.post(urlString) {
|
return this.post(urlString) {
|
||||||
header("Accept", ContentType.Application.Activity)
|
header("Accept", ContentType.Application.Activity)
|
||||||
header("Content-Type", ContentType.Application.Activity)
|
header("Content-Type", ContentType.Application.Activity)
|
||||||
header("Signature", "keyId=\"$username\",algorithm=\"rsa-sha256\",headers=\"(request-target) digest date\"")
|
header("Signature", "keyId=\"$username\",algorithm=\"rsa-sha256\",headers=\"(request-target) digest date\"")
|
||||||
val text = Config.configData.objectMapper.writeValueAsString(jsonLd)
|
val text = objectMapper.writeValueAsString(jsonLd)
|
||||||
setBody(text)
|
setBody(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +163,11 @@ val httpSignaturePlugin = createClientPlugin("HttpSign", ::HttpSignaturePluginCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KtorKeyMap(private val userQueryService: UserQueryService, private val transaction: Transaction) : KeyMap {
|
class KtorKeyMap(
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val transaction: Transaction,
|
||||||
|
private val applicationConfig: ApplicationConfig
|
||||||
|
) : KeyMap {
|
||||||
override fun getPublicKey(keyId: String?): PublicKey = runBlocking {
|
override fun getPublicKey(keyId: String?): PublicKey = runBlocking {
|
||||||
val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey")
|
val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey")
|
||||||
.substringAfterLast("/")
|
.substringAfterLast("/")
|
||||||
|
@ -165,7 +175,7 @@ class KtorKeyMap(private val userQueryService: UserQueryService, private val tra
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
userQueryService.findByNameAndDomain(
|
userQueryService.findByNameAndDomain(
|
||||||
username,
|
username,
|
||||||
Config.configData.domain
|
applicationConfig.url.host
|
||||||
).run {
|
).run {
|
||||||
publicKey
|
publicKey
|
||||||
.replace("-----BEGIN PUBLIC KEY-----", "")
|
.replace("-----BEGIN PUBLIC KEY-----", "")
|
||||||
|
@ -185,7 +195,7 @@ class KtorKeyMap(private val userQueryService: UserQueryService, private val tra
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
userQueryService.findByNameAndDomain(
|
userQueryService.findByNameAndDomain(
|
||||||
username,
|
username,
|
||||||
Config.configData.domain
|
applicationConfig.url.host
|
||||||
).privateKey?.run {
|
).privateKey?.run {
|
||||||
replace("-----BEGIN PRIVATE KEY-----", "")
|
replace("-----BEGIN PRIVATE KEY-----", "")
|
||||||
.replace("-----END PRIVATE KEY-----", "")
|
.replace("-----END PRIVATE KEY-----", "")
|
||||||
|
|
|
@ -48,9 +48,9 @@ class RegisteredClientRepositoryImpl(private val database: Database) : Registere
|
||||||
it[clientSecretExpiresAt] = registeredClient.clientSecretExpiresAt
|
it[clientSecretExpiresAt] = registeredClient.clientSecretExpiresAt
|
||||||
it[clientName] = registeredClient.clientName
|
it[clientName] = registeredClient.clientName
|
||||||
it[clientAuthenticationMethods] =
|
it[clientAuthenticationMethods] =
|
||||||
registeredClient.clientAuthenticationMethods.map { it.value }.joinToString(",")
|
registeredClient.clientAuthenticationMethods.map { method -> method.value }.joinToString(",")
|
||||||
it[authorizationGrantTypes] =
|
it[authorizationGrantTypes] =
|
||||||
registeredClient.authorizationGrantTypes.map { it.value }.joinToString(",")
|
registeredClient.authorizationGrantTypes.map { type -> type.value }.joinToString(",")
|
||||||
it[redirectUris] = registeredClient.redirectUris.joinToString(",")
|
it[redirectUris] = registeredClient.redirectUris.joinToString(",")
|
||||||
it[postLogoutRedirectUris] = registeredClient.postLogoutRedirectUris.joinToString(",")
|
it[postLogoutRedirectUris] = registeredClient.postLogoutRedirectUris.joinToString(",")
|
||||||
it[scopes] = registeredClient.scopes.joinToString(",")
|
it[scopes] = registeredClient.scopes.joinToString(",")
|
||||||
|
@ -100,20 +100,7 @@ class RegisteredClientRepositoryImpl(private val database: Database) : Registere
|
||||||
|
|
||||||
private fun <T, U> jsonToMap(json: String): Map<T, U> = objectMapper.readValue(json)
|
private fun <T, U> jsonToMap(json: String): Map<T, U> = objectMapper.readValue(json)
|
||||||
|
|
||||||
companion object {
|
@Suppress("CyclomaticComplexMethod")
|
||||||
val objectMapper: ObjectMapper = ObjectMapper()
|
|
||||||
val LOGGER = LoggerFactory.getLogger(RegisteredClientRepositoryImpl::class.java)
|
|
||||||
|
|
||||||
init {
|
|
||||||
|
|
||||||
val classLoader = ExposedOAuth2AuthorizationService::class.java.classLoader
|
|
||||||
val modules = SecurityJackson2Modules.getModules(classLoader)
|
|
||||||
this.objectMapper.registerModules(JavaTimeModule())
|
|
||||||
this.objectMapper.registerModules(modules)
|
|
||||||
this.objectMapper.registerModules(OAuth2AuthorizationServerJackson2Module())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ResultRow.toRegisteredClient(): SpringRegisteredClient {
|
fun ResultRow.toRegisteredClient(): SpringRegisteredClient {
|
||||||
fun resolveClientAuthenticationMethods(string: String): ClientAuthenticationMethod {
|
fun resolveClientAuthenticationMethods(string: String): ClientAuthenticationMethod {
|
||||||
return when (string) {
|
return when (string) {
|
||||||
|
@ -175,6 +162,20 @@ class RegisteredClientRepositoryImpl(private val database: Database) : Registere
|
||||||
|
|
||||||
return builder.build()
|
return builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val objectMapper: ObjectMapper = ObjectMapper()
|
||||||
|
val LOGGER = LoggerFactory.getLogger(RegisteredClientRepositoryImpl::class.java)
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
val classLoader = ExposedOAuth2AuthorizationService::class.java.classLoader
|
||||||
|
val modules = SecurityJackson2Modules.getModules(classLoader)
|
||||||
|
this.objectMapper.registerModules(JavaTimeModule())
|
||||||
|
this.objectMapper.registerModules(modules)
|
||||||
|
this.objectMapper.registerModules(OAuth2AuthorizationServerJackson2Module())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql
|
// org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package dev.usbharu.hideout.service.ap
|
package dev.usbharu.hideout.service.ap
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.domain.model.ap.Create
|
import dev.usbharu.hideout.domain.model.ap.Create
|
||||||
import dev.usbharu.hideout.domain.model.ap.Note
|
import dev.usbharu.hideout.domain.model.ap.Note
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
|
@ -20,6 +21,7 @@ import io.ktor.client.*
|
||||||
import io.ktor.client.statement.*
|
import io.ktor.client.statement.*
|
||||||
import kjob.core.job.JobProps
|
import kjob.core.job.JobProps
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@ -41,7 +43,10 @@ class APNoteServiceImpl(
|
||||||
private val apUserService: APUserService,
|
private val apUserService: APUserService,
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val followerQueryService: FollowerQueryService,
|
private val followerQueryService: FollowerQueryService,
|
||||||
private val postQueryService: PostQueryService
|
private val postQueryService: PostQueryService,
|
||||||
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
|
||||||
|
private val applicationConfig: ApplicationConfig
|
||||||
|
|
||||||
) : APNoteService {
|
) : APNoteService {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(this::class.java)
|
private val logger = LoggerFactory.getLogger(this::class.java)
|
||||||
|
@ -49,7 +54,7 @@ class APNoteServiceImpl(
|
||||||
override suspend fun createNote(post: Post) {
|
override suspend fun createNote(post: Post) {
|
||||||
val followers = followerQueryService.findFollowersById(post.userId)
|
val followers = followerQueryService.findFollowersById(post.userId)
|
||||||
val userEntity = userQueryService.findById(post.userId)
|
val userEntity = userQueryService.findById(post.userId)
|
||||||
val note = Config.configData.objectMapper.writeValueAsString(post)
|
val note = objectMapper.writeValueAsString(post)
|
||||||
followers.forEach { followerEntity ->
|
followers.forEach { followerEntity ->
|
||||||
jobQueueParentService.schedule(DeliverPostJob) {
|
jobQueueParentService.schedule(DeliverPostJob) {
|
||||||
props[DeliverPostJob.actor] = userEntity.url
|
props[DeliverPostJob.actor] = userEntity.url
|
||||||
|
@ -61,7 +66,7 @@ class APNoteServiceImpl(
|
||||||
|
|
||||||
override suspend fun createNoteJob(props: JobProps<DeliverPostJob>) {
|
override suspend fun createNoteJob(props: JobProps<DeliverPostJob>) {
|
||||||
val actor = props[DeliverPostJob.actor]
|
val actor = props[DeliverPostJob.actor]
|
||||||
val postEntity = Config.configData.objectMapper.readValue<Post>(props[DeliverPostJob.post])
|
val postEntity = objectMapper.readValue<Post>(props[DeliverPostJob.post])
|
||||||
val note = Note(
|
val note = Note(
|
||||||
name = "Note",
|
name = "Note",
|
||||||
id = postEntity.url,
|
id = postEntity.url,
|
||||||
|
@ -79,8 +84,9 @@ class APNoteServiceImpl(
|
||||||
name = "Create Note",
|
name = "Create Note",
|
||||||
`object` = note,
|
`object` = note,
|
||||||
actor = note.attributedTo,
|
actor = note.attributedTo,
|
||||||
id = "${Config.configData.url}/create/note/${postEntity.id}"
|
id = "${applicationConfig.url}/create/note/${postEntity.id}"
|
||||||
)
|
),
|
||||||
|
objectMapper
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +101,7 @@ class APNoteServiceImpl(
|
||||||
url,
|
url,
|
||||||
targetActor?.let { "$targetActor#pubkey" }
|
targetActor?.let { "$targetActor#pubkey" }
|
||||||
)
|
)
|
||||||
val note = Config.configData.objectMapper.readValue<Note>(response.bodyAsText())
|
val note = objectMapper.readValue<Note>(response.bodyAsText())
|
||||||
return note(note, targetActor, url)
|
return note(note, targetActor, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.service.ap
|
package dev.usbharu.hideout.service.ap
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.ap.Like
|
import dev.usbharu.hideout.domain.model.ap.Like
|
||||||
|
@ -14,6 +15,7 @@ import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import kjob.core.job.JobProps
|
import kjob.core.job.JobProps
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@ -31,8 +33,10 @@ class APReactionServiceImpl(
|
||||||
private val httpClient: HttpClient,
|
private val httpClient: HttpClient,
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val followerQueryService: FollowerQueryService,
|
private val followerQueryService: FollowerQueryService,
|
||||||
private val postQueryService: PostQueryService
|
private val postQueryService: PostQueryService,
|
||||||
) : APReactionService {
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
|
||||||
|
|
||||||
|
) : APReactionService {
|
||||||
override suspend fun reaction(like: Reaction) {
|
override suspend fun reaction(like: Reaction) {
|
||||||
val followers = followerQueryService.findFollowersById(like.userId)
|
val followers = followerQueryService.findFollowersById(like.userId)
|
||||||
val user = userQueryService.findById(like.userId)
|
val user = userQueryService.findById(like.userId)
|
||||||
|
@ -79,7 +83,8 @@ class APReactionServiceImpl(
|
||||||
`object` = postUrl,
|
`object` = postUrl,
|
||||||
id = "${Config.configData.url}/like/note/$id",
|
id = "${Config.configData.url}/like/note/$id",
|
||||||
content = content
|
content = content
|
||||||
)
|
),
|
||||||
|
objectMapper
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +101,8 @@ class APReactionServiceImpl(
|
||||||
`object` = like,
|
`object` = like,
|
||||||
id = "${Config.configData.url}/undo/note/${like.id}",
|
id = "${Config.configData.url}/undo/note/${like.id}",
|
||||||
published = Instant.now()
|
published = Instant.now()
|
||||||
)
|
),
|
||||||
|
objectMapper
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package dev.usbharu.hideout.service.ap
|
package dev.usbharu.hideout.service.ap
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.config.Config
|
|
||||||
import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
||||||
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
||||||
import dev.usbharu.hideout.domain.model.ap.Accept
|
import dev.usbharu.hideout.domain.model.ap.Accept
|
||||||
|
@ -15,9 +15,9 @@ import dev.usbharu.hideout.service.user.UserService
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import kjob.core.job.JobProps
|
import kjob.core.job.JobProps
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
|
||||||
interface APReceiveFollowService {
|
interface APReceiveFollowService {
|
||||||
suspend fun receiveFollow(follow: Follow): ActivityPubResponse
|
suspend fun receiveFollow(follow: Follow): ActivityPubResponse
|
||||||
suspend fun receiveFollowJob(props: JobProps<ReceiveFollowJob>)
|
suspend fun receiveFollowJob(props: JobProps<ReceiveFollowJob>)
|
||||||
|
@ -30,24 +30,26 @@ class APReceiveFollowServiceImpl(
|
||||||
private val userService: UserService,
|
private val userService: UserService,
|
||||||
private val httpClient: HttpClient,
|
private val httpClient: HttpClient,
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction,
|
||||||
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
||||||
) : APReceiveFollowService {
|
) : APReceiveFollowService {
|
||||||
override suspend fun receiveFollow(follow: Follow): ActivityPubResponse {
|
override suspend fun receiveFollow(follow: Follow): ActivityPubResponse {
|
||||||
// TODO: Verify HTTP Signature
|
// TODO: Verify HTTP Signature
|
||||||
jobQueueParentService.schedule(ReceiveFollowJob) {
|
jobQueueParentService.schedule(ReceiveFollowJob) {
|
||||||
props[ReceiveFollowJob.actor] = follow.actor
|
props[ReceiveFollowJob.actor] = follow.actor
|
||||||
props[ReceiveFollowJob.follow] = Config.configData.objectMapper.writeValueAsString(follow)
|
props[ReceiveFollowJob.follow] = objectMapper.writeValueAsString(follow)
|
||||||
props[ReceiveFollowJob.targetActor] = follow.`object`
|
props[ReceiveFollowJob.targetActor] = follow.`object`
|
||||||
}
|
}
|
||||||
return ActivityPubStringResponse(HttpStatusCode.OK, "{}", ContentType.Application.Json)
|
return ActivityPubStringResponse(HttpStatusCode.OK, "{}", ContentType.Application.Json)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun receiveFollowJob(props: JobProps<ReceiveFollowJob>) {
|
override suspend fun receiveFollowJob(props: JobProps<ReceiveFollowJob>) {
|
||||||
|
// throw Exception()
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
val actor = props[ReceiveFollowJob.actor]
|
val actor = props[ReceiveFollowJob.actor]
|
||||||
val targetActor = props[ReceiveFollowJob.targetActor]
|
val targetActor = props[ReceiveFollowJob.targetActor]
|
||||||
val person = apUserService.fetchPerson(actor, targetActor)
|
val person = apUserService.fetchPerson(actor, targetActor)
|
||||||
val follow = Config.configData.objectMapper.readValue<Follow>(props[ReceiveFollowJob.follow])
|
val follow = objectMapper.readValue<Follow>(props[ReceiveFollowJob.follow])
|
||||||
httpClient.postAp(
|
httpClient.postAp(
|
||||||
urlString = person.inbox ?: throw IllegalArgumentException("inbox is not found"),
|
urlString = person.inbox ?: throw IllegalArgumentException("inbox is not found"),
|
||||||
username = "$targetActor#pubkey",
|
username = "$targetActor#pubkey",
|
||||||
|
@ -55,7 +57,8 @@ class APReceiveFollowServiceImpl(
|
||||||
name = "Follow",
|
name = "Follow",
|
||||||
`object` = follow,
|
`object` = follow,
|
||||||
actor = targetActor
|
actor = targetActor
|
||||||
)
|
),
|
||||||
|
objectMapper
|
||||||
)
|
)
|
||||||
|
|
||||||
val targetEntity = userQueryService.findByUrl(targetActor)
|
val targetEntity = userQueryService.findByUrl(targetActor)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package dev.usbharu.hideout.service.ap
|
package dev.usbharu.hideout.service.ap
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import dev.usbharu.hideout.domain.model.ap.Follow
|
import dev.usbharu.hideout.domain.model.ap.Follow
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.SendFollowDto
|
import dev.usbharu.hideout.domain.model.hideout.dto.SendFollowDto
|
||||||
import dev.usbharu.hideout.plugins.postAp
|
import dev.usbharu.hideout.plugins.postAp
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -12,7 +14,10 @@ interface APSendFollowService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class APSendFollowServiceImpl(private val httpClient: HttpClient) : APSendFollowService {
|
class APSendFollowServiceImpl(
|
||||||
|
private val httpClient: HttpClient,
|
||||||
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
|
||||||
|
) : APSendFollowService {
|
||||||
override suspend fun sendFollow(sendFollowDto: SendFollowDto) {
|
override suspend fun sendFollow(sendFollowDto: SendFollowDto) {
|
||||||
val follow = Follow(
|
val follow = Follow(
|
||||||
name = "Follow",
|
name = "Follow",
|
||||||
|
@ -22,7 +27,8 @@ class APSendFollowServiceImpl(private val httpClient: HttpClient) : APSendFollow
|
||||||
httpClient.postAp(
|
httpClient.postAp(
|
||||||
urlString = sendFollowDto.followTargetUserId.inbox,
|
urlString = sendFollowDto.followTargetUserId.inbox,
|
||||||
username = sendFollowDto.userId.url,
|
username = sendFollowDto.userId.url,
|
||||||
jsonLd = follow
|
jsonLd = follow,
|
||||||
|
objectMapper
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package dev.usbharu.hideout.service.ap
|
package dev.usbharu.hideout.service.ap
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.config.Config
|
|
||||||
import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
||||||
import dev.usbharu.hideout.domain.model.ap.Follow
|
import dev.usbharu.hideout.domain.model.ap.Follow
|
||||||
import dev.usbharu.hideout.domain.model.job.*
|
import dev.usbharu.hideout.domain.model.job.*
|
||||||
|
@ -11,6 +11,7 @@ import kjob.core.dsl.JobContextWithProps
|
||||||
import kjob.core.job.JobProps
|
import kjob.core.job.JobProps
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -181,12 +182,13 @@ class APServiceImpl(
|
||||||
private val apAcceptService: APAcceptService,
|
private val apAcceptService: APAcceptService,
|
||||||
private val apCreateService: APCreateService,
|
private val apCreateService: APCreateService,
|
||||||
private val apLikeService: APLikeService,
|
private val apLikeService: APLikeService,
|
||||||
private val apReactionService: APReactionService
|
private val apReactionService: APReactionService,
|
||||||
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
||||||
) : APService {
|
) : APService {
|
||||||
|
|
||||||
val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
||||||
override fun parseActivity(json: String): ActivityType {
|
override fun parseActivity(json: String): ActivityType {
|
||||||
val readTree = Config.configData.objectMapper.readTree(json)
|
val readTree = objectMapper.readTree(json)
|
||||||
logger.trace("readTree: {}", readTree)
|
logger.trace("readTree: {}", readTree)
|
||||||
if (readTree.isObject.not()) {
|
if (readTree.isObject.not()) {
|
||||||
throw JsonParseException("Json is not object.")
|
throw JsonParseException("Json is not object.")
|
||||||
|
@ -204,17 +206,17 @@ class APServiceImpl(
|
||||||
override suspend fun processActivity(json: String, type: ActivityType): ActivityPubResponse {
|
override suspend fun processActivity(json: String, type: ActivityType): ActivityPubResponse {
|
||||||
logger.debug("proccess activity: {}", type)
|
logger.debug("proccess activity: {}", type)
|
||||||
return when (type) {
|
return when (type) {
|
||||||
ActivityType.Accept -> apAcceptService.receiveAccept(Config.configData.objectMapper.readValue(json))
|
ActivityType.Accept -> apAcceptService.receiveAccept(objectMapper.readValue(json))
|
||||||
ActivityType.Follow -> apReceiveFollowService.receiveFollow(
|
ActivityType.Follow -> apReceiveFollowService.receiveFollow(
|
||||||
Config.configData.objectMapper.readValue(
|
objectMapper.readValue(
|
||||||
json,
|
json,
|
||||||
Follow::class.java
|
Follow::class.java
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
ActivityType.Create -> apCreateService.receiveCreate(Config.configData.objectMapper.readValue(json))
|
ActivityType.Create -> apCreateService.receiveCreate(objectMapper.readValue(json))
|
||||||
ActivityType.Like -> apLikeService.receiveLike(Config.configData.objectMapper.readValue(json))
|
ActivityType.Like -> apLikeService.receiveLike(objectMapper.readValue(json))
|
||||||
ActivityType.Undo -> apUndoService.receiveUndo(Config.configData.objectMapper.readValue(json))
|
ActivityType.Undo -> apUndoService.receiveUndo(objectMapper.readValue(json))
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
throw IllegalArgumentException("$type is not supported.")
|
throw IllegalArgumentException("$type is not supported.")
|
||||||
|
@ -224,16 +226,25 @@ class APServiceImpl(
|
||||||
|
|
||||||
override suspend fun <T : HideoutJob> processActivity(job: JobContextWithProps<T>, hideoutJob: HideoutJob) {
|
override suspend fun <T : HideoutJob> processActivity(job: JobContextWithProps<T>, hideoutJob: HideoutJob) {
|
||||||
logger.debug("processActivity: ${hideoutJob.name}")
|
logger.debug("processActivity: ${hideoutJob.name}")
|
||||||
when (hideoutJob) {
|
|
||||||
ReceiveFollowJob -> apReceiveFollowService.receiveFollowJob(
|
|
||||||
job.props as JobProps<ReceiveFollowJob>
|
|
||||||
)
|
|
||||||
|
|
||||||
DeliverPostJob -> apNoteService.createNoteJob(job.props as JobProps<DeliverPostJob>)
|
// println(apReceiveFollowService::class.java)
|
||||||
DeliverReactionJob -> apReactionService.reactionJob(job.props as JobProps<DeliverReactionJob>)
|
// apReceiveFollowService.receiveFollowJob(job.props as JobProps<ReceiveFollowJob>)
|
||||||
DeliverRemoveReactionJob -> apReactionService.removeReactionJob(
|
when {
|
||||||
|
hideoutJob is ReceiveFollowJob -> {
|
||||||
|
apReceiveFollowService.receiveFollowJob(
|
||||||
|
job.props as JobProps<ReceiveFollowJob>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
hideoutJob is DeliverPostJob -> apNoteService.createNoteJob(job.props as JobProps<DeliverPostJob>)
|
||||||
|
hideoutJob is DeliverReactionJob -> apReactionService.reactionJob(job.props as JobProps<DeliverReactionJob>)
|
||||||
|
hideoutJob is DeliverRemoveReactionJob -> apReactionService.removeReactionJob(
|
||||||
job.props as JobProps<DeliverRemoveReactionJob>
|
job.props as JobProps<DeliverRemoveReactionJob>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
throw IllegalStateException("WTF")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package dev.usbharu.hideout.service.ap
|
package dev.usbharu.hideout.service.ap
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.domain.model.ap.Image
|
import dev.usbharu.hideout.domain.model.ap.Image
|
||||||
import dev.usbharu.hideout.domain.model.ap.Key
|
import dev.usbharu.hideout.domain.model.ap.Key
|
||||||
import dev.usbharu.hideout.domain.model.ap.Person
|
import dev.usbharu.hideout.domain.model.ap.Person
|
||||||
|
@ -18,6 +19,7 @@ import io.ktor.client.*
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
import io.ktor.client.statement.*
|
import io.ktor.client.statement.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -41,16 +43,18 @@ class APUserServiceImpl(
|
||||||
private val userService: UserService,
|
private val userService: UserService,
|
||||||
private val httpClient: HttpClient,
|
private val httpClient: HttpClient,
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction,
|
||||||
|
private val applicationConfig: ApplicationConfig,
|
||||||
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
||||||
) :
|
) :
|
||||||
APUserService {
|
APUserService {
|
||||||
|
|
||||||
override suspend fun getPersonByName(name: String): Person {
|
override suspend fun getPersonByName(name: String): Person {
|
||||||
val userEntity = transaction.transaction {
|
val userEntity = transaction.transaction {
|
||||||
userQueryService.findByNameAndDomain(name, Config.configData.domain)
|
userQueryService.findByNameAndDomain(name, applicationConfig.url.host)
|
||||||
}
|
}
|
||||||
// TODO: JOINで書き直し
|
// TODO: JOINで書き直し
|
||||||
val userUrl = "${Config.configData.url}/users/$name"
|
val userUrl = "${applicationConfig.url}/users/$name"
|
||||||
return Person(
|
return Person(
|
||||||
type = emptyList(),
|
type = emptyList(),
|
||||||
name = userEntity.name,
|
name = userEntity.name,
|
||||||
|
@ -73,7 +77,7 @@ class APUserServiceImpl(
|
||||||
owner = userUrl,
|
owner = userUrl,
|
||||||
publicKeyPem = userEntity.publicKey
|
publicKeyPem = userEntity.publicKey
|
||||||
),
|
),
|
||||||
endpoints = mapOf("sharedInbox" to "${Config.configData.url}/inbox")
|
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +109,7 @@ class APUserServiceImpl(
|
||||||
owner = url,
|
owner = url,
|
||||||
publicKeyPem = userEntity.publicKey
|
publicKeyPem = userEntity.publicKey
|
||||||
),
|
),
|
||||||
endpoints = mapOf("sharedInbox" to "${Config.configData.url}/inbox")
|
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox")
|
||||||
) to userEntity
|
) to userEntity
|
||||||
} catch (ignore: FailedToGetResourcesException) {
|
} catch (ignore: FailedToGetResourcesException) {
|
||||||
val httpResponse = if (targetActor != null) {
|
val httpResponse = if (targetActor != null) {
|
||||||
|
@ -115,7 +119,7 @@ class APUserServiceImpl(
|
||||||
accept(ContentType.Application.Activity)
|
accept(ContentType.Application.Activity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val person = Config.configData.objectMapper.readValue<Person>(httpResponse.bodyAsText())
|
val person = objectMapper.readValue<Person>(httpResponse.bodyAsText())
|
||||||
|
|
||||||
person to userService.createRemoteUser(
|
person to userService.createRemoteUser(
|
||||||
RemoteUserCreateDto(
|
RemoteUserCreateDto(
|
||||||
|
|
|
@ -18,10 +18,10 @@ class AccountApiServiceImpl(private val accountService: AccountService, private
|
||||||
AccountApiService {
|
AccountApiService {
|
||||||
override suspend fun verifyCredentials(userid: Long): CredentialAccount = transaction.transaction {
|
override suspend fun verifyCredentials(userid: Long): CredentialAccount = transaction.transaction {
|
||||||
val account = accountService.findById(userid)
|
val account = accountService.findById(userid)
|
||||||
of(account)
|
from(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun of(account: Account): CredentialAccount {
|
private fun from(account: Account): CredentialAccount {
|
||||||
return CredentialAccount(
|
return CredentialAccount(
|
||||||
id = account.id,
|
id = account.id,
|
||||||
username = account.username,
|
username = account.username,
|
||||||
|
|
|
@ -55,7 +55,5 @@ class AppApiServiceImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseScope(string: String): Set<String> {
|
private fun parseScope(string: String): Set<String> = string.split(" ").toSet()
|
||||||
return string.split(" ").toSet()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package dev.usbharu.hideout.service.api.mastodon
|
||||||
import dev.usbharu.hideout.config.ApplicationConfig
|
import dev.usbharu.hideout.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.*
|
import dev.usbharu.hideout.domain.mastodon.model.generated.*
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
interface InstanceApiService {
|
interface InstanceApiService {
|
||||||
|
@ -12,17 +11,18 @@ interface InstanceApiService {
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class InstanceApiServiceImpl(private val applicationConfig: ApplicationConfig) : InstanceApiService {
|
class InstanceApiServiceImpl(private val applicationConfig: ApplicationConfig) : InstanceApiService {
|
||||||
|
@Suppress("LongMethod")
|
||||||
override suspend fun v1Instance(): V1Instance {
|
override suspend fun v1Instance(): V1Instance {
|
||||||
val url = applicationConfig.url
|
val url = applicationConfig.url
|
||||||
val url1 = URL(url)
|
|
||||||
return V1Instance(
|
return V1Instance(
|
||||||
uri = url1.host,
|
uri = url.host,
|
||||||
title = "Hideout Server",
|
title = "Hideout Server",
|
||||||
shortDescription = "Hideout test server",
|
shortDescription = "Hideout test server",
|
||||||
description = "This server is operated for testing of Hideout. We are not responsible for any events that occur when associating with this server",
|
description = "This server is operated for testing of Hideout." +
|
||||||
|
" We are not responsible for any events that occur when associating with this server",
|
||||||
email = "i@usbharu.dev",
|
email = "i@usbharu.dev",
|
||||||
version = "0.0.1",
|
version = "0.0.1",
|
||||||
urls = V1InstanceUrls("wss://${url1.host}"),
|
urls = V1InstanceUrls("wss://${url.host}"),
|
||||||
stats = V1InstanceStats(1, 0, 0),
|
stats = V1InstanceStats(1, 0, 0),
|
||||||
thumbnail = null,
|
thumbnail = null,
|
||||||
languages = listOf("ja-JP"),
|
languages = listOf("ja-JP"),
|
||||||
|
@ -37,7 +37,7 @@ class InstanceApiServiceImpl(private val applicationConfig: ApplicationConfig) :
|
||||||
23
|
23
|
||||||
),
|
),
|
||||||
mediaAttachments = V1InstanceConfigurationMediaAttachments(
|
mediaAttachments = V1InstanceConfigurationMediaAttachments(
|
||||||
listOf(),
|
emptyList(),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -26,6 +26,7 @@ class StatsesApiServiceImpl(
|
||||||
private val userQueryService: UserQueryService
|
private val userQueryService: UserQueryService
|
||||||
) :
|
) :
|
||||||
StatusesApiService {
|
StatusesApiService {
|
||||||
|
@Suppress("LongMethod")
|
||||||
override suspend fun postStatus(statusesRequest: StatusesRequest, user: UserDetailsImpl): Status {
|
override suspend fun postStatus(statusesRequest: StatusesRequest, user: UserDetailsImpl): Status {
|
||||||
val visibility = when (statusesRequest.visibility) {
|
val visibility = when (statusesRequest.visibility) {
|
||||||
StatusesRequest.Visibility.public -> Visibility.PUBLIC
|
StatusesRequest.Visibility.public -> Visibility.PUBLIC
|
||||||
|
@ -37,12 +38,12 @@ class StatsesApiServiceImpl(
|
||||||
|
|
||||||
val post = postService.createLocal(
|
val post = postService.createLocal(
|
||||||
PostCreateDto(
|
PostCreateDto(
|
||||||
statusesRequest.status.orEmpty(),
|
text = statusesRequest.status.orEmpty(),
|
||||||
statusesRequest.spoilerText,
|
overview = statusesRequest.spoilerText,
|
||||||
visibility,
|
visibility = visibility,
|
||||||
null,
|
repostId = null,
|
||||||
statusesRequest.inReplyToId?.toLongOrNull(),
|
repolyId = statusesRequest.inReplyToId?.toLongOrNull(),
|
||||||
user.id
|
userId = user.id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val account = accountService.findById(user.id)
|
val account = accountService.findById(user.id)
|
||||||
|
@ -58,7 +59,7 @@ class StatsesApiServiceImpl(
|
||||||
val replyUser = if (post.replyId != null) {
|
val replyUser = if (post.replyId != null) {
|
||||||
try {
|
try {
|
||||||
userQueryService.findById(postQueryService.findById(post.replyId).userId).id
|
userQueryService.findById(postQueryService.findById(post.replyId).userId).id
|
||||||
} catch (e: FailedToGetResourcesException) {
|
} catch (ignore: FailedToGetResourcesException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -82,7 +83,7 @@ class StatsesApiServiceImpl(
|
||||||
favouritesCount = 0,
|
favouritesCount = 0,
|
||||||
repliesCount = 0,
|
repliesCount = 0,
|
||||||
url = post.url,
|
url = post.url,
|
||||||
post.replyId?.toString(),
|
inReplyToId = post.replyId?.toString(),
|
||||||
inReplyToAccountId = replyUser?.toString(),
|
inReplyToAccountId = replyUser?.toString(),
|
||||||
reblog = null,
|
reblog = null,
|
||||||
language = null,
|
language = null,
|
||||||
|
|
|
@ -40,6 +40,7 @@ class ExposedOAuth2AuthorizationService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
override fun save(authorization: OAuth2Authorization?): Unit = runBlocking {
|
override fun save(authorization: OAuth2Authorization?): Unit = runBlocking {
|
||||||
requireNotNull(authorization)
|
requireNotNull(authorization)
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
|
@ -56,7 +57,8 @@ class ExposedOAuth2AuthorizationService(
|
||||||
it[registeredClientId] = authorization.registeredClientId
|
it[registeredClientId] = authorization.registeredClientId
|
||||||
it[principalName] = authorization.principalName
|
it[principalName] = authorization.principalName
|
||||||
it[authorizationGrantType] = authorization.authorizationGrantType.value
|
it[authorizationGrantType] = authorization.authorizationGrantType.value
|
||||||
it[authorizedScopes] = authorization.authorizedScopes.joinToString(",").takeIf { it.isNotEmpty() }
|
it[authorizedScopes] =
|
||||||
|
authorization.authorizedScopes.joinToString(",").takeIf { s -> s.isNotEmpty() }
|
||||||
it[attributes] = mapToJson(authorization.attributes)
|
it[attributes] = mapToJson(authorization.attributes)
|
||||||
it[state] = authorization.getAttribute(OAuth2ParameterNames.STATE)
|
it[state] = authorization.getAttribute(OAuth2ParameterNames.STATE)
|
||||||
it[authorizationCodeValue] = authorizationCodeToken?.token?.tokenValue
|
it[authorizationCodeValue] = authorizationCodeToken?.token?.tokenValue
|
||||||
|
@ -99,7 +101,8 @@ class ExposedOAuth2AuthorizationService(
|
||||||
it[registeredClientId] = authorization.registeredClientId
|
it[registeredClientId] = authorization.registeredClientId
|
||||||
it[principalName] = authorization.principalName
|
it[principalName] = authorization.principalName
|
||||||
it[authorizationGrantType] = authorization.authorizationGrantType.value
|
it[authorizationGrantType] = authorization.authorizationGrantType.value
|
||||||
it[authorizedScopes] = authorization.authorizedScopes.joinToString(",").takeIf { it.isNotEmpty() }
|
it[authorizedScopes] =
|
||||||
|
authorization.authorizedScopes.joinToString(",").takeIf { s -> s.isNotEmpty() }
|
||||||
it[attributes] = mapToJson(authorization.attributes)
|
it[attributes] = mapToJson(authorization.attributes)
|
||||||
it[state] = authorization.getAttribute(OAuth2ParameterNames.STATE)
|
it[state] = authorization.getAttribute(OAuth2ParameterNames.STATE)
|
||||||
it[authorizationCodeValue] = authorizationCodeToken?.token?.tokenValue
|
it[authorizationCodeValue] = authorizationCodeToken?.token?.tokenValue
|
||||||
|
@ -111,8 +114,9 @@ class ExposedOAuth2AuthorizationService(
|
||||||
it[accessTokenIssuedAt] = accessToken?.token?.issuedAt
|
it[accessTokenIssuedAt] = accessToken?.token?.issuedAt
|
||||||
it[accessTokenExpiresAt] = accessToken?.token?.expiresAt
|
it[accessTokenExpiresAt] = accessToken?.token?.expiresAt
|
||||||
it[accessTokenMetadata] = accessToken?.metadata?.let { it1 -> mapToJson(it1) }
|
it[accessTokenMetadata] = accessToken?.metadata?.let { it1 -> mapToJson(it1) }
|
||||||
it[accessTokenType] = accessToken?.token?.tokenType?.value
|
it[accessTokenType] = accessToken?.run { token.tokenType.value }
|
||||||
it[accessTokenScopes] = accessToken?.token?.scopes?.joinToString(",")?.takeIf { it.isNotEmpty() }
|
it[accessTokenScopes] =
|
||||||
|
accessToken?.run { token.scopes.joinToString(",").takeIf { s -> s.isNotEmpty() } }
|
||||||
it[refreshTokenValue] = refreshToken?.token?.tokenValue
|
it[refreshTokenValue] = refreshToken?.token?.tokenValue
|
||||||
it[refreshTokenIssuedAt] = refreshToken?.token?.issuedAt
|
it[refreshTokenIssuedAt] = refreshToken?.token?.issuedAt
|
||||||
it[refreshTokenExpiresAt] = refreshToken?.token?.expiresAt
|
it[refreshTokenExpiresAt] = refreshToken?.token?.expiresAt
|
||||||
|
@ -203,6 +207,7 @@ class ExposedOAuth2AuthorizationService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
fun ResultRow.toAuthorization(): OAuth2Authorization {
|
fun ResultRow.toAuthorization(): OAuth2Authorization {
|
||||||
val registeredClientId = this[Authorization.registeredClientId]
|
val registeredClientId = this[Authorization.registeredClientId]
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.service.auth
|
package dev.usbharu.hideout.service.auth
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.plugins.KtorKeyMap
|
import dev.usbharu.hideout.plugins.KtorKeyMap
|
||||||
import dev.usbharu.hideout.query.UserQueryService
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.core.Transaction
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
|
@ -15,10 +16,13 @@ interface HttpSignatureVerifyService {
|
||||||
@Service
|
@Service
|
||||||
class HttpSignatureVerifyServiceImpl(
|
class HttpSignatureVerifyServiceImpl(
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction,
|
||||||
|
private val applicationConfig: ApplicationConfig
|
||||||
) : HttpSignatureVerifyService {
|
) : HttpSignatureVerifyService {
|
||||||
override fun verify(headers: Headers): Boolean {
|
override fun verify(headers: Headers): Boolean {
|
||||||
val build = SignatureHeaderVerifier.builder().keyMap(KtorKeyMap(userQueryService, transaction)).build()
|
val build =
|
||||||
|
SignatureHeaderVerifier.builder().keyMap(KtorKeyMap(userQueryService, transaction, applicationConfig))
|
||||||
|
.build()
|
||||||
return true
|
return true
|
||||||
// build.verify(object : HttpMessage {
|
// build.verify(object : HttpMessage {
|
||||||
// override fun headerValues(name: String?): MutableList<String> {
|
// override fun headerValues(name: String?): MutableList<String> {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import org.springframework.security.core.userdetails.UserDetails
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService
|
import org.springframework.security.core.userdetails.UserDetailsService
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException
|
import org.springframework.security.core.userdetails.UsernameNotFoundException
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class UserDetailsServiceImpl(
|
class UserDetailsServiceImpl(
|
||||||
|
@ -23,16 +22,16 @@ class UserDetailsServiceImpl(
|
||||||
throw UsernameNotFoundException("$username not found")
|
throw UsernameNotFoundException("$username not found")
|
||||||
}
|
}
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
val findById = userQueryService.findByNameAndDomain(username, URL(applicationConfig.url).host)
|
val findById = userQueryService.findByNameAndDomain(username, applicationConfig.url.host)
|
||||||
UserDetailsImpl(
|
UserDetailsImpl(
|
||||||
findById.id,
|
id = findById.id,
|
||||||
findById.name,
|
username = findById.name,
|
||||||
findById.password,
|
password = findById.password,
|
||||||
true,
|
enabled = true,
|
||||||
true,
|
accountNonExpired = true,
|
||||||
true,
|
credentialsNonExpired = true,
|
||||||
true,
|
accountNonLocked = true,
|
||||||
mutableListOf()
|
authorities = mutableListOf()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package dev.usbharu.hideout.service.job
|
package dev.usbharu.hideout.service.job
|
||||||
|
|
||||||
import kjob.core.Job
|
|
||||||
import kjob.core.dsl.KJobFunctions
|
import kjob.core.dsl.KJobFunctions
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
import dev.usbharu.hideout.domain.model.job.HideoutJob as HJ
|
||||||
import kjob.core.dsl.JobContextWithProps as JCWP
|
import kjob.core.dsl.JobContextWithProps as JCWP
|
||||||
import kjob.core.dsl.JobRegisterContext as JRC
|
import kjob.core.dsl.JobRegisterContext as JRC
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
interface JobQueueWorkerService {
|
interface JobQueueWorkerService {
|
||||||
fun init(defines: List<Pair<Job, JRC<Job, JCWP<Job>>.(Job) -> KJobFunctions<Job, JCWP<Job>>>>)
|
fun init(
|
||||||
|
defines: List<Pair<HJ, JRC<HJ, JCWP<HJ>>.(HJ) -> KJobFunctions<HJ, JCWP<HJ>>>>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package dev.usbharu.hideout.service.job
|
package dev.usbharu.hideout.service.job
|
||||||
|
|
||||||
import dev.usbharu.kjob.exposed.ExposedKJob
|
import dev.usbharu.kjob.exposed.ExposedKJob
|
||||||
import kjob.core.Job
|
import kjob.core.dsl.JobRegisterContext
|
||||||
import kjob.core.dsl.KJobFunctions
|
import kjob.core.dsl.KJobFunctions
|
||||||
import kjob.core.kjob
|
import kjob.core.kjob
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
import dev.usbharu.hideout.domain.model.job.HideoutJob as HJ
|
||||||
import kjob.core.dsl.JobContextWithProps as JCWP
|
import kjob.core.dsl.JobContextWithProps as JCWP
|
||||||
import kjob.core.dsl.JobRegisterContext as JRC
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class KJobJobQueueWorkerService(private val database: Database) : JobQueueWorkerService {
|
class KJobJobQueueWorkerService(private val database: Database) : JobQueueWorkerService {
|
||||||
|
@ -22,7 +22,7 @@ class KJobJobQueueWorkerService(private val database: Database) : JobQueueWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun init(
|
override fun init(
|
||||||
defines: List<Pair<Job, JRC<Job, JCWP<Job>>.(Job) -> KJobFunctions<Job, JCWP<Job>>>>
|
defines: List<Pair<HJ, JobRegisterContext<HJ, JCWP<HJ>>.(HJ) -> KJobFunctions<HJ, JCWP<HJ>>>>
|
||||||
) {
|
) {
|
||||||
defines.forEach { job ->
|
defines.forEach { job ->
|
||||||
kjob.register(job.first, job.second)
|
kjob.register(job.first, job.second)
|
||||||
|
|
|
@ -25,15 +25,15 @@ class AccountServiceImpl(private val userQueryService: UserQueryService) : Accou
|
||||||
header = findById.url + "/header.jpg",
|
header = findById.url + "/header.jpg",
|
||||||
headerStatic = findById.url + "/header.jpg",
|
headerStatic = findById.url + "/header.jpg",
|
||||||
locked = false,
|
locked = false,
|
||||||
emptyList(),
|
fields = emptyList(),
|
||||||
emptyList(),
|
emojis = emptyList(),
|
||||||
false,
|
bot = false,
|
||||||
false,
|
group = false,
|
||||||
false,
|
discoverable = false,
|
||||||
findById.createdAt.toString(),
|
createdAt = findById.createdAt.toString(),
|
||||||
findById.createdAt.toString(),
|
lastStatusAt = findById.createdAt.toString(),
|
||||||
0,
|
statusesCount = 0,
|
||||||
0,
|
followersCount = 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,7 @@ class UserAuthServiceImpl(
|
||||||
val userQueryService: UserQueryService
|
val userQueryService: UserQueryService
|
||||||
) : UserAuthService {
|
) : UserAuthService {
|
||||||
|
|
||||||
override fun hash(password: String): String {
|
override fun hash(password: String): String = BCryptPasswordEncoder().encode(password)
|
||||||
return BCryptPasswordEncoder().encode(password)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
||||||
userQueryService.findByName(username)
|
userQueryService.findByName(username)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package dev.usbharu.hideout.service.user
|
package dev.usbharu.hideout.service.user
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.RemoteUserCreateDto
|
import dev.usbharu.hideout.domain.model.hideout.dto.RemoteUserCreateDto
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.SendFollowDto
|
import dev.usbharu.hideout.domain.model.hideout.dto.SendFollowDto
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
||||||
|
@ -19,12 +19,13 @@ class UserServiceImpl(
|
||||||
private val userAuthService: UserAuthService,
|
private val userAuthService: UserAuthService,
|
||||||
private val apSendFollowService: APSendFollowService,
|
private val apSendFollowService: APSendFollowService,
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val followerQueryService: FollowerQueryService
|
private val followerQueryService: FollowerQueryService,
|
||||||
|
private val applicationConfig: ApplicationConfig
|
||||||
) :
|
) :
|
||||||
UserService {
|
UserService {
|
||||||
|
|
||||||
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
||||||
val findByNameAndDomain = userQueryService.findByNameAndDomain(username, Config.configData.domain)
|
val findByNameAndDomain = userQueryService.findByNameAndDomain(username, applicationConfig.url.host)
|
||||||
return findByNameAndDomain != null
|
return findByNameAndDomain != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,13 +36,13 @@ class UserServiceImpl(
|
||||||
val userEntity = User.of(
|
val userEntity = User.of(
|
||||||
id = nextId,
|
id = nextId,
|
||||||
name = user.name,
|
name = user.name,
|
||||||
domain = Config.configData.domain,
|
domain = applicationConfig.url.host,
|
||||||
screenName = user.screenName,
|
screenName = user.screenName,
|
||||||
description = user.description,
|
description = user.description,
|
||||||
password = hashedPassword,
|
password = hashedPassword,
|
||||||
inbox = "${Config.configData.url}/users/${user.name}/inbox",
|
inbox = "${applicationConfig.url}/users/${user.name}/inbox",
|
||||||
outbox = "${Config.configData.url}/users/${user.name}/outbox",
|
outbox = "${applicationConfig.url}/users/${user.name}/outbox",
|
||||||
url = "${Config.configData.url}/users/${user.name}",
|
url = "${applicationConfig.url}/users/${user.name}",
|
||||||
publicKey = keyPair.public.toPem(),
|
publicKey = keyPair.public.toPem(),
|
||||||
privateKey = keyPair.private.toPem(),
|
privateKey = keyPair.private.toPem(),
|
||||||
createdAt = Instant.now()
|
createdAt = Instant.now()
|
||||||
|
@ -70,7 +71,7 @@ class UserServiceImpl(
|
||||||
override suspend fun followRequest(id: Long, followerId: Long): Boolean {
|
override suspend fun followRequest(id: Long, followerId: Long): Boolean {
|
||||||
val user = userRepository.findById(id) ?: throw UserNotFoundException("$id was not found.")
|
val user = userRepository.findById(id) ?: throw UserNotFoundException("$id was not found.")
|
||||||
val follower = userRepository.findById(followerId) ?: throw UserNotFoundException("$followerId was not found.")
|
val follower = userRepository.findById(followerId) ?: throw UserNotFoundException("$followerId was not found.")
|
||||||
return if (user.domain == Config.configData.domain) {
|
return if (user.domain == applicationConfig.url.host) {
|
||||||
follow(id, followerId)
|
follow(id, followerId)
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
package dev.usbharu.hideout.util
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
|
||||||
|
|
||||||
object JsonUtil {
|
|
||||||
val objectMapper = jacksonObjectMapper().registerModule(JavaTimeModule())
|
|
||||||
|
|
||||||
fun mapToJson(map: Map<*, *>, objectMapper: ObjectMapper = this.objectMapper): String =
|
|
||||||
objectMapper.writeValueAsString(map)
|
|
||||||
|
|
||||||
fun <K, V> jsonToMap(json: String, objectMapper: ObjectMapper = this.objectMapper): Map<K, V> =
|
|
||||||
objectMapper.readValue(json)
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package dev.usbharu.hideout.util
|
|
||||||
|
|
||||||
import java.math.BigInteger
|
|
||||||
import java.security.KeyFactory
|
|
||||||
import java.security.interfaces.RSAPublicKey
|
|
||||||
import java.security.spec.X509EncodedKeySpec
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
object JsonWebKeyUtil {
|
|
||||||
|
|
||||||
fun publicKeyToJwk(publicKey: String, kid: String): String {
|
|
||||||
val x509EncodedKeySpec = X509EncodedKeySpec(Base64.getDecoder().decode(publicKey))
|
|
||||||
val generatePublic = KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec)
|
|
||||||
return publicKeyToJwk(generatePublic as RSAPublicKey, kid)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun publicKeyToJwk(publicKey: RSAPublicKey, kid: String): String {
|
|
||||||
val e = encodeBase64UInt(publicKey.publicExponent)
|
|
||||||
val n = encodeBase64UInt(publicKey.modulus)
|
|
||||||
return """{"keys":[{"e":"$e","n":"$n","use":"sig","kid":"$kid","kty":"RSA"}]}"""
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun encodeBase64UInt(bigInteger: BigInteger, minLength: Int = -1): String {
|
|
||||||
require(bigInteger.signum() >= 0) { "Cannot encode negative numbers" }
|
|
||||||
|
|
||||||
var bytes = bigInteger.toByteArray()
|
|
||||||
if (bigInteger.bitLength() % 8 == 0 && (bytes[0] == 0.toByte()) && bytes.size > 1) {
|
|
||||||
bytes = Arrays.copyOfRange(bytes, 1, bytes.size)
|
|
||||||
}
|
|
||||||
if (minLength != -1) {
|
|
||||||
if (bytes.size < minLength) {
|
|
||||||
val array = ByteArray(minLength)
|
|
||||||
System.arraycopy(bytes, 0, array, minLength - bytes.size, bytes.size)
|
|
||||||
bytes = array
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@
|
||||||
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
<root level="TRACE">
|
<root level="DEBUG">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
</root>
|
</root>
|
||||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||||
|
@ -12,5 +12,5 @@
|
||||||
<logger name="kjob.core.internal.scheduler.JobServiceImpl" level="INFO"/>
|
<logger name="kjob.core.internal.scheduler.JobServiceImpl" level="INFO"/>
|
||||||
<logger name="Exposed" level="INFO"/>
|
<logger name="Exposed" level="INFO"/>
|
||||||
<logger name="io.ktor.server.plugins.contentnegotiation" level="INFO"/>
|
<logger name="io.ktor.server.plugins.contentnegotiation" level="INFO"/>
|
||||||
<logger name="org.springframework.security" level="trace"/>
|
<logger name="org.springframework.security" level="DEBUG"/>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -12,6 +12,8 @@ import org.junit.jupiter.api.Test
|
||||||
import org.mockito.kotlin.any
|
import org.mockito.kotlin.any
|
||||||
import org.mockito.kotlin.doAnswer
|
import org.mockito.kotlin.doAnswer
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
|
import utils.JsonObjectMapper.objectMapper
|
||||||
|
import utils.TestApplicationConfig.testApplicationConfig
|
||||||
import utils.TestTransaction
|
import utils.TestTransaction
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
@ -41,7 +43,7 @@ class ActivityPubKtTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val ktorKeyMap = KtorKeyMap(userQueryService, TestTransaction)
|
val ktorKeyMap = KtorKeyMap(userQueryService, TestTransaction, testApplicationConfig)
|
||||||
|
|
||||||
val httpClient = HttpClient(
|
val httpClient = HttpClient(
|
||||||
MockEngine { httpRequestData ->
|
MockEngine { httpRequestData ->
|
||||||
|
@ -57,7 +59,7 @@ class ActivityPubKtTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
httpClient.postAp("https://localhost", "test", JsonLd(emptyList()))
|
httpClient.postAp("https://localhost", "test", JsonLd(emptyList()), objectMapper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test
|
||||||
import org.mockito.kotlin.any
|
import org.mockito.kotlin.any
|
||||||
import org.mockito.kotlin.doAnswer
|
import org.mockito.kotlin.doAnswer
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
|
import utils.TestApplicationConfig.testApplicationConfig
|
||||||
import utils.TestTransaction
|
import utils.TestTransaction
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
@ -36,7 +37,7 @@ class KtorKeyMapTest {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val ktorKeyMap = KtorKeyMap(userQueryService, TestTransaction)
|
val ktorKeyMap = KtorKeyMap(userQueryService, TestTransaction, testApplicationConfig)
|
||||||
|
|
||||||
ktorKeyMap.getPrivateKey("test")
|
ktorKeyMap.getPrivateKey("test")
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,15 @@ import org.junit.jupiter.api.Test
|
||||||
import org.mockito.Mockito.eq
|
import org.mockito.Mockito.eq
|
||||||
import org.mockito.kotlin.*
|
import org.mockito.kotlin.*
|
||||||
import utils.JsonObjectMapper
|
import utils.JsonObjectMapper
|
||||||
|
import utils.JsonObjectMapper.objectMapper
|
||||||
|
import utils.TestApplicationConfig.testApplicationConfig
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class APNoteServiceImplTest {
|
class APNoteServiceImplTest {
|
||||||
@Test
|
@Test
|
||||||
fun `createPost 新しい投稿`() = runTest {
|
fun `createPost 新しい投稿`() = runTest {
|
||||||
val followers = listOf<User>(
|
val followers = listOf(
|
||||||
User.of(
|
User.of(
|
||||||
2L,
|
2L,
|
||||||
"follower",
|
"follower",
|
||||||
|
@ -84,7 +86,9 @@ class APNoteServiceImplTest {
|
||||||
mock(),
|
mock(),
|
||||||
userQueryService,
|
userQueryService,
|
||||||
followerQueryService,
|
followerQueryService,
|
||||||
mock()
|
mock(),
|
||||||
|
objectMapper = objectMapper,
|
||||||
|
applicationConfig = testApplicationConfig
|
||||||
)
|
)
|
||||||
val postEntity = Post.of(
|
val postEntity = Post.of(
|
||||||
1L,
|
1L,
|
||||||
|
@ -109,13 +113,15 @@ class APNoteServiceImplTest {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val activityPubNoteService = APNoteServiceImpl(
|
val activityPubNoteService = APNoteServiceImpl(
|
||||||
httpClient,
|
httpClient = httpClient,
|
||||||
mock(),
|
jobQueueParentService = mock(),
|
||||||
mock(),
|
postRepository = mock(),
|
||||||
mock(),
|
apUserService = mock(),
|
||||||
mock(),
|
userQueryService = mock(),
|
||||||
mock(),
|
followerQueryService = mock(),
|
||||||
mock()
|
postQueryService = mock(),
|
||||||
|
objectMapper = objectMapper,
|
||||||
|
applicationConfig = testApplicationConfig
|
||||||
)
|
)
|
||||||
activityPubNoteService.createNoteJob(
|
activityPubNoteService.createNoteJob(
|
||||||
JobProps(
|
JobProps(
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test
|
||||||
import org.mockito.ArgumentMatchers.anyString
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
import org.mockito.kotlin.*
|
import org.mockito.kotlin.*
|
||||||
import utils.JsonObjectMapper
|
import utils.JsonObjectMapper
|
||||||
|
import utils.JsonObjectMapper.objectMapper
|
||||||
import utils.TestTransaction
|
import utils.TestTransaction
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@ -34,7 +35,10 @@ class APReceiveFollowServiceImplTest {
|
||||||
onBlocking { schedule(eq(ReceiveFollowJob), any()) } doReturn Unit
|
onBlocking { schedule(eq(ReceiveFollowJob), any()) } doReturn Unit
|
||||||
}
|
}
|
||||||
val activityPubFollowService =
|
val activityPubFollowService =
|
||||||
APReceiveFollowServiceImpl(jobQueueParentService, mock(), mock(), mock(), mock(), TestTransaction)
|
APReceiveFollowServiceImpl(
|
||||||
|
jobQueueParentService, mock(), mock(), mock(), mock(), TestTransaction,
|
||||||
|
objectMapper
|
||||||
|
)
|
||||||
activityPubFollowService.receiveFollow(
|
activityPubFollowService.receiveFollow(
|
||||||
Follow(
|
Follow(
|
||||||
emptyList(),
|
emptyList(),
|
||||||
|
@ -163,7 +167,8 @@ class APReceiveFollowServiceImplTest {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
userQueryService,
|
userQueryService,
|
||||||
TestTransaction
|
TestTransaction,
|
||||||
|
objectMapper
|
||||||
)
|
)
|
||||||
activityPubFollowService.receiveFollowJob(
|
activityPubFollowService.receiveFollowJob(
|
||||||
JobProps(
|
JobProps(
|
||||||
|
|
|
@ -12,6 +12,7 @@ import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.mockito.ArgumentMatchers.anyString
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
import org.mockito.kotlin.*
|
import org.mockito.kotlin.*
|
||||||
|
import utils.TestApplicationConfig.testApplicationConfig
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
@ -28,7 +29,8 @@ class UserServiceTest {
|
||||||
onBlocking { hash(anyString()) } doReturn "hashedPassword"
|
onBlocking { hash(anyString()) } doReturn "hashedPassword"
|
||||||
onBlocking { generateKeyPair() } doReturn generateKeyPair
|
onBlocking { generateKeyPair() } doReturn generateKeyPair
|
||||||
}
|
}
|
||||||
val userService = UserServiceImpl(userRepository, userAuthService, mock(), mock(), mock())
|
val userService =
|
||||||
|
UserServiceImpl(userRepository, userAuthService, mock(), mock(), mock(), testApplicationConfig)
|
||||||
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
|
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
|
||||||
verify(userRepository, times(1)).save(any())
|
verify(userRepository, times(1)).save(any())
|
||||||
argumentCaptor<dev.usbharu.hideout.domain.model.hideout.entity.User> {
|
argumentCaptor<dev.usbharu.hideout.domain.model.hideout.entity.User> {
|
||||||
|
@ -54,7 +56,7 @@ class UserServiceTest {
|
||||||
val userRepository = mock<UserRepository> {
|
val userRepository = mock<UserRepository> {
|
||||||
onBlocking { nextId() } doReturn 113345L
|
onBlocking { nextId() } doReturn 113345L
|
||||||
}
|
}
|
||||||
val userService = UserServiceImpl(userRepository, mock(), mock(), mock(), mock())
|
val userService = UserServiceImpl(userRepository, mock(), mock(), mock(), mock(), testApplicationConfig)
|
||||||
val user = RemoteUserCreateDto(
|
val user = RemoteUserCreateDto(
|
||||||
"test",
|
"test",
|
||||||
"example.com",
|
"example.com",
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.config.ApplicationConfig
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
object TestApplicationConfig {
|
||||||
|
val testApplicationConfig = ApplicationConfig(URL("https://example.com"))
|
||||||
|
}
|
Loading…
Reference in New Issue