diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/User.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/User.kt index ee46667a..3f54f7bb 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/User.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/User.kt @@ -1,18 +1,18 @@ package dev.usbharu.hideout.domain.model -import java.time.LocalDateTime +import java.time.Instant data class User( - val id:Long, + val id: Long, val name: String, val domain: String, val screenName: String, val description: String, - val password:String? = null, + val password: String? = null, val inbox: String, val outbox: String, val url: String, - val publicKey:String, - val privateKey:String? = null, - val createdAt:LocalDateTime + val publicKey: String, + val privateKey: String? = null, + val createdAt: Instant ) diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/UserRepository.kt b/src/main/kotlin/dev/usbharu/hideout/repository/UserRepository.kt index dd224212..7e0487b1 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/UserRepository.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/UserRepository.kt @@ -9,6 +9,7 @@ import org.jetbrains.exposed.sql.transactions.transaction import java.time.Instant import java.time.LocalDateTime import java.time.ZoneId +import java.time.ZoneOffset class UserRepository(private val database: Database) : IUserRepository { init { @@ -28,13 +29,18 @@ class UserRepository(private val database: Database) : IUserRepository { override suspend fun create(user: User): User { return query { Users.insert { + it[id] = user.id it[name] = user.name it[domain] = user.domain it[screenName] = user.screenName it[description] = user.description + it[password] = user.password it[inbox] = user.inbox it[outbox] = user.outbox it[url] = user.url + it[createdAt] = user.createdAt.toEpochMilli() + it[publicKey] = user.publicKey + it[privateKey] = user.privateKey } return@query user } @@ -101,7 +107,7 @@ class UserRepository(private val database: Database) : IUserRepository { Users.innerJoin( otherTable = UsersFollowers, onColumn = { Users.id }, - otherColumn = { UsersFollowers.userId }) + otherColumn = { userId }) .innerJoin( otherTable = followers, @@ -114,9 +120,13 @@ class UserRepository(private val database: Database) : IUserRepository { followers.get(Users.domain), followers.get(Users.screenName), followers.get(Users.description), + followers.get(Users.password), followers.get(Users.inbox), followers.get(Users.outbox), - followers.get(Users.url) + followers.get(Users.url), + followers.get(Users.publicKey), + followers.get(Users.privateKey), + followers.get(Users.createdAt) ) .select { Users.id eq id } .map { @@ -132,7 +142,7 @@ class UserRepository(private val database: Database) : IUserRepository { url = it[followers[Users.url]], publicKey = it[followers[Users.publicKey]], privateKey = it[followers[Users.privateKey]], - createdAt = LocalDateTime.ofInstant(Instant.ofEpochMilli(it[followers[Users.createdAt]]), ZoneId.systemDefault()) + createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]]) ) } } @@ -189,7 +199,7 @@ object Users : Table("users") { val outbox = varchar("outbox", length = 255).uniqueIndex() val url = varchar("url", length = 255).uniqueIndex() val publicKey = varchar("public_key", length = 10000) - val privateKey = varchar("private_key", length = 10000) + val privateKey = varchar("private_key", length = 10000).nullable() val createdAt = long("created_at") override val primaryKey: PrimaryKey = PrimaryKey(id) @@ -211,6 +221,6 @@ fun ResultRow.toUser(): User { this[Users.url], this[Users.publicKey], this[Users.privateKey], - LocalDateTime.ofInstant(Instant.ofEpochMilli((this[Users.createdAt])), ZoneId.systemDefault()) + Instant.ofEpochMilli((this[Users.createdAt])) ) } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubUserServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubUserServiceImpl.kt index 14d4cd11..11e855c0 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubUserServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubUserServiceImpl.kt @@ -16,6 +16,7 @@ import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import org.slf4j.LoggerFactory +import java.time.Instant import java.time.LocalDateTime class ActivityPubUserServiceImpl( @@ -99,7 +100,7 @@ class ActivityPubUserServiceImpl( outbox = person.outbox ?: throw IllegalActivityPubObjectException("outbox is null"), url = url, publicKey = person.publicKey?.publicKeyPem ?: throw IllegalActivityPubObjectException("publicKey is null"), - createdAt = LocalDateTime.now() + createdAt = Instant.now() ) ) person diff --git a/src/main/kotlin/dev/usbharu/hideout/service/impl/UserAuthService.kt b/src/main/kotlin/dev/usbharu/hideout/service/impl/UserAuthService.kt index db6dccf7..08235238 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/impl/UserAuthService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/impl/UserAuthService.kt @@ -9,6 +9,7 @@ import io.ktor.util.* import java.security.* import java.security.interfaces.RSAPrivateKey import java.security.interfaces.RSAPublicKey +import java.time.Instant import java.time.LocalDateTime import java.util.* @@ -40,7 +41,7 @@ class UserAuthService( outbox = "$url/outbox", url = url, publicKey = "", - createdAt = LocalDateTime.now(), + createdAt = Instant.now(), ) val createdUser = userRepository.create(registerUser) @@ -69,13 +70,13 @@ class UserAuthService( } } -public fun PublicKey.toPem(): String { +fun PublicKey.toPem(): String { return "-----BEGIN PUBLIC KEY-----\n" + Base64.getEncoder().encodeToString(encoded).chunked(64).joinToString("\n") + "\n-----END PUBLIC KEY-----\n" } -public fun PrivateKey.toPem(): String { +fun PrivateKey.toPem(): String { return "-----BEGIN PRIVATE KEY-----" + Base64.getEncoder().encodeToString(encoded).chunked(64).joinToString("\n") + "\n-----END PRIVATE KEY-----\n" diff --git a/src/test/kotlin/dev/usbharu/hideout/plugins/ActivityPubKtTest.kt b/src/test/kotlin/dev/usbharu/hideout/plugins/ActivityPubKtTest.kt index 757c6ec7..87d91ca0 100644 --- a/src/test/kotlin/dev/usbharu/hideout/plugins/ActivityPubKtTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/plugins/ActivityPubKtTest.kt @@ -3,11 +3,14 @@ package dev.usbharu.hideout.plugins import dev.usbharu.hideout.domain.model.User import dev.usbharu.hideout.domain.model.ap.JsonLd import dev.usbharu.hideout.repository.IUserRepository +import dev.usbharu.hideout.service.impl.toPem import io.ktor.client.* import io.ktor.client.engine.mock.* import io.ktor.client.plugins.logging.* import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.Test +import java.security.KeyPairGenerator +import java.time.Instant import java.time.LocalDateTime class ActivityPubKtTest { @@ -27,7 +30,10 @@ class ActivityPubKtTest { TODO("Not yet implemented") } - override suspend fun findByName(name: String): User? { + override suspend fun findByName(name: String): User { + val keyPairGenerator = KeyPairGenerator.getInstance("RSA") + keyPairGenerator.initialize(1024) + val generateKeyPair = keyPairGenerator.generateKeyPair() return User( 1, "test", @@ -39,8 +45,8 @@ class ActivityPubKtTest { "", "", "", - null, - LocalDateTime.now() + generateKeyPair.private.toPem(), + Instant.now() ) } diff --git a/src/test/kotlin/dev/usbharu/hideout/plugins/KtorKeyMapTest.kt b/src/test/kotlin/dev/usbharu/hideout/plugins/KtorKeyMapTest.kt index 9da97821..204f6c8c 100644 --- a/src/test/kotlin/dev/usbharu/hideout/plugins/KtorKeyMapTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/plugins/KtorKeyMapTest.kt @@ -2,7 +2,10 @@ package dev.usbharu.hideout.plugins import dev.usbharu.hideout.domain.model.User import dev.usbharu.hideout.repository.IUserRepository +import dev.usbharu.hideout.service.impl.toPem import org.junit.jupiter.api.Test +import java.security.KeyPairGenerator +import java.time.Instant import java.time.LocalDateTime class KtorKeyMapTest { @@ -22,7 +25,10 @@ class KtorKeyMapTest { TODO("Not yet implemented") } - override suspend fun findByName(name: String): User? { + override suspend fun findByName(name: String): User { + val keyPairGenerator = KeyPairGenerator.getInstance("RSA") + keyPairGenerator.initialize(1024) + val generateKeyPair = keyPairGenerator.generateKeyPair() return User( 1, "test", @@ -34,7 +40,8 @@ class KtorKeyMapTest { "", "", "", - createdAt = LocalDateTime.now() + generateKeyPair.private.toPem(), + createdAt = Instant.now() ) } diff --git a/src/test/kotlin/dev/usbharu/hideout/repository/UserRepositoryTest.kt b/src/test/kotlin/dev/usbharu/hideout/repository/UserRepositoryTest.kt index 54b6dc69..12f9162e 100644 --- a/src/test/kotlin/dev/usbharu/hideout/repository/UserRepositoryTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/repository/UserRepositoryTest.kt @@ -14,6 +14,10 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertIterableEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import java.time.Clock +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId class UserRepositoryTest { @@ -43,35 +47,47 @@ class UserRepositoryTest { val userRepository = UserRepository(db) val user = userRepository.create( User( - "test", - "example.com", - "testUser", - "This user is test user.", - "https://example.com/inbox", - "https://example.com/outbox", - "https://example.com" + id = 0L, + name = "test", + domain = "example.com", + screenName = "testUser", + description = "This user is test user.", + password = "https://example.com/inbox", + inbox = "", + outbox = "https://example.com/outbox", + url = "https://example.com", + publicKey = "", + createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault())) ) ) val follower = userRepository.create( User( - "follower", - "follower.example.com", - "followerUser", - "This user is follower user.", - "https://follower.example.com/inbox", - "https://follower.example.com/outbox", - "https://follower.example.com" + id = 1L, + name = "follower", + domain = "follower.example.com", + screenName = "followerUser", + description = "This user is follower user.", + password = "", + inbox = "https://follower.example.com/inbox", + outbox = "https://follower.example.com/outbox", + url = "https://follower.example.com", + publicKey = "", + createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault())) ) ) val follower2 = userRepository.create( User( - "follower2", - "follower2.example.com", - "followerUser2", - "This user is follower user 2.", - "https://follower2.example.com/inbox", - "https://follower2.example.com/outbox", - "https://follower2.example.com" + id = 3L, + name = "follower2", + domain = "follower2.example.com", + screenName = "followerUser2", + description = "This user is follower user 2.", + password = "", + inbox = "https://follower2.example.com/inbox", + outbox = "https://follower2.example.com/outbox", + url = "https://follower2.example.com", + publicKey = "", + createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault())) ) ) userRepository.createFollower(user.id, follower.id) @@ -86,25 +102,31 @@ class UserRepositoryTest { fun `createFollower フォロワー追加`() = runTest { val userRepository = UserRepository(db) val user = userRepository.create( - User( + User(0L, "test", "example.com", "testUser", "This user is test user.", "https://example.com/inbox", + "", "https://example.com/outbox", - "https://example.com" + "https://example.com", + publicKey = "", + createdAt = Instant.now() ) ) val follower = userRepository.create( - User( + User(1L, "follower", "follower.example.com", "followerUser", "This user is follower user.", + "", "https://follower.example.com/inbox", "https://follower.example.com/outbox", - "https://follower.example.com" + "https://follower.example.com", + publicKey = "", + createdAt = Instant.now() ) ) userRepository.createFollower(user.id, follower.id) diff --git a/src/test/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubFollowServiceImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubFollowServiceImplTest.kt index 3de7494d..cb012e10 100644 --- a/src/test/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubFollowServiceImplTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubFollowServiceImplTest.kt @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test import org.mockito.ArgumentMatchers.anyString import org.mockito.kotlin.* import utils.JsonObjectMapper +import java.time.Instant import java.time.LocalDateTime class ActivityPubFollowServiceImplTest { @@ -99,7 +100,7 @@ class ActivityPubFollowServiceImplTest { outbox = "https://example.com/outbox", url = "https://example.com", publicKey = "", - createdAt = LocalDateTime.now() + createdAt = Instant.now() ), User( id = 2L, @@ -111,7 +112,7 @@ class ActivityPubFollowServiceImplTest { outbox = "https://follower.example.com/outbox", url = "https://follower.example.com", publicKey = "", - createdAt = LocalDateTime.now() + createdAt = Instant.now() ) ) onBlocking { addFollowers(any(), any()) } doReturn Unit diff --git a/src/test/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubNoteServiceImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubNoteServiceImplTest.kt index a9445572..ec1fa5ee 100644 --- a/src/test/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubNoteServiceImplTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/service/activitypub/ActivityPubNoteServiceImplTest.kt @@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test import org.mockito.Mockito.eq import org.mockito.kotlin.* import utils.JsonObjectMapper -import java.time.LocalDateTime +import java.time.Instant import kotlin.test.assertEquals class ActivityPubNoteServiceImplTest { @@ -38,7 +38,7 @@ class ActivityPubNoteServiceImplTest { "https://follower.example.com", "", publicKey = "", - createdAt = LocalDateTime.now() + createdAt = Instant.now() ), User( 3L, @@ -51,7 +51,7 @@ class ActivityPubNoteServiceImplTest { "https://follower2.example.com", "", publicKey = "", - createdAt = LocalDateTime.now() + createdAt = Instant.now() ) ) val userService = mock { @@ -66,7 +66,7 @@ class ActivityPubNoteServiceImplTest { "https:.//example.com", "", publicKey = "", - createdAt = LocalDateTime.now() + createdAt = Instant.now() ) onBlocking { findFollowersById(eq(1L)) } doReturn followers }