From 59298f77c2cac1f83c1f22d133ed22d64d682513 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 11 Nov 2023 17:37:22 +0900 Subject: [PATCH] =?UTF-8?q?test:=20note=E3=81=AE=E5=8C=BF=E5=90=8D?= =?UTF-8?q?=E3=81=AE=E3=81=A8=E3=81=8D=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/activitypub/note/NoteTest.kt | 91 +++++++++++++++++++ .../note/匿名でfollowers投稿を取得できる.sql | 14 +++ .../sql/note/匿名でpublic投稿を取得できる.sql | 13 +++ .../note/匿名でunlisted投稿を取得できる.sql | 14 +++ .../objects/note/NoteApApiServiceImpl.kt | 7 +- .../application/config/SecurityConfig.kt | 3 +- 6 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/intTest/kotlin/activitypub/note/NoteTest.kt create mode 100644 src/intTest/resources/sql/note/匿名でfollowers投稿を取得できる.sql create mode 100644 src/intTest/resources/sql/note/匿名でpublic投稿を取得できる.sql create mode 100644 src/intTest/resources/sql/note/匿名でunlisted投稿を取得できる.sql diff --git a/src/intTest/kotlin/activitypub/note/NoteTest.kt b/src/intTest/kotlin/activitypub/note/NoteTest.kt new file mode 100644 index 00000000..946a14a6 --- /dev/null +++ b/src/intTest/kotlin/activitypub/note/NoteTest.kt @@ -0,0 +1,91 @@ +package activitypub.note + +import dev.usbharu.hideout.SpringApplication +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.context.support.WithAnonymousUser +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity +import org.springframework.test.context.jdbc.Sql +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.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class]) +@AutoConfigureMockMvc +@Transactional +class NoteTest { + private lateinit var mockMvc: MockMvc + + @Autowired + private lateinit var context: WebApplicationContext + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build() + } + + @Test + @WithAnonymousUser + @Sql("/sql/note/匿名でpublic投稿を取得できる.sql") + fun `匿名でpublic投稿を取得できる`() { + mockMvc + .get("/users/test-user/posts/1234") { + accept(MediaType("application", "activity+json")) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + .andExpect { content { contentType("application/activity+json") } } + .andExpect { jsonPath("\$.type") { value("Note") } } + .andExpect { jsonPath("\$.to") { value("https://www.w3.org/ns/activitystreams#Public") } } + .andExpect { jsonPath("\$.cc") { value("https://www.w3.org/ns/activitystreams#Public") } } + } + + @Test + @Sql("/sql/note/匿名でunlisted投稿を取得できる.sql") + @WithAnonymousUser + fun 匿名でunlisted投稿を取得できる() { + mockMvc + .get("/users/test-user2/posts/1235") { + accept(MediaType("application", "activity+json")) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + .andExpect { content { contentType("application/activity+json") } } + .andExpect { jsonPath("\$.type") { value("Note") } } + .andExpect { jsonPath("\$.to") { value("https://example.com/users/test-user2/followers") } } + .andExpect { jsonPath("\$.cc") { value("https://www.w3.org/ns/activitystreams#Public") } } + } + + @Test + @Transactional + @WithAnonymousUser + @Sql("/sql/note/匿名でfollowers投稿を取得できる.sql") + fun 匿名でfollowers投稿を取得しようとすると404() { + mockMvc + .get("/users/test-user2/posts/1236") { + accept(MediaType("application", "activity+json")) + } + .asyncDispatch() + .andExpect { status { isNotFound() } } + } + + @Test + @WithAnonymousUser + fun 匿名でdirect投稿を取得しようとすると404() { + mockMvc + .get("/users/test-user2/posts/1236") { + accept(MediaType("application", "activity+json")) + } + .asyncDispatch() + .andExpect { status { isNotFound() } } + } +} diff --git a/src/intTest/resources/sql/note/匿名でfollowers投稿を取得できる.sql b/src/intTest/resources/sql/note/匿名でfollowers投稿を取得できる.sql new file mode 100644 index 00000000..71ee8f8d --- /dev/null +++ b/src/intTest/resources/sql/note/匿名でfollowers投稿を取得できる.sql @@ -0,0 +1,14 @@ +insert into "USERS" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, PASSWORD, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, + CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS) +VALUES (3, 'test-user3', 'example.com', 'Im test user3.', 'THis account is test user3.', + '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', + 'https://example.com/users/test-user3/inbox', + 'https://example.com/users/test-user3/outbox', 'https://example.com/users/test-user3', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user3#pubkey', 'https://example.com/users/test-user3/following', + 'https://example.com/users/test-user3/followers'); + +insert into POSTS (ID, "userId", OVERVIEW, TEXT, "createdAt", VISIBILITY, URL, "repostId", "replyId", SENSITIVE, AP_ID) +VALUES (1236, 3, null, 'test post', 12345680, 2, 'https://example.com/users/test-user3/posts/1236', null, null, false, + 'https://example.com/users/test-user3/posts/1236') diff --git a/src/intTest/resources/sql/note/匿名でpublic投稿を取得できる.sql b/src/intTest/resources/sql/note/匿名でpublic投稿を取得できる.sql new file mode 100644 index 00000000..23f38afc --- /dev/null +++ b/src/intTest/resources/sql/note/匿名でpublic投稿を取得できる.sql @@ -0,0 +1,13 @@ +insert into "USERS" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, PASSWORD, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, + CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS) +VALUES (1, 'test-user', 'example.com', 'Im test user.', 'THis account is test user.', + '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', 'https://example.com/users/test-user/inbox', + 'https://example.com/users/test-user/outbox', 'https://example.com/users/test-user', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user#pubkey', 'https://example.com/users/test-user/following', + 'https://example.com/users/test-users/followers'); + +insert into POSTS (ID, "userId", OVERVIEW, TEXT, "createdAt", VISIBILITY, URL, "repostId", "replyId", SENSITIVE, AP_ID) +VALUES (1234, 1, null, 'test post', 12345680, 0, 'https://example.com/users/test-user/posts/1234', null, null, false, + 'https://example.com/users/test-user/posts/1234') diff --git a/src/intTest/resources/sql/note/匿名でunlisted投稿を取得できる.sql b/src/intTest/resources/sql/note/匿名でunlisted投稿を取得できる.sql new file mode 100644 index 00000000..88c8bf9a --- /dev/null +++ b/src/intTest/resources/sql/note/匿名でunlisted投稿を取得できる.sql @@ -0,0 +1,14 @@ +insert into "USERS" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, PASSWORD, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, + CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS) +VALUES (2, 'test-user2', 'example.com', 'Im test user2.', 'THis account is test user2.', + '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', + 'https://example.com/users/test-user2/inbox', + 'https://example.com/users/test-user2/outbox', 'https://example.com/users/test-user2', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user2#pubkey', 'https://example.com/users/test-user2/following', + 'https://example.com/users/test-user2/followers'); + +insert into POSTS (ID, "userId", OVERVIEW, TEXT, "createdAt", VISIBILITY, URL, "repostId", "replyId", SENSITIVE, AP_ID) +VALUES (1235, 2, null, 'test post', 12345680, 1, 'https://example.com/users/test-user2/posts/1235', null, null, false, + 'https://example.com/users/test-user2/posts/1235') diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/NoteApApiServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/NoteApApiServiceImpl.kt index 84485ba3..ec92c515 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/NoteApApiServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/NoteApApiServiceImpl.kt @@ -3,6 +3,7 @@ package dev.usbharu.hideout.activitypub.service.objects.note import dev.usbharu.hideout.activitypub.domain.model.Note import dev.usbharu.hideout.activitypub.query.NoteQueryService import dev.usbharu.hideout.application.external.Transaction +import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException import dev.usbharu.hideout.core.domain.model.post.Visibility import dev.usbharu.hideout.core.query.FollowerQueryService import org.springframework.stereotype.Service @@ -14,7 +15,11 @@ class NoteApApiServiceImpl( private val transaction: Transaction ) : NoteApApiService { override suspend fun getNote(postId: Long, userId: Long?): Note? = transaction.transaction { - val findById = noteQueryService.findById(postId) + val findById = try { + noteQueryService.findById(postId) + } catch (_: FailedToGetResourcesException) { + return@transaction null + } when (findById.second.visibility) { Visibility.PUBLIC, Visibility.UNLISTED -> { return@transaction findById.first diff --git a/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt b/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt index 7ca3dfbc..eb76234f 100644 --- a/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt @@ -82,7 +82,8 @@ class SecurityConfig { HttpSignatureFilter::class.java ) .authorizeHttpRequests { - it.anyRequest().authenticated() + it.requestMatchers("/inbox", "/outbox", "/users/*/inbox", "/users/*/outbox").authenticated() + it.anyRequest().permitAll() } .csrf { it.disable()