Merge pull request #37 from usbharu/feature/spring-boot

Feature/spring boot
This commit is contained in:
usbharu 2023-09-19 16:50:28 +09:00 committed by GitHub
commit edd2465ad7
102 changed files with 1224 additions and 20 deletions

View File

@ -21,10 +21,10 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up JDK 11 - name: Set up JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v3
with: with:
java-version: '11' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- name: Build with Gradle - name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1

View File

@ -21,10 +21,10 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up JDK 11 - name: Set up JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v3
with: with:
java-version: '11' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- name: Build with Gradle - name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1

View File

@ -1,4 +1,6 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.openapitools.generator.gradle.plugin.tasks.GenerateTask
val ktor_version: String by project val ktor_version: String by project
val kotlin_version: String by project val kotlin_version: String by project
@ -11,15 +13,22 @@ plugins {
kotlin("jvm") version "1.8.21" kotlin("jvm") version "1.8.21"
id("io.ktor.plugin") version "2.3.0" id("io.ktor.plugin") version "2.3.0"
id("org.graalvm.buildtools.native") version "0.9.21" id("org.graalvm.buildtools.native") version "0.9.21"
id("io.gitlab.arturbosch.detekt") version "1.22.0" id("io.gitlab.arturbosch.detekt") version "1.23.1"
id("com.google.devtools.ksp") version "1.8.21-1.0.11" id("com.google.devtools.ksp") version "1.8.21-1.0.11"
id("org.springframework.boot") version "3.1.2"
kotlin("plugin.spring") version "1.8.21"
id("org.openapi.generator") version "6.6.0"
// id("org.jetbrains.kotlin.plugin.serialization") version "1.8.10" // id("org.jetbrains.kotlin.plugin.serialization") version "1.8.10"
} }
apply {
plugin("io.spring.dependency-management")
}
group = "dev.usbharu" group = "dev.usbharu"
version = "0.0.1" version = "0.0.1"
application { application {
mainClass.set("io.ktor.server.cio.EngineMain") mainClass.set("dev.usbharu.hideout.SpringApplicationKt")
val isDevelopment: Boolean = project.ext.has("development") val isDevelopment: Boolean = project.ext.has("development")
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
@ -34,6 +43,14 @@ tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>>().con
compilerOptions.apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8) compilerOptions.apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8)
} }
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs += "-Xjsr305=strict"
}
dependsOn("openApiGenerateServer")
mustRunAfter("openApiGenerateServer")
}
tasks.withType<ShadowJar> { tasks.withType<ShadowJar> {
manifest { manifest {
attributes( attributes(
@ -46,6 +63,35 @@ tasks.clean {
delete += listOf("$rootDir/src/main/resources/static") delete += listOf("$rootDir/src/main/resources/static")
} }
tasks.create<GenerateTask>("openApiGenerateServer", GenerateTask::class) {
generatorName.set("kotlin-spring")
inputSpec.set("$rootDir/src/main/resources/openapi/api.yaml")
outputDir.set("$buildDir/generated/sources/openapi")
apiPackage.set("dev.usbharu.hideout.controller.generated")
modelPackage.set("dev.usbharu.hideout.domain.model.generated")
configOptions.put("interfaceOnly", "true")
configOptions.put("useSpringBoot3", "true")
additionalProperties.put("useTags", "true")
schemaMappings.putAll(
mapOf(
"ReactionResponse" to "dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse",
"Account" to "dev.usbharu.hideout.domain.model.hideout.dto.Account",
"JwtToken" to "dev.usbharu.hideout.domain.model.hideout.dto.JwtToken",
"PostRequest" to "dev.usbharu.hideout.domain.model.hideout.form.Post",
"PostResponse" to "dev.usbharu.hideout.domain.model.hideout.dto.PostResponse",
"Reaction" to "dev.usbharu.hideout.domain.model.hideout.form.Reaction",
"RefreshToken" to "dev.usbharu.hideout.domain.model.hideout.form.RefreshToken",
"UserLogin" to "dev.usbharu.hideout.domain.model.hideout.form.UserLogin",
"UserResponse" to "dev.usbharu.hideout.domain.model.hideout.dto.UserResponse",
"UserCreate" to "dev.usbharu.hideout.domain.model.hideout.form.UserCreate",
"Visibility" to "dev.usbharu.hideout.domain.model.hideout.entity.Visibility",
)
)
// importMappings.putAll(mapOf("ReactionResponse" to "ReactionResponse"))
// typeMappings.putAll(mapOf("ReactionResponse" to "ReactionResponse"))
}
repositories { repositories {
mavenCentral() mavenCentral()
} }
@ -53,13 +99,13 @@ repositories {
kotlin { kotlin {
target { target {
compilations.all { compilations.all {
kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString() kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString()
} }
} }
} }
sourceSets.main { sourceSets.main {
kotlin.srcDirs("$buildDir/generated/ksp/main") kotlin.srcDirs("$buildDir/generated/ksp/main", "$buildDir/generated/sources/openapi/src/main/kotlin")
} }
dependencies { dependencies {
@ -90,6 +136,23 @@ dependencies {
implementation("io.ktor:ktor-server-compression-jvm:2.3.0") implementation("io.ktor:ktor-server-compression-jvm:2.3.0")
ksp("io.insert-koin:koin-ksp-compiler:1.2.0") ksp("io.insert-koin:koin-ksp-compiler:1.2.0")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
implementation("jakarta.validation:jakarta.validation-api")
implementation("jakarta.annotation:jakarta.annotation-api:2.1.0")
compileOnly("io.swagger.core.v3:swagger-annotations:2.2.6")
implementation("io.swagger.core.v3:swagger-models:2.2.6")
implementation("org.jetbrains.exposed:exposed-java-time:$exposed_version")
implementation("org.jetbrains.exposed:spring-transaction:$exposed_version")
implementation("org.springframework.data:spring-data-commons")
implementation("org.springframework.boot:spring-boot-starter-jdbc")
implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
testImplementation("org.springframework.boot:spring-boot-test-autoconfigure")
testImplementation("org.springframework.boot:spring-boot-starter-test")
implementation("io.ktor:ktor-client-logging-jvm:$ktor_version") implementation("io.ktor:ktor-client-logging-jvm:$ktor_version")
implementation("io.ktor:ktor-server-host-common-jvm:$ktor_version") implementation("io.ktor:ktor-server-host-common-jvm:$ktor_version")
@ -97,7 +160,7 @@ dependencies {
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version") testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
testImplementation ("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4")
implementation("io.ktor:ktor-client-core:$ktor_version") implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-cio:$ktor_version") implementation("io.ktor:ktor-client-cio:$ktor_version")
@ -137,7 +200,7 @@ graalvmNative {
named("main") { named("main") {
fallback.set(false) fallback.set(false)
verbose.set(true) verbose.set(true)
agent{ agent {
enabled.set(false) enabled.set(false)
} }
@ -167,9 +230,17 @@ detekt {
} }
tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach { tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
exclude("**/org/koin/ksp/generated/**") exclude("**/org/koin/ksp/generated/**", "**/generated/**")
} }
tasks.withType<io.gitlab.arturbosch.detekt.DetektCreateBaselineTask>().configureEach { tasks.withType<io.gitlab.arturbosch.detekt.DetektCreateBaselineTask>().configureEach {
exclude("**/org/koin/ksp/generated/**") exclude("**/org/koin/ksp/generated/**", "**/generated/**")
}
configurations.matching { it.name == "detekt" }.all {
resolutionStrategy.eachDependency {
if (requested.group == "org.jetbrains.kotlin") {
useVersion("1.9.0")
}
}
} }

View File

@ -4,7 +4,7 @@ logback_version=1.4.6
kotlin.code.style=official kotlin.code.style=official
exposed_version=0.41.1 exposed_version=0.41.1
h2_version=2.1.214 h2_version=2.1.214
koin_version=3.3.1 koin_version=3.4.3
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.configureondemand=true org.gradle.configureondemand=true
org.gradle.caching=true org.gradle.caching=true

View File

@ -39,6 +39,7 @@ import org.koin.ksp.generated.module
import org.koin.ktor.ext.inject import org.koin.ktor.ext.inject
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@Deprecated("Ktor is deprecated")
fun main(args: Array<String>): Unit = io.ktor.server.cio.EngineMain.main(args) fun main(args: Array<String>): Unit = io.ktor.server.cio.EngineMain.main(args)
val Application.property: Application.(propertyName: String) -> String val Application.property: Application.(propertyName: String) -> String
@ -52,6 +53,7 @@ val Application.propertyOrNull: Application.(propertyName: String) -> String?
} }
// application.conf references the main function. This annotation prevents the IDE from marking it as unused. // application.conf references the main function. This annotation prevents the IDE from marking it as unused.
@Deprecated("Ktor is deprecated")
@Suppress("unused", "LongMethod") @Suppress("unused", "LongMethod")
fun Application.parent() { fun Application.parent() {
Config.configData = ConfigData( Config.configData = ConfigData(
@ -136,6 +138,7 @@ fun Application.parent() {
) )
} }
@Deprecated("Ktor is deprecated")
@Suppress("unused") @Suppress("unused")
fun Application.worker() { fun Application.worker() {
val kJob = kjob(ExposedKJob) { val kJob = kjob(ExposedKJob) {

View File

@ -0,0 +1,13 @@
package dev.usbharu.hideout
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.runApplication
@SpringBootApplication
@ConfigurationPropertiesScan
class SpringApplication
fun main(args: Array<String>) {
runApplication<SpringApplication>(*args)
}

View File

@ -3,10 +3,12 @@ package dev.usbharu.hideout.config
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
@Deprecated("Config is deprecated")
object Config { object Config {
var configData: ConfigData = ConfigData() var configData: ConfigData = ConfigData()
} }
@Deprecated("Config is deprecated")
data class ConfigData( data class ConfigData(
val url: String = "", val url: String = "",
val domain: String = url.substringAfter("://").substringBeforeLast(":"), val domain: String = url.substringAfter("://").substringBeforeLast(":"),
@ -14,12 +16,14 @@ data class ConfigData(
val characterLimit: CharacterLimit = CharacterLimit() val characterLimit: CharacterLimit = CharacterLimit()
) )
@Deprecated("Config is deprecated")
data class CharacterLimit( data class CharacterLimit(
val general: General = General.of(), val general: General = General.of(),
val post: Post = Post(), val post: Post = Post(),
val account: Account = Account(), val account: Account = Account(),
val instance: Instance = Instance() val instance: Instance = Instance()
) { ) {
@Deprecated("Config is deprecated")
data class General private constructor( data class General private constructor(
val url: Int, val url: Int,
val domain: Int, val domain: Int,
@ -39,17 +43,20 @@ data class CharacterLimit(
} }
} }
@Deprecated("Config is deprecated")
data class Post( data class Post(
val text: Int = 3000, val text: Int = 3000,
val overview: Int = 3000 val overview: Int = 3000
) )
@Deprecated("Config is deprecated")
data class Account( data class Account(
val id: Int = 300, val id: Int = 300,
val name: Int = 300, val name: Int = 300,
val description: Int = 10000 val description: Int = 10000
) )
@Deprecated("Config is deprecated")
data class Instance( data class Instance(
val name: Int = 600, val name: Int = 600,
val description: Int = 10000 val description: Int = 10000

View File

@ -0,0 +1,32 @@
package dev.usbharu.hideout.config
import org.jetbrains.exposed.sql.Database
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class DatabaseConfig {
@Autowired
lateinit var dbConfig: DatabaseConnectConfig
@Bean
fun database(): Database {
return Database.connect(
url = dbConfig.url,
driver = dbConfig.driver,
user = dbConfig.user,
password = dbConfig.password
)
}
}
@ConfigurationProperties("hideout.database")
data class DatabaseConnectConfig(
val url: String,
val driver: String,
val user: String,
val password: String
)

View File

@ -0,0 +1,12 @@
package dev.usbharu.hideout.config
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class HttpClientConfig {
@Bean
fun httpClient(): HttpClient = HttpClient(CIO)
}

View File

@ -0,0 +1,130 @@
package dev.usbharu.hideout.config
import com.nimbusds.jose.jwk.JWKSet
import com.nimbusds.jose.jwk.RSAKey
import com.nimbusds.jose.jwk.source.ImmutableJWKSet
import com.nimbusds.jose.jwk.source.JWKSource
import com.nimbusds.jose.proc.SecurityContext
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.annotation.Order
import org.springframework.http.MediaType
import org.springframework.security.config.Customizer
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.oauth2.jwt.JwtDecoder
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher
import java.security.KeyPairGenerator
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import java.util.*
@EnableWebSecurity
@Configuration
class SecurityConfig {
@Bean
@Order(1)
fun oauth2SecurityFilterChain(http: HttpSecurity): SecurityFilterChain {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http)
http
.exceptionHandling {
it.defaultAuthenticationEntryPointFor(
LoginUrlAuthenticationEntryPoint("/login"),
MediaTypeRequestMatcher(MediaType.TEXT_HTML)
)
}
.oauth2ResourceServer {
it.jwt(Customizer.withDefaults())
}
.csrf {
it.disable()
}
return http.build()
}
@Bean
@Order(2)
fun defaultSecurityFilterChain(http: HttpSecurity): SecurityFilterChain {
http
.authorizeHttpRequests {
it.requestMatchers(
"/inbox",
"/users/*/inbox",
"/outbox",
"/users/*/outbox"
)
.permitAll()
}
.authorizeHttpRequests {
it.anyRequest().authenticated()
}
.formLogin(Customizer.withDefaults())
.csrf {
it.disable()
}
return http.build()
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
@Bean
fun genJwkSource(): JWKSource<SecurityContext> {
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
keyPairGenerator.initialize(2048)
val generateKeyPair = keyPairGenerator.generateKeyPair()
val rsaPublicKey = generateKeyPair.public as RSAPublicKey
val rsaPrivateKey = generateKeyPair.private as RSAPrivateKey
val rsaKey = RSAKey
.Builder(rsaPublicKey)
.privateKey(rsaPrivateKey)
.keyID(UUID.randomUUID().toString())
.build()
val jwkSet = JWKSet(rsaKey)
return ImmutableJWKSet(jwkSet)
}
@Bean
@ConditionalOnProperty(name = ["hideout.security.jwt.generate"], havingValue = "")
fun loadJwkSource(jwkConfig: JwkConfig): JWKSource<SecurityContext> {
val rsaKey = RSAKey.Builder(jwkConfig.publicKey)
.privateKey(jwkConfig.privateKey)
.keyID(jwkConfig.keyId)
.build()
return ImmutableJWKSet(JWKSet(rsaKey))
}
@Bean
fun jwtDecoder(jwkSource: JWKSource<SecurityContext>): JwtDecoder {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource)
}
@Bean
fun authorizationServerSettings(): AuthorizationServerSettings {
return AuthorizationServerSettings.builder()
.authorizationEndpoint("/oauth/authorize")
.tokenEndpoint("/oauth/token")
.tokenRevocationEndpoint("/oauth/revoke")
.build()
}
}
@ConfigurationProperties("hideout.security.jwt")
@ConditionalOnProperty(name = ["hideout.security.jwt.generate"], havingValue = "")
data class JwkConfig(
val keyId: String,
val publicKey: RSAPublicKey,
val privateKey: RSAPrivateKey
)

View File

@ -0,0 +1,18 @@
package dev.usbharu.hideout.config
import org.jetbrains.exposed.spring.SpringTransactionManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.transaction.PlatformTransactionManager
import org.springframework.transaction.annotation.EnableTransactionManagement
import org.springframework.transaction.annotation.TransactionManagementConfigurer
import javax.sql.DataSource
@Configuration
@EnableTransactionManagement
class SpringTransactionConfig(val datasource: DataSource) : TransactionManagementConfigurer {
@Bean
override fun annotationDrivenTransactionManager(): PlatformTransactionManager {
return SpringTransactionManager(datasource)
}
}

View File

@ -0,0 +1,15 @@
package dev.usbharu.hideout.controller
import dev.usbharu.hideout.controller.generated.DefaultApi
import dev.usbharu.hideout.domain.model.hideout.dto.JwtToken
import dev.usbharu.hideout.service.api.UserAuthApiService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
@Controller
class DefaultApiImpl(private val userAuthApiService: UserAuthApiService) : DefaultApi {
override fun refreshTokenPost(): ResponseEntity<JwtToken> {
return ResponseEntity(HttpStatus.OK)
}
}

View File

@ -0,0 +1,21 @@
package dev.usbharu.hideout.controller
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
@RestController
interface InboxController {
@RequestMapping(
"/inbox",
"/users/{username}/inbox",
produces = ["application/activity+json", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""],
method = [RequestMethod.GET, RequestMethod.POST]
)
suspend fun inbox(@RequestBody string: String): ResponseEntity<Unit> {
return ResponseEntity(HttpStatus.ACCEPTED)
}
}

View File

@ -0,0 +1,16 @@
package dev.usbharu.hideout.controller
import dev.usbharu.hideout.service.ap.APService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
@RestController
class InboxControllerImpl(private val apService: APService) : InboxController {
override suspend fun inbox(@RequestBody string: String): ResponseEntity<Unit> {
val parseActivity = apService.parseActivity(string)
apService.processActivity(string, parseActivity)
return ResponseEntity(HttpStatus.ACCEPTED)
}
}

View File

@ -0,0 +1,16 @@
package dev.usbharu.hideout.controller
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
@RestController
interface OutboxController {
@RequestMapping("/outbox", "/users/{username}/outbox", method = [RequestMethod.POST, RequestMethod.GET])
fun outbox(@RequestBody string: String): ResponseEntity<Unit> {
return ResponseEntity(HttpStatus.ACCEPTED)
}
}

View File

@ -0,0 +1,13 @@
package dev.usbharu.hideout.controller
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
@RestController
class OutboxControllerImpl : OutboxController {
override fun outbox(@RequestBody string: String): ResponseEntity<Unit> {
return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
}
}

View File

@ -0,0 +1,13 @@
package dev.usbharu.hideout.controller
import dev.usbharu.hideout.domain.model.ap.Person
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
@RestController
interface UserAPController {
@GetMapping("/users/{username}")
suspend fun userAp(@PathVariable("username") username: String): ResponseEntity<Person>
}

View File

@ -0,0 +1,15 @@
package dev.usbharu.hideout.controller
import dev.usbharu.hideout.domain.model.ap.Person
import dev.usbharu.hideout.service.ap.APUserService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
@RestController
class UserAPControllerImpl(private val apUserService: APUserService) : UserAPController {
override suspend fun userAp(username: String): ResponseEntity<Person> {
val person = apUserService.getPersonByName(username)
return ResponseEntity(person, HttpStatus.OK)
}
}

View File

@ -4,6 +4,7 @@ import io.ktor.http.*
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.plugins.compression.* import io.ktor.server.plugins.compression.*
@Deprecated("Ktor is deprecated")
fun Application.configureCompression() { fun Application.configureCompression() {
install(Compression) { install(Compression) {
gzip { gzip {

View File

@ -4,6 +4,7 @@ import io.ktor.server.application.*
import io.ktor.server.plugins.defaultheaders.* import io.ktor.server.plugins.defaultheaders.*
import io.ktor.server.plugins.forwardedheaders.* import io.ktor.server.plugins.forwardedheaders.*
@Deprecated("Ktor is deprecated")
fun Application.configureHTTP() { fun Application.configureHTTP() {
// install(CORS) { // install(CORS) {
// allowMethod(HttpMethod.Options) // allowMethod(HttpMethod.Options)

View File

@ -5,6 +5,7 @@ import org.koin.core.module.Module
import org.koin.ktor.plugin.Koin import org.koin.ktor.plugin.Koin
import org.koin.logger.slf4jLogger import org.koin.logger.slf4jLogger
@Deprecated("Ktor is deprecated")
fun Application.configureKoin(vararg module: Module) { fun Application.configureKoin(vararg module: Module) {
install(Koin) { install(Koin) {
slf4jLogger() slf4jLogger()

View File

@ -4,6 +4,7 @@ import io.ktor.server.application.*
import io.ktor.server.plugins.callloging.* import io.ktor.server.plugins.callloging.*
import org.slf4j.event.Level import org.slf4j.event.Level
@Deprecated("Ktor is deprecated")
fun Application.configureMonitoring() { fun Application.configureMonitoring() {
install(CallLogging) { install(CallLogging) {
level = Level.INFO level = Level.INFO

View File

@ -22,6 +22,7 @@ import io.ktor.server.application.*
import io.ktor.server.plugins.autohead.* import io.ktor.server.plugins.autohead.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
@Suppress("LongParameterList") @Suppress("LongParameterList")
fun Application.configureRouting( fun Application.configureRouting(
httpSignatureVerifyService: HttpSignatureVerifyService, httpSignatureVerifyService: HttpSignatureVerifyService,

View File

@ -13,6 +13,7 @@ import io.ktor.server.routing.*
const val TOKEN_AUTH = "jwt-auth" const val TOKEN_AUTH = "jwt-auth"
@Deprecated("Ktor is deprecated")
@Suppress("MagicNumber") @Suppress("MagicNumber")
fun Application.configureSecurity( fun Application.configureSecurity(
jwkProvider: JwkProvider, jwkProvider: JwkProvider,

View File

@ -8,6 +8,7 @@ import io.ktor.serialization.jackson.*
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.plugins.contentnegotiation.*
@Deprecated("Ktor is deprecated")
fun Application.configureSerialization() { fun Application.configureSerialization() {
install(ContentNegotiation) { install(ContentNegotiation) {
jackson { jackson {

View File

@ -6,6 +6,7 @@ import io.ktor.server.http.content.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
fun Application.configureStaticRouting() { fun Application.configureStaticRouting() {
routing { routing {
get("/") { get("/") {

View File

@ -6,6 +6,7 @@ import io.ktor.server.application.*
import io.ktor.server.plugins.statuspages.* import io.ktor.server.plugins.statuspages.*
import io.ktor.server.response.* import io.ktor.server.response.*
@Deprecated("Ktor is deprecated")
fun Application.configureStatusPages() { fun Application.configureStatusPages() {
install(StatusPages) { install(StatusPages) {
exception<IllegalArgumentException> { call, cause -> exception<IllegalArgumentException> { call, cause ->

View File

@ -1,7 +1,9 @@
package dev.usbharu.hideout.query package dev.usbharu.hideout.query
import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.domain.model.hideout.entity.User
import org.springframework.stereotype.Repository
@Repository
interface FollowerQueryService { interface FollowerQueryService {
suspend fun findFollowersById(id: Long): List<User> suspend fun findFollowersById(id: Long): List<User>
suspend fun findFollowersByNameAndDomain(name: String, domain: String): List<User> suspend fun findFollowersByNameAndDomain(name: String, domain: String): List<User>

View File

@ -6,9 +6,11 @@ import dev.usbharu.hideout.repository.UsersFollowers
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
import java.time.Instant import java.time.Instant
@Single @Single
@Repository
class FollowerQueryServiceImpl : FollowerQueryService { class FollowerQueryServiceImpl : FollowerQueryService {
override suspend fun findFollowersById(id: Long): List<User> { override suspend fun findFollowersById(id: Long): List<User> {
val followers = Users.alias("FOLLOWERS") val followers = Users.alias("FOLLOWERS")

View File

@ -1,7 +1,9 @@
package dev.usbharu.hideout.query package dev.usbharu.hideout.query
import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
import org.springframework.stereotype.Repository
@Repository
interface JwtRefreshTokenQueryService { interface JwtRefreshTokenQueryService {
suspend fun findById(id: Long): JwtRefreshToken suspend fun findById(id: Long): JwtRefreshToken
suspend fun findByToken(token: String): JwtRefreshToken suspend fun findByToken(token: String): JwtRefreshToken

View File

@ -10,8 +10,10 @@ import org.jetbrains.exposed.sql.deleteAll
import org.jetbrains.exposed.sql.deleteWhere import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
@Single @Single
@Repository
class JwtRefreshTokenQueryServiceImpl : JwtRefreshTokenQueryService { class JwtRefreshTokenQueryServiceImpl : JwtRefreshTokenQueryService {
override suspend fun findById(id: Long): JwtRefreshToken = override suspend fun findById(id: Long): JwtRefreshToken =
JwtRefreshTokens.select { JwtRefreshTokens.id.eq(id) } JwtRefreshTokens.select { JwtRefreshTokens.id.eq(id) }

View File

@ -1,7 +1,9 @@
package dev.usbharu.hideout.query package dev.usbharu.hideout.query
import dev.usbharu.hideout.domain.model.hideout.entity.Post import dev.usbharu.hideout.domain.model.hideout.entity.Post
import org.springframework.stereotype.Repository
@Repository
interface PostQueryService { interface PostQueryService {
suspend fun findById(id: Long): Post suspend fun findById(id: Long): Post
suspend fun findByUrl(url: String): Post suspend fun findByUrl(url: String): Post

View File

@ -7,8 +7,10 @@ import dev.usbharu.hideout.repository.toPost
import dev.usbharu.hideout.util.singleOr import dev.usbharu.hideout.util.singleOr
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
@Single @Single
@Repository
class PostQueryServiceImpl : PostQueryService { class PostQueryServiceImpl : PostQueryService {
override suspend fun findById(id: Long): Post = override suspend fun findById(id: Long): Post =
Posts.select { Posts.id eq id } Posts.select { Posts.id eq id }

View File

@ -1,8 +1,10 @@
package dev.usbharu.hideout.query package dev.usbharu.hideout.query
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
import org.springframework.stereotype.Repository
@Suppress("LongParameterList") @Suppress("LongParameterList")
@Repository
interface PostResponseQueryService { interface PostResponseQueryService {
suspend fun findById(id: Long, userId: Long?): PostResponse suspend fun findById(id: Long, userId: Long?): PostResponse
suspend fun findAll( suspend fun findAll(

View File

@ -12,8 +12,10 @@ import org.jetbrains.exposed.sql.innerJoin
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.selectAll
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
@Single @Single
@Repository
class PostResponseQueryServiceImpl : PostResponseQueryService { class PostResponseQueryServiceImpl : PostResponseQueryService {
override suspend fun findById(id: Long, userId: Long?): PostResponse { override suspend fun findById(id: Long, userId: Long?): PostResponse {
return Posts return Posts

View File

@ -2,7 +2,9 @@ package dev.usbharu.hideout.query
import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
import org.springframework.stereotype.Repository
@Repository
interface ReactionQueryService { interface ReactionQueryService {
suspend fun findByPostId(postId: Long, userId: Long? = null): List<Reaction> suspend fun findByPostId(postId: Long, userId: Long? = null): List<Reaction>

View File

@ -11,8 +11,10 @@ import dev.usbharu.hideout.util.singleOr
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
@Single @Single
@Repository
class ReactionQueryServiceImpl : ReactionQueryService { class ReactionQueryServiceImpl : ReactionQueryService {
override suspend fun findByPostId(postId: Long, userId: Long?): List<Reaction> { override suspend fun findByPostId(postId: Long, userId: Long?): List<Reaction> {
return Reactions.select { return Reactions.select {

View File

@ -1,7 +1,9 @@
package dev.usbharu.hideout.query package dev.usbharu.hideout.query
import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.domain.model.hideout.entity.User
import org.springframework.stereotype.Repository
@Repository
interface UserQueryService { interface UserQueryService {
suspend fun findAll(limit: Int, offset: Long): List<User> suspend fun findAll(limit: Int, offset: Long): List<User>
suspend fun findById(id: Long): User suspend fun findById(id: Long): User

View File

@ -10,8 +10,10 @@ import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.selectAll
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Repository
@Single @Single
@Repository
class UserQueryServiceImpl : UserQueryService { class UserQueryServiceImpl : UserQueryService {
private val logger = LoggerFactory.getLogger(UserQueryServiceImpl::class.java) private val logger = LoggerFactory.getLogger(UserQueryServiceImpl::class.java)

View File

@ -1,7 +1,9 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
import org.springframework.stereotype.Repository
@Repository
interface JwtRefreshTokenRepository { interface JwtRefreshTokenRepository {
suspend fun generateId(): Long suspend fun generateId(): Long

View File

@ -6,9 +6,11 @@ import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
import java.time.Instant import java.time.Instant
@Single @Single
@Repository
class JwtRefreshTokenRepositoryImpl( class JwtRefreshTokenRepositoryImpl(
private val database: Database, private val database: Database,
private val idGenerateService: IdGenerateService private val idGenerateService: IdGenerateService

View File

@ -1,7 +1,9 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.Meta import dev.usbharu.hideout.domain.model.hideout.entity.Meta
import org.springframework.stereotype.Repository
@Repository
interface MetaRepository { interface MetaRepository {
suspend fun save(meta: Meta) suspend fun save(meta: Meta)

View File

@ -4,9 +4,11 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Jwt
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
import java.util.* import java.util.*
@Single @Single
@Repository
class MetaRepositoryImpl(private val database: Database) : MetaRepository { class MetaRepositoryImpl(private val database: Database) : MetaRepository {
init { init {

View File

@ -1,8 +1,10 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.Post import dev.usbharu.hideout.domain.model.hideout.entity.Post
import org.springframework.stereotype.Repository
@Suppress("LongParameterList") @Suppress("LongParameterList")
@Repository
interface PostRepository { interface PostRepository {
suspend fun generateId(): Long suspend fun generateId(): Long
suspend fun save(post: Post): Post suspend fun save(post: Post): Post

View File

@ -8,8 +8,10 @@ import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
@Single @Single
@Repository
class PostRepositoryImpl(database: Database, private val idGenerateService: IdGenerateService) : PostRepository { class PostRepositoryImpl(database: Database, private val idGenerateService: IdGenerateService) : PostRepository {
init { init {

View File

@ -1,7 +1,9 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
import org.springframework.stereotype.Repository
@Repository
interface ReactionRepository { interface ReactionRepository {
suspend fun generateId(): Long suspend fun generateId(): Long
suspend fun save(reaction: Reaction): Reaction suspend fun save(reaction: Reaction): Reaction

View File

@ -7,8 +7,10 @@ import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
@Single @Single
@Repository
class ReactionRepositoryImpl( class ReactionRepositoryImpl(
private val database: Database, private val database: Database,
private val idGenerateService: IdGenerateService private val idGenerateService: IdGenerateService

View File

@ -0,0 +1,169 @@
package dev.usbharu.hideout.repository
import dev.usbharu.hideout.repository.RegisteredClient.clientId
import dev.usbharu.hideout.repository.RegisteredClient.clientSettings
import dev.usbharu.hideout.repository.RegisteredClient.tokenSettings
import dev.usbharu.hideout.util.JsonUtil
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.javatime.CurrentTimestamp
import org.jetbrains.exposed.sql.javatime.timestamp
import org.jetbrains.exposed.sql.transactions.transaction
import org.springframework.security.oauth2.core.AuthorizationGrantType
import org.springframework.security.oauth2.core.ClientAuthenticationMethod
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings
import org.springframework.security.oauth2.server.authorization.settings.ConfigurationSettingNames
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings
import org.springframework.stereotype.Repository
import org.springframework.transaction.annotation.Transactional
import java.time.Instant
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient as SpringRegisteredClient
@Repository
class RegisteredClientRepositoryImpl(private val database: Database) : RegisteredClientRepository {
init {
transaction(database) {
SchemaUtils.create(RegisteredClient)
SchemaUtils.createMissingTablesAndColumns(RegisteredClient)
}
}
override fun save(registeredClient: SpringRegisteredClient?) {
requireNotNull(registeredClient)
val singleOrNull = RegisteredClient.select { RegisteredClient.id eq registeredClient.id }.singleOrNull()
if (singleOrNull == null) {
RegisteredClient.insert {
it[id] = registeredClient.id
it[clientId] = registeredClient.clientId
it[clientIdIssuedAt] = registeredClient.clientIdIssuedAt ?: Instant.now()
it[clientSecret] = registeredClient.clientSecret
it[clientSecretExpiresAt] = registeredClient.clientSecretExpiresAt
it[clientName] = registeredClient.clientName
it[clientAuthenticationMethods] = registeredClient.clientAuthenticationMethods.joinToString(",")
it[authorizationGrantTypes] = registeredClient.authorizationGrantTypes.joinToString(",")
it[redirectUris] = registeredClient.redirectUris.joinToString(",")
it[postLogoutRedirectUris] = registeredClient.postLogoutRedirectUris.joinToString(",")
it[scopes] = registeredClient.scopes.joinToString(",")
it[clientSettings] = JsonUtil.mapToJson(registeredClient.clientSettings.settings)
it[tokenSettings] = JsonUtil.mapToJson(registeredClient.tokenSettings.settings)
}
} else {
RegisteredClient.update({ RegisteredClient.id eq registeredClient.id }) {
it[clientId] = registeredClient.clientId
it[clientIdIssuedAt] = registeredClient.clientIdIssuedAt ?: Instant.now()
it[clientSecret] = registeredClient.clientSecret
it[clientSecretExpiresAt] = registeredClient.clientSecretExpiresAt
it[clientName] = registeredClient.clientName
it[clientAuthenticationMethods] = registeredClient.clientAuthenticationMethods.joinToString(",")
it[authorizationGrantTypes] = registeredClient.authorizationGrantTypes.joinToString(",")
it[redirectUris] = registeredClient.redirectUris.joinToString(",")
it[postLogoutRedirectUris] = registeredClient.postLogoutRedirectUris.joinToString(",")
it[scopes] = registeredClient.scopes.joinToString(",")
it[clientSettings] = JsonUtil.mapToJson(registeredClient.clientSettings.settings)
it[tokenSettings] = JsonUtil.mapToJson(registeredClient.tokenSettings.settings)
}
}
}
override fun findById(id: String?): SpringRegisteredClient? {
if (id == null) {
return null
}
return RegisteredClient.select {
RegisteredClient.id eq id
}.singleOrNull()?.toRegisteredClient()
}
@Transactional
override fun findByClientId(clientId: String?): SpringRegisteredClient? {
if (clientId == null) {
return null
}
return RegisteredClient.select {
RegisteredClient.clientId eq clientId
}.singleOrNull()?.toRegisteredClient()
}
}
// org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql
object RegisteredClient : Table("registered_client") {
val id = varchar("id", 100)
val clientId = varchar("client_id", 100)
val clientIdIssuedAt = timestamp("client_id_issued_at").defaultExpression(CurrentTimestamp())
val clientSecret = varchar("client_secret", 200).nullable().default(null)
val clientSecretExpiresAt = timestamp("client_secret_expires_at").nullable().default(null)
val clientName = varchar("client_name", 200)
val clientAuthenticationMethods = varchar("client_authentication_methods", 1000)
val authorizationGrantTypes = varchar("authorization_grant_types", 1000)
val redirectUris = varchar("redirect_uris", 1000).nullable().default(null)
val postLogoutRedirectUris = varchar("post_logout_redirect_uris", 1000).nullable().default(null)
val scopes = varchar("scopes", 1000)
val clientSettings = varchar("client_settings", 2000)
val tokenSettings = varchar("token_settings", 2000)
override val primaryKey = PrimaryKey(id)
}
fun ResultRow.toRegisteredClient(): SpringRegisteredClient {
fun resolveClientAuthenticationMethods(string: String): ClientAuthenticationMethod {
return when (string) {
ClientAuthenticationMethod.CLIENT_SECRET_BASIC.value -> ClientAuthenticationMethod.CLIENT_SECRET_BASIC
ClientAuthenticationMethod.CLIENT_SECRET_JWT.value -> ClientAuthenticationMethod.CLIENT_SECRET_JWT
ClientAuthenticationMethod.CLIENT_SECRET_POST.value -> ClientAuthenticationMethod.CLIENT_SECRET_POST
ClientAuthenticationMethod.NONE.value -> ClientAuthenticationMethod.NONE
else -> {
ClientAuthenticationMethod(string)
}
}
}
fun resolveAuthorizationGrantType(string: String): AuthorizationGrantType {
return when (string) {
AuthorizationGrantType.AUTHORIZATION_CODE.value -> AuthorizationGrantType.AUTHORIZATION_CODE
AuthorizationGrantType.CLIENT_CREDENTIALS.value -> AuthorizationGrantType.CLIENT_CREDENTIALS
AuthorizationGrantType.REFRESH_TOKEN.value -> AuthorizationGrantType.REFRESH_TOKEN
else -> {
AuthorizationGrantType(string)
}
}
}
val clientAuthenticationMethods = this[RegisteredClient.clientAuthenticationMethods].split(",").toSet()
val authorizationGrantTypes = this[RegisteredClient.authorizationGrantTypes].split(",").toSet()
val redirectUris = this[RegisteredClient.redirectUris]?.split(",").orEmpty().toSet()
val postLogoutRedirectUris = this[RegisteredClient.postLogoutRedirectUris]?.split(",").orEmpty().toSet()
val clientScopes = this[RegisteredClient.scopes].split(",").toSet()
val builder = SpringRegisteredClient
.withId(this[RegisteredClient.id])
.clientId(this[clientId])
.clientIdIssuedAt(this[RegisteredClient.clientIdIssuedAt])
.clientSecret(this[RegisteredClient.clientSecret])
.clientSecretExpiresAt(this[RegisteredClient.clientSecretExpiresAt])
.clientName(this[RegisteredClient.clientName])
.clientAuthenticationMethods {
clientAuthenticationMethods.forEach { s ->
it.add(resolveClientAuthenticationMethods(s))
}
}
.authorizationGrantTypes {
authorizationGrantTypes.forEach { s ->
it.add(resolveAuthorizationGrantType(s))
}
}
.redirectUris { it.addAll(redirectUris) }
.postLogoutRedirectUris { it.addAll(postLogoutRedirectUris) }
.scopes { it.addAll(clientScopes) }
.clientSettings(ClientSettings.withSettings(JsonUtil.jsonToMap(this[clientSettings])).build())
val tokenSettingsMap = JsonUtil.jsonToMap<String, Any>(this[tokenSettings])
val withSettings = TokenSettings.withSettings(tokenSettingsMap)
if (tokenSettingsMap.containsKey(ConfigurationSettingNames.Token.ACCESS_TOKEN_FORMAT)) {
withSettings.accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
}
builder.tokenSettings(withSettings.build())
return builder.build()
}

View File

@ -1,8 +1,10 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.domain.model.hideout.entity.User
import org.springframework.stereotype.Repository
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
@Repository
interface UserRepository { interface UserRepository {
suspend fun save(user: User): User suspend fun save(user: User): User

View File

@ -8,9 +8,11 @@ import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Repository
import java.time.Instant import java.time.Instant
@Single @Single
@Repository
class UserRepositoryImpl(private val database: Database, private val idGenerateService: IdGenerateService) : class UserRepositoryImpl(private val database: Database, private val idGenerateService: IdGenerateService) :
UserRepository { UserRepository {
init { init {

View File

@ -8,6 +8,7 @@ import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
fun Application.register(userApiService: UserApiService) { fun Application.register(userApiService: UserApiService) {
routing { routing {
get("/register") { get("/register") {

View File

@ -11,6 +11,7 @@ import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
fun Routing.inbox( fun Routing.inbox(
httpSignatureVerifyService: HttpSignatureVerifyService, httpSignatureVerifyService: HttpSignatureVerifyService,
apService: dev.usbharu.hideout.service.ap.APService apService: dev.usbharu.hideout.service.ap.APService

View File

@ -5,6 +5,7 @@ import io.ktor.server.application.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
fun Routing.outbox() { fun Routing.outbox() {
route("/outbox") { route("/outbox") {
get { get {

View File

@ -15,6 +15,7 @@ import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
fun Routing.usersAP( fun Routing.usersAP(
apUserService: APUserService, apUserService: APUserService,
userQueryService: UserQueryService, userQueryService: UserQueryService,
@ -50,6 +51,7 @@ fun Routing.usersAP(
} }
} }
@Deprecated("Ktor is deprecated")
class ContentTypeRouteSelector(private vararg val contentType: ContentType) : RouteSelector() { class ContentTypeRouteSelector(private vararg val contentType: ContentType) : RouteSelector() {
override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation { override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation {
context.call.application.log.debug("Accept: ${context.call.request.accept()}") context.call.application.log.debug("Accept: ${context.call.request.accept()}")

View File

@ -11,6 +11,7 @@ import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
fun Route.auth(userAuthApiService: UserAuthApiService) { fun Route.auth(userAuthApiService: UserAuthApiService) {
post("/login") { post("/login") {
val loginUser = call.receive<UserLogin>() val loginUser = call.receive<UserLogin>()

View File

@ -14,6 +14,7 @@ import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
@Suppress("LongMethod") @Suppress("LongMethod")
fun Route.posts(postApiService: PostApiService) { fun Route.posts(postApiService: PostApiService) {
route("/posts") { route("/posts") {

View File

@ -16,6 +16,7 @@ import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
@Suppress("LongMethod", "CognitiveComplexMethod") @Suppress("LongMethod", "CognitiveComplexMethod")
fun Route.users(userService: UserService, userApiService: UserApiService) { fun Route.users(userService: UserService, userApiService: UserApiService) {
route("/users") { route("/users") {

View File

@ -11,6 +11,7 @@ import io.ktor.server.application.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@Deprecated("Ktor is deprecated")
fun Routing.webfinger(webFingerApiService: WebFingerApiService) { fun Routing.webfinger(webFingerApiService: WebFingerApiService) {
route("/.well-known/webfinger") { route("/.well-known/webfinger") {
get { get {

View File

@ -11,12 +11,15 @@ import dev.usbharu.hideout.service.core.Transaction
import dev.usbharu.hideout.service.user.UserService import dev.usbharu.hideout.service.user.UserService
import io.ktor.http.* import io.ktor.http.*
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Service
interface APAcceptService { interface APAcceptService {
suspend fun receiveAccept(accept: Accept): ActivityPubResponse suspend fun receiveAccept(accept: Accept): ActivityPubResponse
} }
@Single @Single
@Service
class APAcceptServiceImpl( class APAcceptServiceImpl(
private val userService: UserService, private val userService: UserService,
private val userQueryService: UserQueryService, private val userQueryService: UserQueryService,

View File

@ -8,12 +8,15 @@ import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
import dev.usbharu.hideout.service.core.Transaction import dev.usbharu.hideout.service.core.Transaction
import io.ktor.http.* import io.ktor.http.*
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Service
interface APCreateService { interface APCreateService {
suspend fun receiveCreate(create: Create): ActivityPubResponse suspend fun receiveCreate(create: Create): ActivityPubResponse
} }
@Single @Single
@Service
class APCreateServiceImpl( class APCreateServiceImpl(
private val apNoteService: APNoteService, private val apNoteService: APNoteService,
private val transaction: Transaction private val transaction: Transaction

View File

@ -9,12 +9,15 @@ import dev.usbharu.hideout.service.core.Transaction
import dev.usbharu.hideout.service.reaction.ReactionService import dev.usbharu.hideout.service.reaction.ReactionService
import io.ktor.http.* import io.ktor.http.*
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Service
interface APLikeService { interface APLikeService {
suspend fun receiveLike(like: Like): ActivityPubResponse suspend fun receiveLike(like: Like): ActivityPubResponse
} }
@Single @Single
@Service
class APLikeServiceImpl( class APLikeServiceImpl(
private val reactionService: ReactionService, private val reactionService: ReactionService,
private val apUserService: APUserService, private val apUserService: APUserService,

View File

@ -21,8 +21,10 @@ import io.ktor.client.statement.*
import kjob.core.job.JobProps import kjob.core.job.JobProps
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.time.Instant import java.time.Instant
@Service
interface APNoteService { interface APNoteService {
suspend fun createNote(post: Post) suspend fun createNote(post: Post)
@ -33,6 +35,7 @@ interface APNoteService {
} }
@Single @Single
@Service
class APNoteServiceImpl( class APNoteServiceImpl(
private val httpClient: HttpClient, private val httpClient: HttpClient,
private val jobQueueParentService: JobQueueParentService, private val jobQueueParentService: JobQueueParentService,

View File

@ -15,8 +15,10 @@ 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.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
import java.time.Instant import java.time.Instant
@Service
interface APReactionService { interface APReactionService {
suspend fun reaction(like: Reaction) suspend fun reaction(like: Reaction)
suspend fun removeReaction(like: Reaction) suspend fun removeReaction(like: Reaction)
@ -25,6 +27,7 @@ interface APReactionService {
} }
@Single @Single
@Service
class APReactionServiceImpl( class APReactionServiceImpl(
private val jobQueueParentService: JobQueueParentService, private val jobQueueParentService: JobQueueParentService,
private val httpClient: HttpClient, private val httpClient: HttpClient,

View File

@ -16,13 +16,16 @@ import io.ktor.client.*
import io.ktor.http.* import io.ktor.http.*
import kjob.core.job.JobProps import kjob.core.job.JobProps
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
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>)
} }
@Single @Single
@Service
class APReceiveFollowServiceImpl( class APReceiveFollowServiceImpl(
private val jobQueueParentService: JobQueueParentService, private val jobQueueParentService: JobQueueParentService,
private val apUserService: APUserService, private val apUserService: APUserService,

View File

@ -5,12 +5,15 @@ 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.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Service
interface APSendFollowService { interface APSendFollowService {
suspend fun sendFollow(sendFollowDto: SendFollowDto) suspend fun sendFollow(sendFollowDto: SendFollowDto)
} }
@Single @Single
@Service
class APSendFollowServiceImpl(private val httpClient: HttpClient) : APSendFollowService { class APSendFollowServiceImpl(private val httpClient: HttpClient) : APSendFollowService {
override suspend fun sendFollow(sendFollowDto: SendFollowDto) { override suspend fun sendFollow(sendFollowDto: SendFollowDto) {
val follow = Follow( val follow = Follow(

View File

@ -12,7 +12,9 @@ import kjob.core.job.JobProps
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
interface APService { interface APService {
fun parseActivity(json: String): ActivityType fun parseActivity(json: String): ActivityType
@ -173,6 +175,7 @@ enum class ExtendedVocabulary {
} }
@Single @Single
@Service
class APServiceImpl( class APServiceImpl(
private val apReceiveFollowService: APReceiveFollowService, private val apReceiveFollowService: APReceiveFollowService,
private val apNoteService: APNoteService, private val apNoteService: APNoteService,

View File

@ -9,12 +9,15 @@ import dev.usbharu.hideout.service.core.Transaction
import dev.usbharu.hideout.service.user.UserService import dev.usbharu.hideout.service.user.UserService
import io.ktor.http.* import io.ktor.http.*
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Service
interface APUndoService { interface APUndoService {
suspend fun receiveUndo(undo: Undo): ActivityPubResponse suspend fun receiveUndo(undo: Undo): ActivityPubResponse
} }
@Single @Single
@Service
@Suppress("UnsafeCallOnNullableType") @Suppress("UnsafeCallOnNullableType")
class APUndoServiceImpl( class APUndoServiceImpl(
private val userService: UserService, private val userService: UserService,

View File

@ -19,7 +19,9 @@ 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.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Service
interface APUserService { interface APUserService {
suspend fun getPersonByName(name: String): Person suspend fun getPersonByName(name: String): Person
@ -36,6 +38,7 @@ interface APUserService {
} }
@Single @Single
@Service
class APUserServiceImpl( class APUserServiceImpl(
private val userService: UserService, private val userService: UserService,
private val httpClient: HttpClient, private val httpClient: HttpClient,

View File

@ -13,9 +13,11 @@ import dev.usbharu.hideout.service.post.PostService
import dev.usbharu.hideout.service.reaction.ReactionService import dev.usbharu.hideout.service.reaction.ReactionService
import dev.usbharu.hideout.util.AcctUtil import dev.usbharu.hideout.util.AcctUtil
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
import java.time.Instant import java.time.Instant
@Suppress("LongParameterList") @Suppress("LongParameterList")
@Service
interface PostApiService { interface PostApiService {
suspend fun createPost(postForm: dev.usbharu.hideout.domain.model.hideout.form.Post, userId: Long): PostResponse suspend fun createPost(postForm: dev.usbharu.hideout.domain.model.hideout.form.Post, userId: Long): PostResponse
suspend fun getById(id: Long, userId: Long?): PostResponse suspend fun getById(id: Long, userId: Long?): PostResponse
@ -44,6 +46,7 @@ interface PostApiService {
} }
@Single @Single
@Service
class PostApiServiceImpl( class PostApiServiceImpl(
private val postService: PostService, private val postService: PostService,
private val userRepository: UserRepository, private val userRepository: UserRepository,

View File

@ -10,9 +10,11 @@ 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.user.UserService import dev.usbharu.hideout.service.user.UserService
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
import kotlin.math.min import kotlin.math.min
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
@Service
interface UserApiService { interface UserApiService {
suspend fun findAll(limit: Int? = 100, offset: Long = 0): List<UserResponse> suspend fun findAll(limit: Int? = 100, offset: Long = 0): List<UserResponse>
@ -37,6 +39,7 @@ interface UserApiService {
} }
@Single @Single
@Service
class UserApiServiceImpl( class UserApiServiceImpl(
private val userQueryService: UserQueryService, private val userQueryService: UserQueryService,
private val followerQueryService: FollowerQueryService, private val followerQueryService: FollowerQueryService,

View File

@ -9,13 +9,16 @@ import dev.usbharu.hideout.service.auth.JwtService
import dev.usbharu.hideout.service.core.Transaction import dev.usbharu.hideout.service.core.Transaction
import dev.usbharu.hideout.service.user.UserAuthServiceImpl import dev.usbharu.hideout.service.user.UserAuthServiceImpl
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Service
interface UserAuthApiService { interface UserAuthApiService {
suspend fun login(username: String, password: String): JwtToken suspend fun login(username: String, password: String): JwtToken
suspend fun refreshToken(refreshToken: RefreshToken): JwtToken suspend fun refreshToken(refreshToken: RefreshToken): JwtToken
} }
@Single @Single
@Service
class UserAuthApiServiceImpl( class UserAuthApiServiceImpl(
private val userAuthService: UserAuthServiceImpl, private val userAuthService: UserAuthServiceImpl,
private val userQueryService: UserQueryService, private val userQueryService: UserQueryService,

View File

@ -4,12 +4,15 @@ import dev.usbharu.hideout.domain.model.hideout.entity.User
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
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Service
interface WebFingerApiService { interface WebFingerApiService {
suspend fun findByNameAndDomain(name: String, domain: String): User suspend fun findByNameAndDomain(name: String, domain: String): User
} }
@Single @Single
@Service
class WebFingerApiServiceImpl(private val transaction: Transaction, private val userQueryService: UserQueryService) : class WebFingerApiServiceImpl(private val transaction: Transaction, private val userQueryService: UserQueryService) :
WebFingerApiService { WebFingerApiService {
override suspend fun findByNameAndDomain(name: String, domain: String): User { override suspend fun findByNameAndDomain(name: String, domain: String): User {

View File

@ -0,0 +1,72 @@
package dev.usbharu.hideout.service.auth
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
import org.springframework.stereotype.Service
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent as AuthorizationConsent
@Service
class ExposedOAuth2AuthorizationConsentService(private val registeredClientRepository: RegisteredClientRepository) :
OAuth2AuthorizationConsentService {
override fun save(authorizationConsent: AuthorizationConsent?) {
requireNotNull(authorizationConsent)
val singleOrNull =
OAuth2AuthorizationConsent.select {
OAuth2AuthorizationConsent.registeredClientId
.eq(authorizationConsent.registeredClientId)
.and(OAuth2AuthorizationConsent.principalName.eq(authorizationConsent.principalName))
}
.singleOrNull()
if (singleOrNull == null) {
OAuth2AuthorizationConsent.insert {
it[registeredClientId] = authorizationConsent.registeredClientId
it[principalName] = authorizationConsent.principalName
it[authorities] = authorizationConsent.authorities.joinToString(",")
}
}
}
override fun remove(authorizationConsent: AuthorizationConsent?) {
if (authorizationConsent == null) {
return
}
OAuth2AuthorizationConsent.deleteWhere {
registeredClientId eq authorizationConsent.registeredClientId and (principalName eq principalName)
}
}
override fun findById(registeredClientId: String?, principalName: String?): AuthorizationConsent? {
requireNotNull(registeredClientId)
requireNotNull(principalName)
return OAuth2AuthorizationConsent.select {
(OAuth2AuthorizationConsent.registeredClientId eq registeredClientId)
.and(OAuth2AuthorizationConsent.principalName eq principalName)
}
.singleOrNull()?.toAuthorizationConsent()
}
fun ResultRow.toAuthorizationConsent(): AuthorizationConsent {
val registeredClientId = this[OAuth2AuthorizationConsent.registeredClientId]
registeredClientRepository.findById(registeredClientId)
val principalName = this[OAuth2AuthorizationConsent.principalName]
val builder = AuthorizationConsent.withId(registeredClientId, principalName)
this[OAuth2AuthorizationConsent.authorities].split(",").forEach {
builder.authority(SimpleGrantedAuthority(it))
}
return builder.build()
}
}
object OAuth2AuthorizationConsent : Table("oauth2_authorization_consent") {
val registeredClientId = varchar("registered_client_id", 100)
val principalName = varchar("principal_name", 200)
val authorities = varchar("authorities", 1000)
override val primaryKey = PrimaryKey(registeredClientId, principalName)
}

View File

@ -0,0 +1,331 @@
package dev.usbharu.hideout.service.auth
import dev.usbharu.hideout.util.JsonUtil
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.javatime.timestamp
import org.springframework.security.oauth2.core.*
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
import org.springframework.security.oauth2.core.oidc.OidcIdToken
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
import org.springframework.stereotype.Service
@Service
class ExposedOAuth2AuthorizationService(private val registeredClientRepository: RegisteredClientRepository) :
OAuth2AuthorizationService {
override fun save(authorization: OAuth2Authorization?) {
requireNotNull(authorization)
val singleOrNull = Authorization.select { Authorization.id eq authorization.id }.singleOrNull()
if (singleOrNull == null) {
val authorizationCodeToken = authorization.getToken(OAuth2AuthorizationCode::class.java)
val accessToken = authorization.getToken(OAuth2AccessToken::class.java)
val refreshToken = authorization.getToken(OAuth2RefreshToken::class.java)
val oidcIdToken = authorization.getToken(OidcIdToken::class.java)
val userCode = authorization.getToken(OAuth2UserCode::class.java)
val deviceCode = authorization.getToken(OAuth2DeviceCode::class.java)
Authorization.insert {
it[id] = authorization.id
it[registeredClientId] = authorization.registeredClientId
it[principalName] = authorization.principalName
it[authorizationGrantType] = authorization.authorizationGrantType.value
it[authorizedScopes] = authorization.authorizedScopes.joinToString(",").takeIf { it.isEmpty() }
it[attributes] = JsonUtil.mapToJson(authorization.attributes)
it[state] = authorization.getAttribute(OAuth2ParameterNames.STATE)
it[authorizationCodeValue] = authorizationCodeToken?.token?.tokenValue
it[authorizationCodeIssuedAt] = authorizationCodeToken?.token?.issuedAt
it[authorizationCodeExpiresAt] = authorizationCodeToken?.token?.expiresAt
it[authorizationCodeMetadata] = authorizationCodeToken?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[accessTokenValue] = accessToken?.token?.tokenValue
it[accessTokenIssuedAt] = accessToken?.token?.issuedAt
it[accessTokenExpiresAt] = accessToken?.token?.expiresAt
it[accessTokenMetadata] = accessToken?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[accessTokenType] = accessToken?.token?.tokenType?.value
it[accessTokenScopes] = accessToken?.run { token.scopes.joinToString(",").takeIf { it.isEmpty() } }
it[refreshTokenValue] = refreshToken?.token?.tokenValue
it[refreshTokenIssuedAt] = refreshToken?.token?.issuedAt
it[refreshTokenExpiresAt] = refreshToken?.token?.expiresAt
it[refreshTokenMetadata] = refreshToken?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[oidcIdTokenValue] = oidcIdToken?.token?.tokenValue
it[oidcIdTokenIssuedAt] = oidcIdToken?.token?.issuedAt
it[oidcIdTokenExpiresAt] = oidcIdToken?.token?.expiresAt
it[oidcIdTokenMetadata] = oidcIdToken?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[userCodeValue] = userCode?.token?.tokenValue
it[userCodeIssuedAt] = userCode?.token?.issuedAt
it[userCodeExpiresAt] = userCode?.token?.expiresAt
it[userCodeMetadata] = userCode?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[deviceCodeValue] = deviceCode?.token?.tokenValue
it[deviceCodeIssuedAt] = deviceCode?.token?.issuedAt
it[deviceCodeExpiresAt] = deviceCode?.token?.expiresAt
it[deviceCodeMetadata] = deviceCode?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
}
} else {
val authorizationCodeToken = authorization.getToken(OAuth2AuthorizationCode::class.java)
val accessToken = authorization.getToken(OAuth2AccessToken::class.java)
val refreshToken = authorization.getToken(OAuth2RefreshToken::class.java)
val oidcIdToken = authorization.getToken(OidcIdToken::class.java)
val userCode = authorization.getToken(OAuth2UserCode::class.java)
val deviceCode = authorization.getToken(OAuth2DeviceCode::class.java)
Authorization.update({ Authorization.id eq authorization.id }) {
it[registeredClientId] = authorization.registeredClientId
it[principalName] = authorization.principalName
it[authorizationGrantType] = authorization.authorizationGrantType.value
it[authorizedScopes] = authorization.authorizedScopes.joinToString(",").takeIf { it.isEmpty() }
it[attributes] = JsonUtil.mapToJson(authorization.attributes)
it[state] = authorization.getAttribute(OAuth2ParameterNames.STATE)
it[authorizationCodeValue] = authorizationCodeToken?.token?.tokenValue
it[authorizationCodeIssuedAt] = authorizationCodeToken?.token?.issuedAt
it[authorizationCodeExpiresAt] = authorizationCodeToken?.token?.expiresAt
it[authorizationCodeMetadata] = authorizationCodeToken?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[accessTokenValue] = accessToken?.token?.tokenValue
it[accessTokenIssuedAt] = accessToken?.token?.issuedAt
it[accessTokenExpiresAt] = accessToken?.token?.expiresAt
it[accessTokenMetadata] = accessToken?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[accessTokenType] = accessToken?.token?.tokenType?.value
it[accessTokenScopes] = accessToken?.token?.scopes?.joinToString(",")?.takeIf { it.isEmpty() }
it[refreshTokenValue] = refreshToken?.token?.tokenValue
it[refreshTokenIssuedAt] = refreshToken?.token?.issuedAt
it[refreshTokenExpiresAt] = refreshToken?.token?.expiresAt
it[refreshTokenMetadata] = refreshToken?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[oidcIdTokenValue] = oidcIdToken?.token?.tokenValue
it[oidcIdTokenIssuedAt] = oidcIdToken?.token?.issuedAt
it[oidcIdTokenExpiresAt] = oidcIdToken?.token?.expiresAt
it[oidcIdTokenMetadata] = oidcIdToken?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[userCodeValue] = userCode?.token?.tokenValue
it[userCodeIssuedAt] = userCode?.token?.issuedAt
it[userCodeExpiresAt] = userCode?.token?.expiresAt
it[userCodeMetadata] = userCode?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
it[deviceCodeValue] = deviceCode?.token?.tokenValue
it[deviceCodeIssuedAt] = deviceCode?.token?.issuedAt
it[deviceCodeExpiresAt] = deviceCode?.token?.expiresAt
it[deviceCodeMetadata] = deviceCode?.metadata?.let { it1 -> JsonUtil.mapToJson(it1) }
}
}
}
override fun remove(authorization: OAuth2Authorization?) {
if (authorization == null) {
return
}
Authorization.deleteWhere { Authorization.id eq authorization.id }
}
override fun findById(id: String?): OAuth2Authorization? {
if (id == null) {
return null
}
return Authorization.select { Authorization.id eq id }.singleOrNull()?.toAuthorization()
}
override fun findByToken(token: String?, tokenType: OAuth2TokenType?): OAuth2Authorization? {
requireNotNull(token)
return when (tokenType?.value) {
null -> {
Authorization.select {
Authorization.authorizationCodeValue eq token
}.orWhere {
Authorization.accessTokenValue eq token
}.orWhere {
Authorization.oidcIdTokenValue eq token
}.orWhere {
Authorization.refreshTokenValue eq token
}.orWhere {
Authorization.userCodeValue eq token
}.orWhere {
Authorization.deviceCodeValue eq token
}
}
OAuth2ParameterNames.STATE -> {
Authorization.select { Authorization.state eq token }
}
OAuth2ParameterNames.CODE -> {
Authorization.select { Authorization.authorizationCodeValue eq token }
}
OAuth2ParameterNames.ACCESS_TOKEN -> {
Authorization.select { Authorization.accessTokenValue eq token }
}
OidcParameterNames.ID_TOKEN -> {
Authorization.select { Authorization.oidcIdTokenValue eq token }
}
OAuth2ParameterNames.REFRESH_TOKEN -> {
Authorization.select { Authorization.refreshTokenValue eq token }
}
OAuth2ParameterNames.USER_CODE -> {
Authorization.select { Authorization.userCodeValue eq token }
}
OAuth2ParameterNames.DEVICE_CODE -> {
Authorization.select { Authorization.deviceCodeValue eq token }
}
else -> {
null
}
}?.singleOrNull()?.toAuthorization()
}
fun ResultRow.toAuthorization(): OAuth2Authorization {
val registeredClientId = this[Authorization.registeredClientId]
val registeredClient = registeredClientRepository.findById(registeredClientId)
val builder = OAuth2Authorization.withRegisteredClient(registeredClient)
val id = this[Authorization.id]
val principalName = this[Authorization.principalName]
val authorizationGrantType = this[Authorization.authorizationGrantType]
val authorizedScopes = this[Authorization.authorizedScopes]?.split(",").orEmpty().toSet()
val attributes = this[Authorization.attributes]?.let { JsonUtil.jsonToMap<String, Any>(it) }.orEmpty()
builder.id(id).principalName(principalName)
.authorizationGrantType(AuthorizationGrantType(authorizationGrantType)).authorizedScopes(authorizedScopes)
.attributes { it.putAll(attributes) }
val state = this[Authorization.state].orEmpty()
if (state.isNotBlank()) {
builder.attribute(OAuth2ParameterNames.STATE, state)
}
val authorizationCodeValue = this[Authorization.authorizationCodeValue]
if (authorizationCodeValue.isNullOrBlank()) {
val authorizationCodeIssuedAt = this[Authorization.authorizationCodeIssuedAt]
val authorizationCodeExpiresAt = this[Authorization.authorizationCodeExpiresAt]
val authorizationCodeMetadata = this[Authorization.authorizationCodeMetadata]?.let {
JsonUtil.jsonToMap<String, Any>(
it
)
}.orEmpty()
val oAuth2AuthorizationCode =
OAuth2AuthorizationCode(authorizationCodeValue, authorizationCodeIssuedAt, authorizationCodeExpiresAt)
builder.token(oAuth2AuthorizationCode) {
it.putAll(authorizationCodeMetadata)
}
}
val accessTokenValue = this[Authorization.accessTokenValue].orEmpty()
if (accessTokenValue.isNotBlank()) {
val accessTokenIssuedAt = this[Authorization.accessTokenIssuedAt]
val accessTokenExpiresAt = this[Authorization.accessTokenExpiresAt]
val accessTokenMetadata =
this[Authorization.accessTokenMetadata]?.let { JsonUtil.jsonToMap<String, Any>(it) }.orEmpty()
val accessTokenType =
if (this[Authorization.accessTokenType].equals(OAuth2AccessToken.TokenType.BEARER.value, true)) {
OAuth2AccessToken.TokenType.BEARER
} else {
null
}
val accessTokenScope = this[Authorization.accessTokenScopes]?.split(",").orEmpty().toSet()
val oAuth2AccessToken = OAuth2AccessToken(
accessTokenType,
accessTokenValue,
accessTokenIssuedAt,
accessTokenExpiresAt,
accessTokenScope
)
builder.token(oAuth2AccessToken) { it.putAll(accessTokenMetadata) }
}
val oidcIdTokenValue = this[Authorization.oidcIdTokenValue].orEmpty()
if (oidcIdTokenValue.isNotBlank()) {
val oidcTokenIssuedAt = this[Authorization.oidcIdTokenIssuedAt]
val oidcTokenExpiresAt = this[Authorization.oidcIdTokenExpiresAt]
val oidcTokenMetadata =
this[Authorization.oidcIdTokenMetadata]?.let { JsonUtil.jsonToMap<String, Any>(it) }.orEmpty()
val oidcIdToken = OidcIdToken(
oidcIdTokenValue,
oidcTokenIssuedAt,
oidcTokenExpiresAt,
oidcTokenMetadata.getValue(OAuth2Authorization.Token.CLAIMS_METADATA_NAME) as MutableMap<String, Any>?
)
builder.token(oidcIdToken) { it.putAll(oidcTokenMetadata) }
}
val refreshTokenValue = this[Authorization.refreshTokenValue].orEmpty()
if (refreshTokenValue.isNotBlank()) {
val refreshTokenIssuedAt = this[Authorization.refreshTokenIssuedAt]
val refreshTokenExpiresAt = this[Authorization.refreshTokenExpiresAt]
val refreshTokenMetadata =
this[Authorization.refreshTokenMetadata]?.let { JsonUtil.jsonToMap<String, Any>(it) }.orEmpty()
val oAuth2RefreshToken = OAuth2RefreshToken(refreshTokenValue, refreshTokenIssuedAt, refreshTokenExpiresAt)
builder.token(oAuth2RefreshToken) { it.putAll(refreshTokenMetadata) }
}
val userCodeValue = this[Authorization.userCodeValue].orEmpty()
if (userCodeValue.isNotBlank()) {
val userCodeIssuedAt = this[Authorization.userCodeIssuedAt]
val userCodeExpiresAt = this[Authorization.userCodeExpiresAt]
val userCodeMetadata =
this[Authorization.userCodeMetadata]?.let { JsonUtil.jsonToMap<String, Any>(it) }.orEmpty()
val oAuth2UserCode = OAuth2UserCode(userCodeValue, userCodeIssuedAt, userCodeExpiresAt)
builder.token(oAuth2UserCode) { it.putAll(userCodeMetadata) }
}
val deviceCodeValue = this[Authorization.deviceCodeValue].orEmpty()
if (deviceCodeValue.isNotBlank()) {
val deviceCodeIssuedAt = this[Authorization.deviceCodeIssuedAt]
val deviceCodeExpiresAt = this[Authorization.deviceCodeExpiresAt]
val deviceCodeMetadata =
this[Authorization.deviceCodeMetadata]?.let { JsonUtil.jsonToMap<String, Any>(it) }.orEmpty()
val oAuth2DeviceCode = OAuth2DeviceCode(deviceCodeValue, deviceCodeIssuedAt, deviceCodeExpiresAt)
builder.token(oAuth2DeviceCode) { it.putAll(deviceCodeMetadata) }
}
return builder.build()
}
}
object Authorization : Table("authorization") {
val id = varchar("id", 255)
val registeredClientId = varchar("registered_client_id", 255)
val principalName = varchar("principal_name", 255)
val authorizationGrantType = varchar("authorization_grant_type", 255)
val authorizedScopes = varchar("authorized_scopes", 1000).nullable().default(null)
val attributes = varchar("attributes", 4000).nullable().default(null)
val state = varchar("state", 500).nullable().default(null)
val authorizationCodeValue = varchar("authorization_code_value", 4000).nullable().default(null)
val authorizationCodeIssuedAt = timestamp("authorization_code_issued_at").nullable().default(null)
val authorizationCodeExpiresAt = timestamp("authorization_code_expires_at").nullable().default(null)
val authorizationCodeMetadata = varchar("authorization_code_metadata", 2000).nullable().default(null)
val accessTokenValue = varchar("access_token_value", 4000).nullable().default(null)
val accessTokenIssuedAt = timestamp("access_token_issued_at").nullable().default(null)
val accessTokenExpiresAt = timestamp("access_token_expires_at").nullable().default(null)
val accessTokenMetadata = varchar("access_token_metadata", 2000).nullable().default(null)
val accessTokenType = varchar("access_token_type", 255).nullable().default(null)
val accessTokenScopes = varchar("access_token_scopes", 1000).nullable().default(null)
val refreshTokenValue = varchar("refresh_token_value", 4000).nullable().default(null)
val refreshTokenIssuedAt = timestamp("refresh_token_issued_at").nullable().default(null)
val refreshTokenExpiresAt = timestamp("refresh_token_expires_at").nullable().default(null)
val refreshTokenMetadata = varchar("refresh_token_metadata", 2000).nullable().default(null)
val oidcIdTokenValue = varchar("oidc_id_token_value", 4000).nullable().default(null)
val oidcIdTokenIssuedAt = timestamp("oidc_id_token_issued_at").nullable().default(null)
val oidcIdTokenExpiresAt = timestamp("oidc_id_token_expires_at").nullable().default(null)
val oidcIdTokenMetadata = varchar("oidc_id_token_metadata", 2000).nullable().default(null)
val oidcIdTokenClaims = varchar("oidc_id_token_claims", 2000).nullable().default(null)
val userCodeValue = varchar("user_code_value", 4000).nullable().default(null)
val userCodeIssuedAt = timestamp("user_code_issued_at").nullable().default(null)
val userCodeExpiresAt = timestamp("user_code_expires_at").nullable().default(null)
val userCodeMetadata = varchar("user_code_metadata", 2000).nullable().default(null)
val deviceCodeValue = varchar("device_code_value", 4000).nullable().default(null)
val deviceCodeIssuedAt = timestamp("device_code_issued_at").nullable().default(null)
val deviceCodeExpiresAt = timestamp("device_code_expires_at").nullable().default(null)
val deviceCodeMetadata = varchar("device_code_metadata", 2000).nullable().default(null)
override val primaryKey = PrimaryKey(id)
}

View File

@ -5,13 +5,16 @@ import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.service.core.Transaction import dev.usbharu.hideout.service.core.Transaction
import io.ktor.http.* import io.ktor.http.*
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
import tech.barbero.http.message.signing.SignatureHeaderVerifier import tech.barbero.http.message.signing.SignatureHeaderVerifier
@Service
interface HttpSignatureVerifyService { interface HttpSignatureVerifyService {
fun verify(headers: Headers): Boolean fun verify(headers: Headers): Boolean
} }
@Single @Single
@Service
class HttpSignatureVerifyServiceImpl( class HttpSignatureVerifyServiceImpl(
private val userQueryService: UserQueryService, private val userQueryService: UserQueryService,
private val transaction: Transaction private val transaction: Transaction

View File

@ -15,10 +15,12 @@ import dev.usbharu.hideout.service.core.MetaService
import dev.usbharu.hideout.util.RsaUtil import dev.usbharu.hideout.util.RsaUtil
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
import java.time.Instant import java.time.Instant
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
import java.util.* import java.util.*
@Service
interface JwtService { interface JwtService {
suspend fun createToken(user: User): JwtToken suspend fun createToken(user: User): JwtToken
suspend fun refreshToken(refreshToken: RefreshToken): JwtToken suspend fun refreshToken(refreshToken: RefreshToken): JwtToken
@ -30,6 +32,7 @@ interface JwtService {
@Suppress("InjectDispatcher") @Suppress("InjectDispatcher")
@Single @Single
@Service
class JwtServiceImpl( class JwtServiceImpl(
private val metaService: MetaService, private val metaService: MetaService,
private val refreshTokenRepository: JwtRefreshTokenRepository, private val refreshTokenRepository: JwtRefreshTokenRepository,

View File

@ -0,0 +1,28 @@
package dev.usbharu.hideout.service.auth
import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.service.core.Transaction
import kotlinx.coroutines.runBlocking
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.stereotype.Service
@Service
class UserDetailsServiceImpl(private val userQueryService: UserQueryService, private val transaction: Transaction) :
UserDetailsService {
override fun loadUserByUsername(username: String?): UserDetails = runBlocking {
if (username == null) {
throw UsernameNotFoundException("$username not found")
}
transaction.transaction {
val findById = userQueryService.findByNameAndDomain(username, "")
User(
findById.name,
findById.password,
emptyList()
)
}
}
}

View File

@ -2,8 +2,10 @@ package dev.usbharu.hideout.service.core
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Single @Single
@Service
class ExposedTransaction : Transaction { class ExposedTransaction : Transaction {
override suspend fun <T> transaction(block: suspend () -> T): T { override suspend fun <T> transaction(block: suspend () -> T): T {
return newSuspendedTransaction(transactionIsolation = java.sql.Connection.TRANSACTION_SERIALIZABLE) { return newSuspendedTransaction(transactionIsolation = java.sql.Connection.TRANSACTION_SERIALIZABLE) {

View File

@ -1,5 +1,8 @@
package dev.usbharu.hideout.service.core package dev.usbharu.hideout.service.core
import org.springframework.stereotype.Service
@Service
interface IdGenerateService { interface IdGenerateService {
suspend fun generateId(): Long suspend fun generateId(): Long
} }

View File

@ -2,7 +2,9 @@ package dev.usbharu.hideout.service.core
import dev.usbharu.hideout.domain.model.hideout.entity.Jwt import dev.usbharu.hideout.domain.model.hideout.entity.Jwt
import dev.usbharu.hideout.domain.model.hideout.entity.Meta import dev.usbharu.hideout.domain.model.hideout.entity.Meta
import org.springframework.stereotype.Service
@Service
interface MetaService { interface MetaService {
suspend fun getMeta(): Meta suspend fun getMeta(): Meta
suspend fun updateMeta(meta: Meta) suspend fun updateMeta(meta: Meta)

View File

@ -5,8 +5,10 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Meta
import dev.usbharu.hideout.exception.NotInitException import dev.usbharu.hideout.exception.NotInitException
import dev.usbharu.hideout.repository.MetaRepository import dev.usbharu.hideout.repository.MetaRepository
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Single @Single
@Service
class MetaServiceImpl(private val metaRepository: MetaRepository, private val transaction: Transaction) : class MetaServiceImpl(private val metaRepository: MetaRepository, private val transaction: Transaction) :
MetaService { MetaService {
override suspend fun getMeta(): Meta = override suspend fun getMeta(): Meta =

View File

@ -1,5 +1,8 @@
package dev.usbharu.hideout.service.core package dev.usbharu.hideout.service.core
import org.springframework.stereotype.Service
@Service
interface ServerInitialiseService { interface ServerInitialiseService {
suspend fun init() suspend fun init()
} }

View File

@ -7,10 +7,12 @@ import dev.usbharu.hideout.util.ServerUtil
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.security.KeyPairGenerator import java.security.KeyPairGenerator
import java.util.* import java.util.*
@Single @Single
@Service
class ServerInitialiseServiceImpl( class ServerInitialiseServiceImpl(
private val metaRepository: MetaRepository, private val metaRepository: MetaRepository,
private val transaction: Transaction private val transaction: Transaction

View File

@ -1,5 +1,8 @@
package dev.usbharu.hideout.service.core package dev.usbharu.hideout.service.core
import org.springframework.stereotype.Service
@Service
interface Transaction { interface Transaction {
suspend fun <T> transaction(block: suspend () -> T): T suspend fun <T> transaction(block: suspend () -> T): T
suspend fun <T> transaction(transactionLevel: Int, block: suspend () -> T): T suspend fun <T> transaction(transactionLevel: Int, block: suspend () -> T): T

View File

@ -1,5 +1,10 @@
package dev.usbharu.hideout.service.core package dev.usbharu.hideout.service.core
import org.springframework.context.annotation.Primary
import org.springframework.stereotype.Service
// 2010-11-04T01:42:54.657 // 2010-11-04T01:42:54.657
@Suppress("MagicNumber") @Suppress("MagicNumber")
@Service
@Primary
object TwitterSnowflakeIdGenerateService : SnowflakeIdGenerateService(1288834974657L) object TwitterSnowflakeIdGenerateService : SnowflakeIdGenerateService(1288834974657L)

View File

@ -2,7 +2,9 @@ package dev.usbharu.hideout.service.job
import kjob.core.Job import kjob.core.Job
import kjob.core.dsl.ScheduleContext import kjob.core.dsl.ScheduleContext
import org.springframework.stereotype.Service
@Service
interface JobQueueParentService { interface JobQueueParentService {
fun init(jobDefines: List<Job>) fun init(jobDefines: List<Job>)

View File

@ -2,9 +2,11 @@ package dev.usbharu.hideout.service.job
import kjob.core.Job import kjob.core.Job
import kjob.core.dsl.KJobFunctions import kjob.core.dsl.KJobFunctions
import org.springframework.stereotype.Service
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
interface JobQueueWorkerService { interface JobQueueWorkerService {
fun init(defines: List<Pair<Job, JRC<Job, JCWP<Job>>.(Job) -> KJobFunctions<Job, JCWP<Job>>>>) fun init(defines: List<Pair<Job, JRC<Job, JCWP<Job>>.(Job) -> KJobFunctions<Job, JCWP<Job>>>>)
} }

View File

@ -7,7 +7,9 @@ import kjob.core.dsl.ScheduleContext
import kjob.core.kjob import kjob.core.kjob
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
class KJobJobQueueParentService(private val database: Database) : JobQueueParentService { class KJobJobQueueParentService(private val database: Database) : JobQueueParentService {
private val logger = LoggerFactory.getLogger(this::class.java) private val logger = LoggerFactory.getLogger(this::class.java)

View File

@ -5,9 +5,11 @@ import kjob.core.Job
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 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
class KJobJobQueueWorkerService(private val database: Database) : JobQueueWorkerService { class KJobJobQueueWorkerService(private val database: Database) : JobQueueWorkerService {
val kjob by lazy { val kjob by lazy {

View File

@ -2,7 +2,9 @@ package dev.usbharu.hideout.service.post
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
import dev.usbharu.hideout.domain.model.hideout.entity.Post import dev.usbharu.hideout.domain.model.hideout.entity.Post
import org.springframework.stereotype.Service
@Service
interface PostService { interface PostService {
suspend fun createLocal(post: PostCreateDto): Post suspend fun createLocal(post: PostCreateDto): Post
} }

View File

@ -7,8 +7,10 @@ import dev.usbharu.hideout.repository.PostRepository
import dev.usbharu.hideout.repository.UserRepository import dev.usbharu.hideout.repository.UserRepository
import dev.usbharu.hideout.service.ap.APNoteService import dev.usbharu.hideout.service.ap.APNoteService
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
import java.time.Instant import java.time.Instant
@Service
@Single @Single
class PostServiceImpl( class PostServiceImpl(
private val postRepository: PostRepository, private val postRepository: PostRepository,

View File

@ -1,5 +1,8 @@
package dev.usbharu.hideout.service.reaction package dev.usbharu.hideout.service.reaction
import org.springframework.stereotype.Service
@Service
interface ReactionService { interface ReactionService {
suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long) suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long)
suspend fun sendReaction(name: String, userId: Long, postId: Long) suspend fun sendReaction(name: String, userId: Long, postId: Long)

View File

@ -5,8 +5,10 @@ import dev.usbharu.hideout.query.ReactionQueryService
import dev.usbharu.hideout.repository.ReactionRepository import dev.usbharu.hideout.repository.ReactionRepository
import dev.usbharu.hideout.service.ap.APReactionService import dev.usbharu.hideout.service.ap.APReactionService
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
@Single @Single
@Service
class ReactionServiceImpl( class ReactionServiceImpl(
private val reactionRepository: ReactionRepository, private val reactionRepository: ReactionRepository,
private val apReactionService: APReactionService, private val apReactionService: APReactionService,

View File

@ -1,7 +1,9 @@
package dev.usbharu.hideout.service.user package dev.usbharu.hideout.service.user
import org.springframework.stereotype.Service
import java.security.KeyPair import java.security.KeyPair
@Service
interface UserAuthService { interface UserAuthService {
fun hash(password: String): String fun hash(password: String): String

View File

@ -4,10 +4,12 @@ import dev.usbharu.hideout.config.Config
import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.query.UserQueryService
import io.ktor.util.* import io.ktor.util.*
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
import java.security.* import java.security.*
import java.util.* import java.util.*
@Single @Single
@Service
class UserAuthServiceImpl( class UserAuthServiceImpl(
val userQueryService: UserQueryService val userQueryService: UserQueryService
) : UserAuthService { ) : UserAuthService {

View File

@ -3,8 +3,10 @@ package dev.usbharu.hideout.service.user
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.UserCreateDto import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.domain.model.hideout.entity.User
import org.springframework.stereotype.Service
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
@Service
interface UserService { interface UserService {
suspend fun usernameAlreadyUse(username: String): Boolean suspend fun usernameAlreadyUse(username: String): Boolean

View File

@ -11,9 +11,11 @@ import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.repository.UserRepository import dev.usbharu.hideout.repository.UserRepository
import dev.usbharu.hideout.service.ap.APSendFollowService import dev.usbharu.hideout.service.ap.APSendFollowService
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import org.springframework.stereotype.Service
import java.time.Instant import java.time.Instant
@Single @Single
@Service
class UserServiceImpl( class UserServiceImpl(
private val userRepository: UserRepository, private val userRepository: UserRepository,
private val userAuthService: UserAuthService, private val userAuthService: UserAuthService,

View File

@ -0,0 +1,15 @@
package dev.usbharu.hideout.util
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
object JsonUtil {
val objectMapper = jacksonObjectMapper()
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)
}

View File

@ -0,0 +1,12 @@
hideout:
database:
url: "jdbc:h2:./test;MODE=POSTGRESQL"
driver: "org.h2.Driver"
user: ""
password: ""
spring:
datasource:
driver-class-name: org.h2.Driver
url: "jdbc:h2:./test;MODE=POSTGRESQL"
username: ""
password: ""

View File

@ -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"/>

Some files were not shown because too many files have changed in this diff Show More