実際に起動できるように

This commit is contained in:
usbharu 2024-06-04 23:46:09 +09:00
parent bd747718d4
commit 5e7b538d1d
14 changed files with 227 additions and 21 deletions

View File

@ -165,6 +165,7 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-log4j2") implementation("org.springframework.boot:spring-boot-starter-log4j2")
implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springframework.boot:spring-boot-starter-validation")
implementation(libs.blurhash) implementation(libs.blurhash)
implementation(libs.aws.s3) implementation(libs.aws.s3)
implementation(libs.jsoup) implementation(libs.jsoup)
@ -173,6 +174,7 @@ dependencies {
implementation(libs.imageio.webp) implementation(libs.imageio.webp)
implementation(libs.thumbnailator) implementation(libs.thumbnailator)
implementation(libs.flyway.core) implementation(libs.flyway.core)
runtimeOnly(libs.flyway.postgresql)
implementation("dev.usbharu:owl-common-serialize-jackson:0.0.1") implementation("dev.usbharu:owl-common-serialize-jackson:0.0.1")

View File

@ -23,4 +23,5 @@ import java.net.URL
data class ApplicationConfig( data class ApplicationConfig(
val url: URL, val url: URL,
val private: Boolean = true, val private: Boolean = true,
val keySize: Int = 2048,
) )

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.config
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
@Configuration
class SecurityConfig {
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
}

View File

@ -16,5 +16,22 @@
package dev.usbharu.hideout.core.domain.model.actor package dev.usbharu.hideout.core.domain.model.actor
import java.security.PrivateKey
import java.util.*
@JvmInline @JvmInline
value class ActorPrivateKey(val privateKey: String) value class ActorPrivateKey(val privateKey: String) {
companion object {
fun create(privateKey: PrivateKey): ActorPrivateKey {
return ActorPrivateKey(
"-----BEGIN PRIVATE KEY-----\n" +
Base64
.getEncoder()
.encodeToString(privateKey.encoded)
.chunked(64)
.joinToString("\n") +
"\n-----END PRIVATE KEY-----"
)
}
}
}

View File

@ -16,5 +16,22 @@
package dev.usbharu.hideout.core.domain.model.actor package dev.usbharu.hideout.core.domain.model.actor
import java.security.PublicKey
import java.util.*
@JvmInline @JvmInline
value class ActorPublicKey(val publicKey: String) value class ActorPublicKey(val publicKey: String) {
companion object {
fun create(publicKey: PublicKey): ActorPublicKey {
return ActorPublicKey(
"-----BEGIN PUBLIC KEY-----\n" +
Base64
.getEncoder()
.encodeToString(publicKey.encoded)
.chunked(64)
.joinToString("\n") +
"\n-----END PUBLIC KEY-----"
)
}
}
}

View File

@ -20,4 +20,5 @@ interface ActorRepository {
suspend fun save(actor: Actor): Actor suspend fun save(actor: Actor): Actor
suspend fun delete(actor: Actor) suspend fun delete(actor: Actor)
suspend fun findById(id: ActorId): Actor? suspend fun findById(id: ActorId): Actor?
suspend fun findByNameAndDomain(name: String, domain: String): Actor?
} }

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.domain.service.actor.local
import dev.usbharu.hideout.core.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.ActorPrivateKey
import dev.usbharu.hideout.core.domain.model.actor.ActorPublicKey
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import org.springframework.stereotype.Service
import java.security.KeyPairGenerator
@Service
class LocalActorDomainServiceImpl(
private val actorRepository: ActorRepository,
private val applicationConfig: ApplicationConfig,
) : LocalActorDomainService {
override suspend fun usernameAlreadyUse(name: String): Boolean =
actorRepository.findByNameAndDomain(name, applicationConfig.url.host) == null
override suspend fun generateKeyPair(): Pair<ActorPublicKey, ActorPrivateKey> {
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
keyPairGenerator.initialize(applicationConfig.keySize)
val generateKeyPair = keyPairGenerator.generateKeyPair()
return ActorPublicKey.create(generateKeyPair.public) to ActorPrivateKey.create(generateKeyPair.private)
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.domain.service.actor.local
import dev.usbharu.hideout.core.domain.model.actor.Actor
import org.springframework.stereotype.Service
@Service
class LocalActorMigrationCheckDomainServiceImpl : LocalActorMigrationCheckDomainService {
override suspend fun canAccountMigration(from: Actor, to: Actor): AccountMigrationCheck {
if (to == from) {
return AccountMigrationCheck.SelfReferences()
}
if (to.moveTo != null) {
return AccountMigrationCheck.AlreadyMoved("${to.name}@${to.domain} was move to ${to.moveTo}")
}
if (from.moveTo != null) {
return AccountMigrationCheck.AlreadyMoved("${from.name}@${from.domain} was move to ${from.moveTo}")
}
if (to.alsoKnownAs.contains(to.id).not()) {
return AccountMigrationCheck.AlsoKnownAsNotFound("${to.id} has ${to.alsoKnownAs}")
}
return AccountMigrationCheck.CanAccountMigration()
}
}

View File

@ -83,7 +83,20 @@ class ExposedActorRepository(
Actors.id eq id.id Actors.id eq id.id
} }
.let(actorQueryMapper::map) .let(actorQueryMapper::map)
.first() .firstOrNull()
}
}
override suspend fun findByNameAndDomain(name: String, domain: String): Actor? {
return query {
Actors
.leftJoin(ActorsAlsoKnownAs, onColumn = { id }, otherColumn = { actorId })
.selectAll()
.where {
Actors.name eq name and (Actors.domain eq domain)
}
.let(actorQueryMapper::map)
.firstOrNull()
} }
} }
} }

View File

@ -20,6 +20,7 @@ import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.post.* import dev.usbharu.hideout.core.domain.model.post.*
import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher
import dev.usbharu.hideout.core.domain.shared.repository.DomainEventPublishableRepository import dev.usbharu.hideout.core.domain.shared.repository.DomainEventPublishableRepository
import dev.usbharu.hideout.core.infrastructure.exposed.QueryMapper
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.actorId import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.actorId
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.apId import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.apId
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.content import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.content
@ -44,7 +45,10 @@ import org.slf4j.LoggerFactory
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
@Repository @Repository
class ExposedPostRepository(override val domainEventPublisher: DomainEventPublisher) : class ExposedPostRepository(
private val postQueryMapper: QueryMapper<Post>,
override val domainEventPublisher: DomainEventPublisher,
) :
PostRepository, PostRepository,
AbstractRepository(), AbstractRepository(),
DomainEventPublishableRepository<Post> { DomainEventPublishableRepository<Post> {
@ -144,16 +148,23 @@ class ExposedPostRepository(override val domainEventPublisher: DomainEventPublis
return posts return posts
} }
override suspend fun findById(id: PostId): Post? { override suspend fun findById(id: PostId): Post? = query {
query { Posts
Posts.selectAll().where { .selectAll()
.where {
Posts.id eq id.id Posts.id eq id.id
} }
} .let(postQueryMapper::map)
.first()
} }
override suspend fun findByActorId(id: ActorId): List<Post> { override suspend fun findByActorId(id: ActorId): List<Post> = query {
TODO("Not yet implemented") Posts
.selectAll()
.where {
actorId eq id.id
}
.let(postQueryMapper::map)
} }
override suspend fun delete(post: Post) { override suspend fun delete(post: Post) {

View File

@ -0,0 +1,28 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.springframework
import dev.usbharu.hideout.core.domain.service.userdetail.PasswordEncoder
import org.springframework.stereotype.Component
@Component
class SpringSecurityPasswordEncoder(private val passwordEncoder: org.springframework.security.crypto.password.PasswordEncoder) :
PasswordEncoder {
override suspend fun encode(input: String): String {
return passwordEncoder.encode(input)
}
}

View File

@ -23,7 +23,7 @@ spring:
default-property-inclusion: always default-property-inclusion: always
datasource: datasource:
driver-class-name: org.postgresql.Driver driver-class-name: org.postgresql.Driver
url: "jdbc:postgresql:hideout2" url: "jdbc:postgresql:hideout3"
username: "postgres" username: "postgres"
password: "" password: ""
data: data:

View File

@ -41,20 +41,20 @@ create table if not exists actors
url varchar(1000) not null unique, url varchar(1000) not null unique,
public_key varchar(10000) not null, public_key varchar(10000) not null,
private_key varchar(10000) null, private_key varchar(10000) null,
created_at bigint not null, created_at timestamp not null,
key_id varchar(1000) not null, key_id varchar(1000) not null,
"following" varchar(1000) null, "following" varchar(1000) null,
followers varchar(1000) null, followers varchar(1000) null,
"instance" bigint not null, "instance" bigint not null,
locked boolean not null, locked boolean not null,
following_count int not null, following_count int null,
followers_count int not null, followers_count int null,
posts_count int not null, posts_count int not null,
last_post_at timestamp null default null, last_post_at timestamp null default null,
last_update_at timestamp not null, last_update_at timestamp not null,
suspend boolean not null, suspend boolean not null,
move_to bigint null default null, move_to bigint null default null,
emojis varchar(3000) not null default '', emojis varchar(3000) not null default '',
unique ("name", "domain"), unique ("name", "domain"),
constraint fk_actors_instance__id foreign key ("instance") references instance (id) on delete restrict on update restrict, constraint fk_actors_instance__id foreign key ("instance") references instance (id) on delete restrict on update restrict,
constraint fk_actors_actors__move_to foreign key ("move_to") references actors (id) on delete restrict on update restrict constraint fk_actors_actors__move_to foreign key ("move_to") references actors (id) on delete restrict on update restrict
@ -250,8 +250,9 @@ values (0, 'system', '', '', '', null, '', '', false, false, '', current_timesta
insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at, insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at,
key_id, following, followers, instance, locked, following_count, followers_count, posts_count, key_id, following, followers, instance, locked, following_count, followers_count, posts_count,
last_post_at) last_post_at, last_update_at, suspend, move_to, emojis)
values (0, 'ghost', '', '', '', '', '', '', '', null, 0, '', '', '', 0, true, 0, 0, 0, null); values (0, '', '', '', '', '', '', '', '', null, current_timestamp, '', null, null, 0, true, null, null, 0, null,
current_timestamp, false, null, '');
create table if not exists deleted_actors create table if not exists deleted_actors
( (

View File

@ -82,6 +82,7 @@ imageio-webp = { module = "com.twelvemonkeys.imageio:imageio-webp", version = "3
thumbnailator = { module = "net.coobird:thumbnailator", version = "0.4.20" } thumbnailator = { module = "net.coobird:thumbnailator", version = "0.4.20" }
flyway-core = { module = "org.flywaydb:flyway-core" } flyway-core = { module = "org.flywaydb:flyway-core" }
flyway-postgresql = { module = "org.flywaydb:flyway-database-postgresql", version = "10.14.0" }
h2db = { module = "com.h2database:h2", version = "2.2.224" } h2db = { module = "com.h2database:h2", version = "2.2.224" }