style: スタイルを修正

This commit is contained in:
usbharu 2023-10-14 23:34:57 +09:00
parent 25ad32918b
commit ae376d55d0
16 changed files with 60 additions and 94 deletions

View File

@ -127,16 +127,16 @@ class APNoteServiceImpl(
transaction.transaction { transaction.transaction {
val signer = userQueryService.findByUrl(actor) val signer = userQueryService.findByUrl(actor)
apRequestService.apPost( apRequestService.apPost(
inbox, Create( inbox,
Create(
name = "Create Note", name = "Create Note",
`object` = note, `object` = note,
actor = note.attributedTo, actor = note.attributedTo,
id = "${applicationConfig.url}/create/note/${postEntity.id}" id = "${applicationConfig.url}/create/note/${postEntity.id}"
), signer ),
signer
) )
} }
} }
override suspend fun fetchNote(url: String, targetActor: String?): Note { override suspend fun fetchNote(url: String, targetActor: String?): Note {

View File

@ -12,7 +12,6 @@ import dev.usbharu.hideout.query.FollowerQueryService
import dev.usbharu.hideout.query.PostQueryService import dev.usbharu.hideout.query.PostQueryService
import dev.usbharu.hideout.query.UserQueryService 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 kjob.core.job.JobProps import kjob.core.job.JobProps
import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -28,7 +27,6 @@ interface APReactionService {
@Service @Service
class APReactionServiceImpl( class APReactionServiceImpl(
private val jobQueueParentService: JobQueueParentService, private val jobQueueParentService: JobQueueParentService,
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,
@ -77,13 +75,15 @@ class APReactionServiceImpl(
val signer = userQueryService.findByUrl(actor) val signer = userQueryService.findByUrl(actor)
apRequestService.apPost( apRequestService.apPost(
inbox, Like( inbox,
Like(
name = "Like", name = "Like",
actor = actor, actor = actor,
`object` = postUrl, `object` = postUrl,
id = "${applicationConfig.url}/like/note/$id", id = "${applicationConfig.url}/like/note/$id",
content = content content = content
), signer ),
signer
) )
} }
@ -95,13 +95,15 @@ class APReactionServiceImpl(
val signer = userQueryService.findByUrl(actor) val signer = userQueryService.findByUrl(actor)
apRequestService.apPost( apRequestService.apPost(
inbox, Undo( inbox,
Undo(
name = "Undo Reaction", name = "Undo Reaction",
actor = actor, actor = actor,
`object` = like, `object` = like,
id = "${applicationConfig.url}/undo/note/${like.id}", id = "${applicationConfig.url}/undo/note/${like.id}",
published = Instant.now() published = Instant.now()
), signer ),
signer
) )
} }
} }

View File

@ -11,7 +11,6 @@ import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.service.core.Transaction import dev.usbharu.hideout.service.core.Transaction
import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.job.JobQueueParentService
import dev.usbharu.hideout.service.user.UserService import dev.usbharu.hideout.service.user.UserService
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.beans.factory.annotation.Qualifier
@ -27,7 +26,6 @@ class APReceiveFollowServiceImpl(
private val jobQueueParentService: JobQueueParentService, private val jobQueueParentService: JobQueueParentService,
private val apUserService: APUserService, private val apUserService: APUserService,
private val userService: UserService, private val userService: UserService,
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, @Qualifier("activitypub") private val objectMapper: ObjectMapper,
@ -56,11 +54,13 @@ class APReceiveFollowServiceImpl(
val urlString = person.inbox ?: throw IllegalArgumentException("inbox is not found") val urlString = person.inbox ?: throw IllegalArgumentException("inbox is not found")
apRequestService.apPost( apRequestService.apPost(
urlString, Accept( urlString,
Accept(
name = "Follow", name = "Follow",
`object` = follow, `object` = follow,
actor = targetActor actor = targetActor
), signer ),
signer
) )
val targetEntity = userQueryService.findByUrl(targetActor) val targetEntity = userQueryService.findByUrl(targetActor)

View File

@ -29,7 +29,6 @@ class APRequestServiceImpl(
) : APRequestService { ) : APRequestService {
override suspend fun <R : Object> apGet(url: String, signer: User?, responseClass: Class<R>): R { override suspend fun <R : Object> apGet(url: String, signer: User?, responseClass: Class<R>): R {
val date = dateTimeFormatter.format(ZonedDateTime.now(ZoneId.of("GMT"))) val date = dateTimeFormatter.format(ZonedDateTime.now(ZoneId.of("GMT")))
val u = URL(url) val u = URL(url)
if (signer?.privateKey == null) { if (signer?.privateKey == null) {
@ -47,11 +46,16 @@ class APRequestServiceImpl(
} }
val sign = httpSignatureSigner.sign( val sign = httpSignatureSigner.sign(
url, HttpMethod.Get, headers, "", Key( url = url,
method = HttpMethod.Get,
headers = headers,
requestBody = "",
keyPair = Key(
keyId = "${signer.url}#pubkey", keyId = "${signer.url}#pubkey",
privateKey = RsaUtil.decodeRsaPrivateKeyPem(signer.privateKey), privateKey = RsaUtil.decodeRsaPrivateKeyPem(signer.privateKey),
publicKey = RsaUtil.decodeRsaPublicKeyPem(signer.publicKey) publicKey = RsaUtil.decodeRsaPublicKeyPem(signer.publicKey)
), listOf("(request-target)", "date", "host", "accept") ),
signHeaders = listOf("(request-target)", "date", "host", "accept")
) )
val bodyAsText = httpClient.get(url) { val bodyAsText = httpClient.get(url) {
@ -77,7 +81,6 @@ class APRequestServiceImpl(
} }
override suspend fun <T : Object> apPost(url: String, body: T?, signer: User?): String { override suspend fun <T : Object> apPost(url: String, body: T?, signer: User?): String {
if (body != null) { if (body != null) {
val mutableListOf = mutableListOf<String>() val mutableListOf = mutableListOf<String>()
mutableListOf.add("https://www.w3.org/ns/activitystreams") mutableListOf.add("https://www.w3.org/ns/activitystreams")
@ -111,11 +114,16 @@ class APRequestServiceImpl(
} }
val sign = httpSignatureSigner.sign( val sign = httpSignatureSigner.sign(
url, HttpMethod.Post, headers, "", Key( url = url,
method = HttpMethod.Post,
headers = headers,
requestBody = "",
keyPair = Key(
keyId = "${signer.url}#pubkey", keyId = "${signer.url}#pubkey",
privateKey = RsaUtil.decodeRsaPrivateKeyPem(signer.privateKey), privateKey = RsaUtil.decodeRsaPrivateKeyPem(signer.privateKey),
publicKey = RsaUtil.decodeRsaPublicKeyPem(signer.publicKey) publicKey = RsaUtil.decodeRsaPublicKeyPem(signer.publicKey)
), listOf("(request-target)", "date", "host", "digest") ),
signHeaders = listOf("(request-target)", "date", "host", "digest")
) )
return httpClient.post(url) { return httpClient.post(url) {

View File

@ -1,9 +1,7 @@
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 org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
interface APSendFollowService { interface APSendFollowService {
@ -12,7 +10,6 @@ interface APSendFollowService {
@Service @Service
class APSendFollowServiceImpl( class APSendFollowServiceImpl(
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
private val apRequestService: APRequestService, private val apRequestService: APRequestService,
) : APSendFollowService { ) : APSendFollowService {
override suspend fun sendFollow(sendFollowDto: SendFollowDto) { override suspend fun sendFollow(sendFollowDto: SendFollowDto) {

View File

@ -103,7 +103,6 @@ class APUserServiceImpl(
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox") endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox")
) to userEntity ) to userEntity
} catch (ignore: FailedToGetResourcesException) { } catch (ignore: FailedToGetResourcesException) {
val person = apResourceResolveService.resolve<Person>(url, null as Long?) val person = apResourceResolveService.resolve<Person>(url, null as Long?)
person to userService.createRemoteUser( person to userService.createRemoteUser(

View File

@ -8,10 +8,8 @@ interface APResourceResolveService {
suspend fun <T : Object> resolve(url: String, clazz: Class<T>, singerId: Long?): T suspend fun <T : Object> resolve(url: String, clazz: Class<T>, singerId: Long?): T
} }
suspend inline fun <reified T : Object> APResourceResolveService.resolve(url: String, singer: User?): T { suspend inline fun <reified T : Object> APResourceResolveService.resolve(url: String, singer: User?): T =
return resolve(url, T::class.java, singer) resolve(url, T::class.java, singer)
}
suspend inline fun <reified T : Object> APResourceResolveService.resolve(url: String, singerId: Long?): T { suspend inline fun <reified T : Object> APResourceResolveService.resolve(url: String, singerId: Long?): T =
return resolve(url, T::class.java, singerId) resolve(url, T::class.java, singerId)
}

View File

@ -1,32 +1,26 @@
package dev.usbharu.hideout.service.ap.resource package dev.usbharu.hideout.service.ap.resource
import com.fasterxml.jackson.databind.ObjectMapper
import dev.usbharu.hideout.domain.model.ap.Object import dev.usbharu.hideout.domain.model.ap.Object
import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.domain.model.hideout.entity.User
import dev.usbharu.hideout.repository.UserRepository import dev.usbharu.hideout.repository.UserRepository
import dev.usbharu.hideout.service.ap.APRequestService import dev.usbharu.hideout.service.ap.APRequestService
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class APResourceResolveServiceImpl( class APResourceResolveServiceImpl(
private val apRequestService: APRequestService, private val apRequestService: APRequestService,
private val userRepository: UserRepository, private val userRepository: UserRepository,
private val cacheManager: CacheManager, private val cacheManager: CacheManager
@Qualifier("activitypub") private val objectMapper: ObjectMapper
) : ) :
APResourceResolveService { APResourceResolveService {
override suspend fun <T : Object> resolve(url: String, clazz: Class<T>, singerId: Long?): T { override suspend fun <T : Object> resolve(url: String, clazz: Class<T>, singerId: Long?): T =
return internalResolve(url, singerId, clazz) internalResolve(url, singerId, clazz)
}
override suspend fun <T : Object> resolve(url: String, clazz: Class<T>, singer: User?): T { override suspend fun <T : Object> resolve(url: String, clazz: Class<T>, singer: User?): T =
return internalResolve(url, singer, clazz) internalResolve(url, singer, clazz)
}
private suspend fun <T : Object> internalResolve(url: String, singerId: Long?, clazz: Class<T>): T { private suspend fun <T : Object> internalResolve(url: String, singerId: Long?, clazz: Class<T>): T {
val key = genCacheKey(url, singerId) val key = genCacheKey(url, singerId)
cacheManager.putCache(key) { cacheManager.putCache(key) {
@ -43,9 +37,8 @@ class APResourceResolveServiceImpl(
return cacheManager.getOrWait(key) as T return cacheManager.getOrWait(key) as T
} }
private suspend fun <T : Object> runResolve(url: String, singer: User?, clazz: Class<T>): Object { private suspend fun <T : Object> runResolve(url: String, singer: User?, clazz: Class<T>): Object =
return apRequestService.apGet(url, singer, clazz) apRequestService.apGet(url, singer, clazz)
}
private fun genCacheKey(url: String, singerId: Long?): String { private fun genCacheKey(url: String, singerId: Long?): String {
if (singerId != null) { if (singerId != null) {

View File

@ -35,12 +35,10 @@ class InMemoryCacheManager : CacheManager {
if (cacheKey.containsKey(key)) { if (cacheKey.containsKey(key)) {
valueStore[key] = processed valueStore[key] = processed
} }
} }
} }
override suspend fun getOrWait(key: String): Object { override suspend fun getOrWait(key: String): Object {
while (valueStore.contains(key).not()) { while (valueStore.contains(key).not()) {
if (cacheKey.containsKey(key).not()) { if (cacheKey.containsKey(key).not()) {
throw IllegalStateException("Invalid cache key.") throw IllegalStateException("Invalid cache key.")
@ -48,6 +46,5 @@ class InMemoryCacheManager : CacheManager {
delay(1) delay(1)
} }
return valueStore.getValue(key) return valueStore.getValue(key)
} }
} }

View File

@ -3,6 +3,7 @@ package dev.usbharu.hideout.service.signature
import io.ktor.http.* import io.ktor.http.*
interface HttpSignatureSigner { interface HttpSignatureSigner {
@Suppress("LongParameterList")
suspend fun sign( suspend fun sign(
url: String, url: String,
method: HttpMethod, method: HttpMethod,

View File

@ -48,7 +48,11 @@ class HttpSignatureSignerImpl : HttpSignatureSigner {
val signature = Base64Util.encode(sign) val signature = Base64Util.encode(sign)
return Sign( return Sign(
signature, signature,
"""keyId="${keyPair.keyId}",algorithm="rsa-sha256",headers="${signHeaders.joinToString(" ")}",signature="$signature"""" """keyId="${keyPair.keyId}",algorithm="rsa-sha256",headers="${
signHeaders.joinToString(
" "
)
}",signature="$signature""""
) )
} }
@ -76,7 +80,5 @@ class HttpSignatureSignerImpl : HttpSignatureSigner {
return "(request-target): ${method.value.lowercase()} ${url.path}" return "(request-target): ${method.value.lowercase()} ${url.path}"
} }
private fun generalHeader(fieldName: String, value: String): String { private fun generalHeader(fieldName: String, value: String): String = "$fieldName: $value"
return "$fieldName: $value"
}
} }

View File

@ -17,8 +17,7 @@ object HttpUtil {
fun isContentTypeOfActivityPub( fun isContentTypeOfActivityPub(
contentType: String, contentType: String,
subType: String, subType: String
parameter: String
): Boolean { ): Boolean {
if (contentType != "application") { if (contentType != "application") {
return false return false
@ -32,8 +31,7 @@ object HttpUtil {
fun isContentTypeOfActivityPub(contentType: ContentType): Boolean { fun isContentTypeOfActivityPub(contentType: ContentType): Boolean {
return isContentTypeOfActivityPub( return isContentTypeOfActivityPub(
contentType.contentType, contentType.contentType,
contentType.contentSubtype, contentType.contentSubtype
contentType.parameter("profile").orEmpty()
) )
} }
// fun // fun

View File

@ -10,5 +10,4 @@ class LruCache<K, V>(private val maxSize: Int) : LinkedHashMap<K, V>(15, 0.75f,
@Serial @Serial
private const val serialVersionUID: Long = -6446947260925053191L private const val serialVersionUID: Long = -6446947260925053191L
} }
} }

View File

@ -7,6 +7,8 @@ import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec import java.security.spec.X509EncodedKeySpec
object RsaUtil { object RsaUtil {
private val replaceHeaderAndFooterRegex = Regex("-----.*?-----")
fun decodeRsaPublicKey(byteArray: ByteArray): RSAPublicKey { fun decodeRsaPublicKey(byteArray: ByteArray): RSAPublicKey {
val x509EncodedKeySpec = X509EncodedKeySpec(byteArray) val x509EncodedKeySpec = X509EncodedKeySpec(byteArray)
return KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec) as RSAPublicKey return KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec) as RSAPublicKey
@ -32,6 +34,4 @@ object RsaUtil {
.replace("\n", "") .replace("\n", "")
return decodeRsaPrivateKey(replace) return decodeRsaPrivateKey(replace)
} }
private val replaceHeaderAndFooterRegex = Regex("-----.*?-----")
} }

View File

@ -3,17 +3,17 @@
package dev.usbharu.hideout.service.ap package dev.usbharu.hideout.service.ap
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.config.Config import dev.usbharu.hideout.config.Config
import dev.usbharu.hideout.config.ConfigData import dev.usbharu.hideout.config.ConfigData
import dev.usbharu.hideout.domain.model.ap.* import dev.usbharu.hideout.domain.model.ap.Follow
import dev.usbharu.hideout.domain.model.ap.Image
import dev.usbharu.hideout.domain.model.ap.Key
import dev.usbharu.hideout.domain.model.ap.Person
import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.domain.model.hideout.entity.User
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.job.JobQueueParentService
import dev.usbharu.hideout.service.user.UserService import dev.usbharu.hideout.service.user.UserService
import io.ktor.client.*
import io.ktor.client.engine.mock.*
import kjob.core.dsl.ScheduleContext import kjob.core.dsl.ScheduleContext
import kjob.core.job.JobProps import kjob.core.job.JobProps
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -40,7 +40,6 @@ class APReceiveFollowServiceImplTest {
mock(), mock(),
mock(), mock(),
mock(), mock(),
mock(),
TestTransaction, TestTransaction,
objectMapper, objectMapper,
mock() mock()
@ -146,32 +145,6 @@ class APReceiveFollowServiceImplTest {
mock(), mock(),
apUserService, apUserService,
userService, userService,
HttpClient(
MockEngine { httpRequestData ->
assertEquals(person.inbox, httpRequestData.url.toString())
val accept = Accept(
type = emptyList(),
name = "Follow",
`object` = Follow(
type = emptyList(),
name = "Follow",
`object` = "https://example.com",
actor = "https://follower.example.com"
),
actor = "https://example.com"
)
accept.context += "https://www.w3.org/ns/activitystreams"
val content = httpRequestData.body.toByteArray().decodeToString()
println(content)
assertEquals(
accept,
Config.configData.objectMapper.readValue<Accept>(
content
)
)
respondOk()
}
),
userQueryService, userQueryService,
TestTransaction, TestTransaction,
objectMapper, objectMapper,

View File

@ -16,7 +16,6 @@ import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
import utils.JsonObjectMapper.objectMapper
import java.time.Instant import java.time.Instant
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -53,7 +52,7 @@ class APResourceResolveServiceImplTest {
) )
val apResourceResolveService = val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager(), objectMapper) APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager())
apResourceResolveService.resolve<Object>("https", 0) apResourceResolveService.resolve<Object>("https", 0)
@ -88,7 +87,7 @@ class APResourceResolveServiceImplTest {
) )
val apResourceResolveService = val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager(), objectMapper) APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager())
apResourceResolveService.resolve<Object>("https", 0) apResourceResolveService.resolve<Object>("https", 0)
apResourceResolveService.resolve<Object>("https", 0) apResourceResolveService.resolve<Object>("https", 0)
@ -126,7 +125,7 @@ class APResourceResolveServiceImplTest {
) )
val apResourceResolveService = val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager(), objectMapper) APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager())
repeat(10) { repeat(10) {
awaitAll( awaitAll(
@ -175,7 +174,7 @@ class APResourceResolveServiceImplTest {
) )
val apResourceResolveService = val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager(), objectMapper) APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager())
apResourceResolveService.resolve<Object>("abcd", 0) apResourceResolveService.resolve<Object>("abcd", 0)
apResourceResolveService.resolve<Object>("1234", 0) apResourceResolveService.resolve<Object>("1234", 0)