diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt index 071e6930..a989af78 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt @@ -127,16 +127,16 @@ class APNoteServiceImpl( transaction.transaction { val signer = userQueryService.findByUrl(actor) apRequestService.apPost( - inbox, Create( + inbox, + Create( name = "Create Note", `object` = note, actor = note.attributedTo, id = "${applicationConfig.url}/create/note/${postEntity.id}" - ), signer + ), + signer ) } - - } override suspend fun fetchNote(url: String, targetActor: String?): Note { diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APReactionService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APReactionService.kt index 1833b08d..5a8cb788 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APReactionService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APReactionService.kt @@ -12,7 +12,6 @@ import dev.usbharu.hideout.query.FollowerQueryService import dev.usbharu.hideout.query.PostQueryService import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.service.job.JobQueueParentService -import io.ktor.client.* import kjob.core.job.JobProps import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Service @@ -28,7 +27,6 @@ interface APReactionService { @Service class APReactionServiceImpl( private val jobQueueParentService: JobQueueParentService, - private val httpClient: HttpClient, private val userQueryService: UserQueryService, private val followerQueryService: FollowerQueryService, private val postQueryService: PostQueryService, @@ -77,13 +75,15 @@ class APReactionServiceImpl( val signer = userQueryService.findByUrl(actor) apRequestService.apPost( - inbox, Like( + inbox, + Like( name = "Like", actor = actor, `object` = postUrl, id = "${applicationConfig.url}/like/note/$id", content = content - ), signer + ), + signer ) } @@ -95,13 +95,15 @@ class APReactionServiceImpl( val signer = userQueryService.findByUrl(actor) apRequestService.apPost( - inbox, Undo( + inbox, + Undo( name = "Undo Reaction", actor = actor, `object` = like, id = "${applicationConfig.url}/undo/note/${like.id}", published = Instant.now() - ), signer + ), + signer ) } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APReceiveFollowService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APReceiveFollowService.kt index 28f277da..38af4dd2 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APReceiveFollowService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APReceiveFollowService.kt @@ -11,7 +11,6 @@ import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.service.core.Transaction import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.user.UserService -import io.ktor.client.* import io.ktor.http.* import kjob.core.job.JobProps import org.springframework.beans.factory.annotation.Qualifier @@ -27,7 +26,6 @@ class APReceiveFollowServiceImpl( private val jobQueueParentService: JobQueueParentService, private val apUserService: APUserService, private val userService: UserService, - private val httpClient: HttpClient, private val userQueryService: UserQueryService, private val transaction: Transaction, @Qualifier("activitypub") private val objectMapper: ObjectMapper, @@ -56,11 +54,13 @@ class APReceiveFollowServiceImpl( val urlString = person.inbox ?: throw IllegalArgumentException("inbox is not found") apRequestService.apPost( - urlString, Accept( + urlString, + Accept( name = "Follow", `object` = follow, actor = targetActor - ), signer + ), + signer ) val targetEntity = userQueryService.findByUrl(targetActor) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APRequestServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APRequestServiceImpl.kt index 972c75b5..4d8e227d 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APRequestServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APRequestServiceImpl.kt @@ -29,7 +29,6 @@ class APRequestServiceImpl( ) : APRequestService { override suspend fun apGet(url: String, signer: User?, responseClass: Class): R { - val date = dateTimeFormatter.format(ZonedDateTime.now(ZoneId.of("GMT"))) val u = URL(url) if (signer?.privateKey == null) { @@ -47,11 +46,16 @@ class APRequestServiceImpl( } val sign = httpSignatureSigner.sign( - url, HttpMethod.Get, headers, "", Key( + url = url, + method = HttpMethod.Get, + headers = headers, + requestBody = "", + keyPair = Key( keyId = "${signer.url}#pubkey", privateKey = RsaUtil.decodeRsaPrivateKeyPem(signer.privateKey), publicKey = RsaUtil.decodeRsaPublicKeyPem(signer.publicKey) - ), listOf("(request-target)", "date", "host", "accept") + ), + signHeaders = listOf("(request-target)", "date", "host", "accept") ) val bodyAsText = httpClient.get(url) { @@ -77,7 +81,6 @@ class APRequestServiceImpl( } override suspend fun apPost(url: String, body: T?, signer: User?): String { - if (body != null) { val mutableListOf = mutableListOf() mutableListOf.add("https://www.w3.org/ns/activitystreams") @@ -111,11 +114,16 @@ class APRequestServiceImpl( } val sign = httpSignatureSigner.sign( - url, HttpMethod.Post, headers, "", Key( + url = url, + method = HttpMethod.Post, + headers = headers, + requestBody = "", + keyPair = Key( keyId = "${signer.url}#pubkey", privateKey = RsaUtil.decodeRsaPrivateKeyPem(signer.privateKey), publicKey = RsaUtil.decodeRsaPublicKeyPem(signer.publicKey) - ), listOf("(request-target)", "date", "host", "digest") + ), + signHeaders = listOf("(request-target)", "date", "host", "digest") ) return httpClient.post(url) { diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APSendFollowService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APSendFollowService.kt index 91fe53b9..0bc74d60 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APSendFollowService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APSendFollowService.kt @@ -1,9 +1,7 @@ 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.hideout.dto.SendFollowDto -import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Service interface APSendFollowService { @@ -12,7 +10,6 @@ interface APSendFollowService { @Service class APSendFollowServiceImpl( - @Qualifier("activitypub") private val objectMapper: ObjectMapper, private val apRequestService: APRequestService, ) : APSendFollowService { override suspend fun sendFollow(sendFollowDto: SendFollowDto) { diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APUserService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APUserService.kt index 90e39966..5909d3f5 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APUserService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APUserService.kt @@ -103,7 +103,6 @@ class APUserServiceImpl( endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox") ) to userEntity } catch (ignore: FailedToGetResourcesException) { - val person = apResourceResolveService.resolve(url, null as Long?) person to userService.createRemoteUser( diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveService.kt index 986a958e..7815f088 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveService.kt @@ -8,10 +8,8 @@ interface APResourceResolveService { suspend fun resolve(url: String, clazz: Class, singerId: Long?): T } -suspend inline fun APResourceResolveService.resolve(url: String, singer: User?): T { - return resolve(url, T::class.java, singer) -} +suspend inline fun APResourceResolveService.resolve(url: String, singer: User?): T = + resolve(url, T::class.java, singer) -suspend inline fun APResourceResolveService.resolve(url: String, singerId: Long?): T { - return resolve(url, T::class.java, singerId) -} +suspend inline fun APResourceResolveService.resolve(url: String, singerId: Long?): T = + resolve(url, T::class.java, singerId) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveServiceImpl.kt index 90d648f9..962f4563 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveServiceImpl.kt @@ -1,32 +1,26 @@ 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.hideout.entity.User import dev.usbharu.hideout.repository.UserRepository import dev.usbharu.hideout.service.ap.APRequestService -import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Service @Service class APResourceResolveServiceImpl( private val apRequestService: APRequestService, private val userRepository: UserRepository, - private val cacheManager: CacheManager, - @Qualifier("activitypub") private val objectMapper: ObjectMapper + private val cacheManager: CacheManager ) : APResourceResolveService { - override suspend fun resolve(url: String, clazz: Class, singerId: Long?): T { - return internalResolve(url, singerId, clazz) - } + override suspend fun resolve(url: String, clazz: Class, singerId: Long?): T = + internalResolve(url, singerId, clazz) - override suspend fun resolve(url: String, clazz: Class, singer: User?): T { - return internalResolve(url, singer, clazz) - } + override suspend fun resolve(url: String, clazz: Class, singer: User?): T = + internalResolve(url, singer, clazz) private suspend fun internalResolve(url: String, singerId: Long?, clazz: Class): T { - val key = genCacheKey(url, singerId) cacheManager.putCache(key) { @@ -43,9 +37,8 @@ class APResourceResolveServiceImpl( return cacheManager.getOrWait(key) as T } - private suspend fun runResolve(url: String, singer: User?, clazz: Class): Object { - return apRequestService.apGet(url, singer, clazz) - } + private suspend fun runResolve(url: String, singer: User?, clazz: Class): Object = + apRequestService.apGet(url, singer, clazz) private fun genCacheKey(url: String, singerId: Long?): String { if (singerId != null) { diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/InMemoryCacheManager.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/InMemoryCacheManager.kt index 12bdc70a..e68692bd 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/InMemoryCacheManager.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/resource/InMemoryCacheManager.kt @@ -35,12 +35,10 @@ class InMemoryCacheManager : CacheManager { if (cacheKey.containsKey(key)) { valueStore[key] = processed } - } } override suspend fun getOrWait(key: String): Object { - while (valueStore.contains(key).not()) { if (cacheKey.containsKey(key).not()) { throw IllegalStateException("Invalid cache key.") @@ -48,6 +46,5 @@ class InMemoryCacheManager : CacheManager { delay(1) } return valueStore.getValue(key) - } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSigner.kt b/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSigner.kt index 4f0eb495..f920f048 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSigner.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSigner.kt @@ -3,6 +3,7 @@ package dev.usbharu.hideout.service.signature import io.ktor.http.* interface HttpSignatureSigner { + @Suppress("LongParameterList") suspend fun sign( url: String, method: HttpMethod, diff --git a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImpl.kt index ea455200..193658ba 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImpl.kt @@ -48,7 +48,11 @@ class HttpSignatureSignerImpl : HttpSignatureSigner { val signature = Base64Util.encode(sign) return Sign( 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}" } - private fun generalHeader(fieldName: String, value: String): String { - return "$fieldName: $value" - } + private fun generalHeader(fieldName: String, value: String): String = "$fieldName: $value" } diff --git a/src/main/kotlin/dev/usbharu/hideout/util/HttpUtil.kt b/src/main/kotlin/dev/usbharu/hideout/util/HttpUtil.kt index c6c1bfe5..882a211f 100644 --- a/src/main/kotlin/dev/usbharu/hideout/util/HttpUtil.kt +++ b/src/main/kotlin/dev/usbharu/hideout/util/HttpUtil.kt @@ -17,8 +17,7 @@ object HttpUtil { fun isContentTypeOfActivityPub( contentType: String, - subType: String, - parameter: String + subType: String ): Boolean { if (contentType != "application") { return false @@ -32,8 +31,7 @@ object HttpUtil { fun isContentTypeOfActivityPub(contentType: ContentType): Boolean { return isContentTypeOfActivityPub( contentType.contentType, - contentType.contentSubtype, - contentType.parameter("profile").orEmpty() + contentType.contentSubtype ) } // fun diff --git a/src/main/kotlin/dev/usbharu/hideout/util/LruCache.kt b/src/main/kotlin/dev/usbharu/hideout/util/LruCache.kt index ed0c3661..3f65175a 100644 --- a/src/main/kotlin/dev/usbharu/hideout/util/LruCache.kt +++ b/src/main/kotlin/dev/usbharu/hideout/util/LruCache.kt @@ -10,5 +10,4 @@ class LruCache(private val maxSize: Int) : LinkedHashMap(15, 0.75f, @Serial private const val serialVersionUID: Long = -6446947260925053191L } - } diff --git a/src/main/kotlin/dev/usbharu/hideout/util/RsaUtil.kt b/src/main/kotlin/dev/usbharu/hideout/util/RsaUtil.kt index 307654f3..278019e3 100644 --- a/src/main/kotlin/dev/usbharu/hideout/util/RsaUtil.kt +++ b/src/main/kotlin/dev/usbharu/hideout/util/RsaUtil.kt @@ -7,6 +7,8 @@ import java.security.spec.PKCS8EncodedKeySpec import java.security.spec.X509EncodedKeySpec object RsaUtil { + private val replaceHeaderAndFooterRegex = Regex("-----.*?-----") + fun decodeRsaPublicKey(byteArray: ByteArray): RSAPublicKey { val x509EncodedKeySpec = X509EncodedKeySpec(byteArray) return KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec) as RSAPublicKey @@ -32,6 +34,4 @@ object RsaUtil { .replace("\n", "") return decodeRsaPrivateKey(replace) } - - private val replaceHeaderAndFooterRegex = Regex("-----.*?-----") } diff --git a/src/test/kotlin/dev/usbharu/hideout/service/ap/APReceiveFollowServiceImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/service/ap/APReceiveFollowServiceImplTest.kt index 1b6a4899..d16fcc2e 100644 --- a/src/test/kotlin/dev/usbharu/hideout/service/ap/APReceiveFollowServiceImplTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/service/ap/APReceiveFollowServiceImplTest.kt @@ -3,17 +3,17 @@ package dev.usbharu.hideout.service.ap -import com.fasterxml.jackson.module.kotlin.readValue import dev.usbharu.hideout.config.Config 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.job.ReceiveFollowJob import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.service.job.JobQueueParentService 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.job.JobProps import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -40,7 +40,6 @@ class APReceiveFollowServiceImplTest { mock(), mock(), mock(), - mock(), TestTransaction, objectMapper, mock() @@ -146,32 +145,6 @@ class APReceiveFollowServiceImplTest { mock(), apUserService, 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( - content - ) - ) - respondOk() - } - ), userQueryService, TestTransaction, objectMapper, diff --git a/src/test/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveServiceImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveServiceImplTest.kt index ac485f08..fa244184 100644 --- a/src/test/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveServiceImplTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/service/ap/resource/APResourceResolveServiceImplTest.kt @@ -16,7 +16,6 @@ import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.whenever -import utils.JsonObjectMapper.objectMapper import java.time.Instant import kotlin.test.assertEquals @@ -53,7 +52,7 @@ class APResourceResolveServiceImplTest { ) val apResourceResolveService = - APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager(), objectMapper) + APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager()) apResourceResolveService.resolve("https", 0) @@ -88,7 +87,7 @@ class APResourceResolveServiceImplTest { ) val apResourceResolveService = - APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager(), objectMapper) + APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager()) apResourceResolveService.resolve("https", 0) apResourceResolveService.resolve("https", 0) @@ -126,7 +125,7 @@ class APResourceResolveServiceImplTest { ) val apResourceResolveService = - APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager(), objectMapper) + APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager()) repeat(10) { awaitAll( @@ -175,7 +174,7 @@ class APResourceResolveServiceImplTest { ) val apResourceResolveService = - APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager(), objectMapper) + APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager()) apResourceResolveService.resolve("abcd", 0) apResourceResolveService.resolve("1234", 0)