mirror of https://github.com/usbharu/Hideout.git
Merge pull request #37 from usbharu/feature/spring-boot
Feature/spring boot
This commit is contained in:
commit
edd2465ad7
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
)
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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("/") {
|
||||||
|
|
|
@ -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 ->
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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") {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()}")
|
||||||
|
|
|
@ -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>()
|
||||||
|
|
|
@ -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") {
|
||||||
|
|
|
@ -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") {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>)
|
||||||
|
|
|
@ -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>>>>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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: ""
|
|
@ -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
Loading…
Reference in New Issue