mirror of https://github.com/usbharu/Hideout.git
commit
f49bec3252
|
@ -0,0 +1,16 @@
|
|||
package dev.usbharu.hideout.activitypub.application.nodeinfo
|
||||
|
||||
@Suppress("ClassName")
|
||||
data class Nodeinfo2_0(
|
||||
val version: String = "2,0",
|
||||
val software: Map<String, String>,
|
||||
val protocol: List<String>,
|
||||
val usage: NodeinfoUsage,
|
||||
val openRegistration: Boolean,
|
||||
val metadata: Map<String, Any>,
|
||||
)
|
||||
|
||||
data class NodeinfoUsage(
|
||||
val users: Map<String, Long>,
|
||||
val localPosts: Long,
|
||||
)
|
|
@ -0,0 +1,52 @@
|
|||
package dev.usbharu.hideout.activitypub.application.nodeinfo
|
||||
|
||||
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.info.BuildProperties
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service/*
|
||||
* 今後ユーザーエージェントに応じてレスポンスを変更する可能性があるためApplicationServiceとして作成する commandは現時点ではUnitだが今後変化する可能性あり
|
||||
*/
|
||||
class NodeinfoApplicationService(
|
||||
@Autowired(required = false) private val buildInfo: BuildProperties?,
|
||||
private val applicationConfig: ApplicationConfig,
|
||||
transaction: Transaction,
|
||||
) : AbstractApplicationService<NodeinfoRequest, Nodeinfo2_0>(
|
||||
transaction,
|
||||
logger
|
||||
) {
|
||||
override suspend fun internalExecute(command: NodeinfoRequest, principal: Principal): Nodeinfo2_0 {
|
||||
return when (command.version) {
|
||||
"2.0", "2.1" -> Nodeinfo2_0(
|
||||
version = command.version,
|
||||
software = mapOf(
|
||||
"name" to "hideout",
|
||||
"version" to (buildInfo?.version ?: "UNKNOWN")
|
||||
),
|
||||
protocol = listOf("activitypub"),
|
||||
NodeinfoUsage(
|
||||
users = mapOf(
|
||||
"total" to 0,
|
||||
"activeMonth" to 0,
|
||||
"activeHalfyear" to 0
|
||||
),
|
||||
localPosts = 0
|
||||
),
|
||||
openRegistration = applicationConfig.private.not(),
|
||||
metadata = mapOf()
|
||||
)
|
||||
|
||||
else -> throw IllegalArgumentException("Invalid command version ${command.version}")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger: Logger = LoggerFactory.getLogger(NodeinfoApplicationService::class.java)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package dev.usbharu.hideout.activitypub.application.nodeinfo
|
||||
|
||||
data class NodeinfoRequest(val version: String)
|
|
@ -24,6 +24,7 @@ class ActivityPubSecurityConfig {
|
|||
)
|
||||
authorizeHttpRequests {
|
||||
authorize(GET, "/.well-known/**", permitAll)
|
||||
authorize(GET, "/nodeinfo/**", permitAll)
|
||||
authorize(GET, "/error", permitAll)
|
||||
authorize(POST, "/inbox", permitAll)
|
||||
authorize(POST, "/users/{username}/inbox", permitAll)
|
||||
|
|
|
@ -19,12 +19,8 @@ class HostmetaController(private val linkList: List<Link> = emptyList()) {
|
|||
|
||||
@Order(2)
|
||||
@GetMapping("/host-meta", produces = ["application/json"])
|
||||
fun hostmetaJson(): XRD {
|
||||
return XRD(linkList)
|
||||
}
|
||||
fun hostmetaJson(): XRD = XRD(linkList)
|
||||
|
||||
@GetMapping("/host-meta.json", produces = ["application/json"])
|
||||
fun hostmetaJson2(): XRD {
|
||||
return XRD(linkList)
|
||||
}
|
||||
fun hostmetaJson2(): XRD = XRD(linkList)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package dev.usbharu.hideout.activitypub.interfaces.wellknown
|
||||
|
||||
import dev.usbharu.hideout.activitypub.application.nodeinfo.Nodeinfo2_0
|
||||
import dev.usbharu.hideout.activitypub.application.nodeinfo.NodeinfoApplicationService
|
||||
import dev.usbharu.hideout.activitypub.application.nodeinfo.NodeinfoRequest
|
||||
import dev.usbharu.hideout.core.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
@RestController
|
||||
class NodeinfoController(
|
||||
private val applicationConfig: ApplicationConfig,
|
||||
private val nodeinfoApplicationService: NodeinfoApplicationService,
|
||||
) {
|
||||
@GetMapping("/.well-known/nodeinfo", produces = ["application/json"])
|
||||
fun nodeinfo(): XRD = XRD(
|
||||
listOf(
|
||||
Link(
|
||||
"http://nodeinfo.diaspora.software/ns/schema/2.1",
|
||||
href = applicationConfig.url.resolve("/nodeinfo/2.1").toString()
|
||||
),
|
||||
Link(
|
||||
"http://nodeinfo.diaspora.software/ns/schema/2.0",
|
||||
href = applicationConfig.url.resolve("/nodeinfo/2.0").toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@GetMapping("/nodeinfo/2.0", produces = ["application/json"])
|
||||
suspend fun nodeinfo2_0(): Nodeinfo2_0 = nodeinfoApplicationService.execute(NodeinfoRequest("2.0"), Anonymous)
|
||||
|
||||
@GetMapping("/nodeinfo/2.1", produces = ["application/json"])
|
||||
suspend fun nodeinfo2_1(): Nodeinfo2_0 = nodeinfoApplicationService.execute(NodeinfoRequest("2.1"), Anonymous)
|
||||
}
|
|
@ -24,8 +24,9 @@ data class XRD(
|
|||
data class Link(
|
||||
@JacksonXmlProperty(localName = "rel", isAttribute = true) val rel: String,
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JacksonXmlProperty(localName = "template", isAttribute = true) val template: String?,
|
||||
@JacksonXmlProperty(localName = "type", isAttribute = true) val type: String,
|
||||
@JacksonXmlProperty(localName = "template", isAttribute = true) val template: String? = null,
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JacksonXmlProperty(localName = "href", isAttribute = true) val href: String?,
|
||||
@JacksonXmlProperty(localName = "type", isAttribute = true) val type: String? = null,
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JacksonXmlProperty(localName = "href", isAttribute = true) val href: String? = null,
|
||||
)
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package dev.usbharu.hideout.activitypub.application.webfinger
|
||||
|
||||
|
||||
import dev.usbharu.hideout.activitypub.application.nodeinfo.NodeinfoApplicationService
|
||||
import dev.usbharu.hideout.activitypub.application.nodeinfo.NodeinfoRequest
|
||||
import dev.usbharu.hideout.core.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.InjectMocks
|
||||
import org.mockito.Spy
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import org.springframework.boot.info.BuildProperties
|
||||
import util.TestTransaction
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
|
||||
@ExtendWith(MockitoExtension::class)
|
||||
class NodeinfoApplicationServiceTest {
|
||||
@InjectMocks
|
||||
lateinit var nodeinfoApplicationService: NodeinfoApplicationService
|
||||
|
||||
@Spy
|
||||
val buildInfo: BuildProperties = BuildProperties(Properties())
|
||||
|
||||
@Spy
|
||||
val applicationConfig = ApplicationConfig(URI.create("https://example.com"))
|
||||
|
||||
@Spy
|
||||
val transaction = TestTransaction
|
||||
|
||||
@Test
|
||||
fun nodeinfo2_0() = runTest {
|
||||
val execute = nodeinfoApplicationService.execute(NodeinfoRequest("2.0"), Anonymous)
|
||||
|
||||
assertFalse(execute.openRegistration)
|
||||
assertEquals("2.0", execute.version)
|
||||
assertEquals("hideout", execute.software["name"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nodeinfo2_1() = runTest {
|
||||
val execute = nodeinfoApplicationService.execute(NodeinfoRequest("2.1"), Anonymous)
|
||||
|
||||
assertFalse(execute.openRegistration)
|
||||
assertEquals("2.1", execute.version)
|
||||
assertEquals("hideout", execute.software["name"])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package wellknown
|
||||
|
||||
import dev.usbharu.hideout.SpringApplication
|
||||
import org.flywaydb.core.Flyway
|
||||
import org.junit.jupiter.api.AfterAll
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||
import org.springframework.web.context.WebApplicationContext
|
||||
|
||||
@SpringBootTest(classes = [SpringApplication::class])
|
||||
@AutoConfigureMockMvc
|
||||
class NodeinfoControllerTest {
|
||||
|
||||
@Autowired
|
||||
private lateinit var context: WebApplicationContext
|
||||
|
||||
private lateinit var mockMvc: MockMvc
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockMvc = MockMvcBuilders.webAppContextSetup(context)
|
||||
.apply<DefaultMockMvcBuilder>(springSecurity())
|
||||
.build()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nodeinfo() {
|
||||
mockMvc.get("/.well-known/nodeinfo")
|
||||
.andDo { print() }
|
||||
.andExpect { status { isOk() } }
|
||||
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nodeinfo2_0() {
|
||||
mockMvc.get("/nodeinfo/2.0")
|
||||
.asyncDispatch()
|
||||
.andDo { print() }
|
||||
.andExpect { status { isOk() } }
|
||||
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nodeinfo2_1() {
|
||||
mockMvc.get("/nodeinfo/2.1")
|
||||
.asyncDispatch()
|
||||
.andDo { print() }
|
||||
.andExpect { status { isOk() } }
|
||||
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@AfterAll
|
||||
fun dropDatabase(@Autowired flyway: Flyway) {
|
||||
flyway.clean()
|
||||
flyway.migrate()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -90,7 +90,7 @@ class SecurityConfig {
|
|||
authorize("/error", permitAll)
|
||||
authorize("/auth/sign_in", permitAll)
|
||||
authorize(GET, "/.well-known/**", permitAll)
|
||||
authorize(GET, "/nodeinfo/2.0", permitAll)
|
||||
authorize(GET, "/nodeinfo/**", permitAll)
|
||||
|
||||
authorize(GET, "/auth/sign_up", hasRole("ANONYMOUS"))
|
||||
authorize(POST, "/auth/sign_up", permitAll)
|
||||
|
|
Loading…
Reference in New Issue