実際に起動できるように

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-validation")
implementation(libs.blurhash)
implementation(libs.aws.s3)
implementation(libs.jsoup)
@ -173,6 +174,7 @@ dependencies {
implementation(libs.imageio.webp)
implementation(libs.thumbnailator)
implementation(libs.flyway.core)
runtimeOnly(libs.flyway.postgresql)
implementation("dev.usbharu:owl-common-serialize-jackson:0.0.1")

View File

@ -23,4 +23,5 @@ import java.net.URL
data class ApplicationConfig(
val url: URL,
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
import java.security.PrivateKey
import java.util.*
@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
import java.security.PublicKey
import java.util.*
@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 delete(actor: 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
}
.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.shared.domainevent.DomainEventPublisher
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.apId
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.content
@ -44,7 +45,10 @@ import org.slf4j.LoggerFactory
import org.springframework.stereotype.Repository
@Repository
class ExposedPostRepository(override val domainEventPublisher: DomainEventPublisher) :
class ExposedPostRepository(
private val postQueryMapper: QueryMapper<Post>,
override val domainEventPublisher: DomainEventPublisher,
) :
PostRepository,
AbstractRepository(),
DomainEventPublishableRepository<Post> {
@ -144,16 +148,23 @@ class ExposedPostRepository(override val domainEventPublisher: DomainEventPublis
return posts
}
override suspend fun findById(id: PostId): Post? {
query {
Posts.selectAll().where {
override suspend fun findById(id: PostId): Post? = query {
Posts
.selectAll()
.where {
Posts.id eq id.id
}
}
.let(postQueryMapper::map)
.first()
}
override suspend fun findByActorId(id: ActorId): List<Post> {
TODO("Not yet implemented")
override suspend fun findByActorId(id: ActorId): List<Post> = query {
Posts
.selectAll()
.where {
actorId eq id.id
}
.let(postQueryMapper::map)
}
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
datasource:
driver-class-name: org.postgresql.Driver
url: "jdbc:postgresql:hideout2"
url: "jdbc:postgresql:hideout3"
username: "postgres"
password: ""
data:

View File

@ -41,20 +41,20 @@ create table if not exists actors
url varchar(1000) not null unique,
public_key varchar(10000) not null,
private_key varchar(10000) null,
created_at bigint not null,
created_at timestamp not null,
key_id varchar(1000) not null,
"following" varchar(1000) null,
followers varchar(1000) null,
"instance" bigint not null,
"instance" bigint not null,
locked boolean not null,
following_count int not null,
followers_count int not null,
following_count int null,
followers_count int null,
posts_count int not null,
last_post_at timestamp null default null,
last_update_at timestamp not null,
suspend boolean not null,
move_to bigint null default null,
emojis varchar(3000) not null default '',
last_update_at timestamp not null,
suspend boolean not null,
move_to bigint null default null,
emojis varchar(3000) not null default '',
unique ("name", "domain"),
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
@ -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,
key_id, following, followers, instance, locked, following_count, followers_count, posts_count,
last_post_at)
values (0, 'ghost', '', '', '', '', '', '', '', null, 0, '', '', '', 0, true, 0, 0, 0, null);
last_post_at, last_update_at, suspend, move_to, emojis)
values (0, '', '', '', '', '', '', '', '', null, current_timestamp, '', null, null, 0, true, null, null, 0, null,
current_timestamp, false, null, '');
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" }
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" }