diff --git a/build.gradle.kts b/build.gradle.kts index d347a77a..b7cca720 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + val ktor_version: String by project val kotlin_version: String by project val logback_version: String by project @@ -31,6 +33,14 @@ tasks.withType>().con compilerOptions.apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8) } +tasks.withType { + manifest { + attributes( + "Implementation-Version" to project.version.toString() + ) + } +} + repositories { mavenCentral() } diff --git a/src/main/kotlin/dev/usbharu/hideout/Application.kt b/src/main/kotlin/dev/usbharu/hideout/Application.kt index 9fb82629..4d3180a9 100644 --- a/src/main/kotlin/dev/usbharu/hideout/Application.kt +++ b/src/main/kotlin/dev/usbharu/hideout/Application.kt @@ -8,15 +8,9 @@ import dev.usbharu.hideout.config.ConfigData import dev.usbharu.hideout.domain.model.job.DeliverPostJob import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob import dev.usbharu.hideout.plugins.* -import dev.usbharu.hideout.repository.IPostRepository -import dev.usbharu.hideout.repository.IUserRepository -import dev.usbharu.hideout.repository.PostRepositoryImpl -import dev.usbharu.hideout.repository.UserRepository +import dev.usbharu.hideout.repository.* import dev.usbharu.hideout.routing.register -import dev.usbharu.hideout.service.IPostService -import dev.usbharu.hideout.service.IUserAuthService -import dev.usbharu.hideout.service.IdGenerateService -import dev.usbharu.hideout.service.TwitterSnowflakeIdGenerateService +import dev.usbharu.hideout.service.* import dev.usbharu.hideout.service.activitypub.* import dev.usbharu.hideout.service.impl.IUserService import dev.usbharu.hideout.service.impl.PostService @@ -32,6 +26,7 @@ import io.ktor.client.engine.cio.* import io.ktor.client.plugins.logging.* import io.ktor.server.application.* import kjob.core.kjob +import kotlinx.coroutines.runBlocking import org.jetbrains.exposed.sql.Database import org.koin.ktor.ext.inject @@ -89,15 +84,19 @@ fun Application.parent() { single { PostService(get(), get()) } single { PostRepositoryImpl(get(), get()) } single { TwitterSnowflakeIdGenerateService } + single{ MetaRepositoryImpl(get()) } + single { ServerInitialiseServiceImpl(get()) } } - configureKoin(module) + runBlocking { + inject().value.init() + } configureHTTP() configureStaticRouting() configureMonitoring() configureSerialization() register(inject().value) - configureSecurity(inject().value) + configureSecurity(inject().value,inject().value) configureRouting( inject().value, inject().value, diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Meta.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Meta.kt new file mode 100644 index 00000000..f1fa6d5f --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Meta.kt @@ -0,0 +1,3 @@ +package dev.usbharu.hideout.domain.model.hideout.entity + +data class Meta(val version:String,val jwt:Jwt) diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/IMetaRepository.kt b/src/main/kotlin/dev/usbharu/hideout/repository/IMetaRepository.kt new file mode 100644 index 00000000..b3ed940f --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/repository/IMetaRepository.kt @@ -0,0 +1,10 @@ +package dev.usbharu.hideout.repository + +import dev.usbharu.hideout.domain.model.hideout.entity.Meta + +interface IMetaRepository { + + suspend fun save(meta: Meta) + + suspend fun get():Meta? +} diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/MetaRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/MetaRepositoryImpl.kt new file mode 100644 index 00000000..5a537ae7 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/repository/MetaRepositoryImpl.kt @@ -0,0 +1,62 @@ +package dev.usbharu.hideout.repository + +import dev.usbharu.hideout.domain.model.hideout.entity.Jwt +import kotlinx.coroutines.Dispatchers +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.sql.transactions.transaction +import java.util.* + +class MetaRepositoryImpl(private val database: Database) : IMetaRepository { + + init { + transaction(database) { + SchemaUtils.create(Meta) + SchemaUtils.createMissingTablesAndColumns(Meta) + } + } + + suspend fun query(block: suspend () -> T): T = + newSuspendedTransaction(Dispatchers.IO) { block() } + + override suspend fun save(meta: dev.usbharu.hideout.domain.model.hideout.entity.Meta) { + return query { + if (Meta.select { Meta.id eq 1 }.empty()) { + Meta.insert { + it[id] = 1 + it[this.version] = meta.version + it[kid] = UUID.randomUUID().toString() + it[this.jwtPrivateKey] = meta.jwt.privateKey + it[this.jwtPublicKey] = meta.jwt.publicKey + } + }else { + Meta.update({ Meta.id eq 1 }) { + it[this.version] = meta.version + it[kid] = UUID.randomUUID().toString() + it[this.jwtPrivateKey] = meta.jwt.privateKey + it[this.jwtPublicKey] = meta.jwt.publicKey + } + } + } + } + + override suspend fun get(): dev.usbharu.hideout.domain.model.hideout.entity.Meta? { + return query { + Meta.select { Meta.id eq 1 }.singleOrNull()?.let { + dev.usbharu.hideout.domain.model.hideout.entity.Meta( + it[Meta.version], + Jwt(UUID.fromString(it[Meta.kid]), it[Meta.jwtPrivateKey], it[Meta.jwtPublicKey]) + ) + } + } + } +} + +object Meta : Table("meta_info") { + val id = long("id") + val version = varchar("version", 1000) + val kid = varchar("kid", 1000) + val jwtPrivateKey = varchar("jwt_private_key", 100000) + val jwtPublicKey = varchar("jwt_public_key", 100000) + override val primaryKey: PrimaryKey = PrimaryKey(id) +} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/IServerInitialiseService.kt b/src/main/kotlin/dev/usbharu/hideout/service/IServerInitialiseService.kt new file mode 100644 index 00000000..49a613fd --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/service/IServerInitialiseService.kt @@ -0,0 +1,5 @@ +package dev.usbharu.hideout.service + +interface IServerInitialiseService { + suspend fun init() +} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ServerInitialiseServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/ServerInitialiseServiceImpl.kt new file mode 100644 index 00000000..39ea048e --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/service/ServerInitialiseServiceImpl.kt @@ -0,0 +1,56 @@ +package dev.usbharu.hideout.service + +import dev.usbharu.hideout.domain.model.hideout.entity.Jwt +import dev.usbharu.hideout.domain.model.hideout.entity.Meta +import dev.usbharu.hideout.repository.IMetaRepository +import dev.usbharu.hideout.util.ServerUtil +import org.slf4j.LoggerFactory +import java.security.KeyPairGenerator +import java.util.* + +class ServerInitialiseServiceImpl(private val metaRepository: IMetaRepository) : IServerInitialiseService { + + val logger = LoggerFactory.getLogger(ServerInitialiseServiceImpl::class.java) + + override suspend fun init() { + + val savedMeta = metaRepository.get() + val implementationVersion = ServerUtil.getImplementationVersion() + if (wasInitialised(savedMeta).not()) { + logger.info("Start Initialise") + initialise(implementationVersion) + logger.info("Finish Initialise") + return + } + + if (isVersionChanged(savedMeta!!)) { + logger.info("Version changed!! (${savedMeta.version} -> $implementationVersion)") + updateVersion(savedMeta, implementationVersion) + } + + } + + private fun wasInitialised(meta: Meta?): Boolean { + logger.debug("Initialise checking...") + return meta != null + } + + private fun isVersionChanged(meta: Meta): Boolean = meta.version != ServerUtil.getImplementationVersion() + + private suspend fun initialise(implementationVersion: String) { + val keyPairGenerator = KeyPairGenerator.getInstance("RSA") + keyPairGenerator.initialize(2048) + val generateKeyPair = keyPairGenerator.generateKeyPair() + val jwt = Jwt( + UUID.randomUUID(), + Base64.getEncoder().encodeToString(generateKeyPair.public.encoded), + Base64.getEncoder().encodeToString(generateKeyPair.private.encoded) + ) + val meta = Meta(implementationVersion, jwt) + metaRepository.save(meta) + } + + private suspend fun updateVersion(meta: Meta, version: String) { + metaRepository.save(meta.copy(version = version)) + } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/util/ServerUtil.kt b/src/main/kotlin/dev/usbharu/hideout/util/ServerUtil.kt new file mode 100644 index 00000000..438f7e33 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/util/ServerUtil.kt @@ -0,0 +1,5 @@ +package dev.usbharu.hideout.util + +object ServerUtil { + fun getImplementationVersion():String = ServerUtil.javaClass.`package`.implementationVersion ?: "DEVELOPMENT-VERSION" +}