From bac87790c6d044e3bfe9781dd285dfa4b33e49ee Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Mon, 1 Oct 2018 17:58:46 +0300 Subject: ActivityPub: HTTP Signatures and autoaccept followers --- .../java/com/juick/server/tests/ServerTests.java | 39 ++++++++++++---- juick-server/src/test/resources/follow.json | 42 +++++++++++++++++ juick-server/src/test/resources/person.json | 54 ++++++++++++++++++++++ juick-server/src/test/resources/undo.json | 47 +++++++++++++++++++ 4 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 juick-server/src/test/resources/follow.json create mode 100644 juick-server/src/test/resources/person.json create mode 100644 juick-server/src/test/resources/undo.json (limited to 'juick-server/src/test') diff --git a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java index 0f483acc..c697ffc6 100644 --- a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java +++ b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java @@ -27,18 +27,21 @@ import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.jayway.jsonpath.JsonPath; import com.juick.*; -import com.juick.server.*; -import com.juick.server.api.activity.model.ActivityObject; -import com.juick.service.component.MessageEvent; import com.juick.model.AnonymousUser; import com.juick.model.CommandResult; import com.juick.model.TagStats; +import com.juick.server.*; +import com.juick.server.api.activity.model.Context; +import com.juick.server.api.activity.model.Key; +import com.juick.server.api.activity.model.Person; +import com.juick.server.api.activity.model.activities.Follow; import com.juick.server.util.HttpUtils; import com.juick.server.util.ImageUtils; import com.juick.server.www.Utils; import com.juick.server.xmpp.helpers.XMPPStatus; import com.juick.server.xmpp.s2s.ConnectionIn; import com.juick.service.*; +import com.juick.service.component.MessageEvent; import com.juick.util.DateFormattersHolder; import com.juick.util.MessageUtils; import com.mitchellbosecke.pebble.PebbleEngine; @@ -60,10 +63,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.core.io.ClassPathResource; import org.springframework.http.*; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -193,6 +194,8 @@ public class ServerTests { private PebbleEngine pebbleEngine; @Value("${ios_app_id:}") private String appId; + @Inject + private SignatureManager signatureManager; private static User ugnich, freefd, juick; static String ugnichName, ugnichPassword, freefdName, freefdPassword, juickName, juickPassword; @@ -1419,17 +1422,17 @@ public class ServerTests { } @Test public void userProfileAndBlogShouldBeExposedAsActivityStream() throws Exception { - mockMvc.perform(get("/u/ugnich").accept(ActivityObject.LD_JSON_MEDIA_TYPE)) + mockMvc.perform(get("/u/ugnich").accept(Context.LD_JSON_MEDIA_TYPE)) .andExpect(status().isOk()) .andExpect(jsonPath("$.icon.url", is("http://localhost:8080/i/a/1.png"))) - .andExpect(jsonPath("$.publicKey.publicKeyPem", is(keystoreManager.getPublicKey()))); + .andExpect(jsonPath("$.publicKey.publicKeyPem", is(keystoreManager.getPublicKeyPem()))); jdbcTemplate.execute("DELETE FROM messages"); List mids = IteratorUtils.toList(IntStream.rangeClosed(1, 30) .mapToObj(i -> messagesService.createMessage(ugnich.getUid(), String.format("message %d", i), null, null)) .collect(Collectors.toCollection(ArrayDeque::new)).descendingIterator()); List midsPage = mids.stream().limit(20).collect(Collectors.toList()); - mockMvc.perform(get("/u/ugnich/blog").accept(ActivityObject.ACTIVITY_JSON_MEDIA_TYPE)) + mockMvc.perform(get("/u/ugnich/blog").accept(Context.ACTIVITY_JSON_MEDIA_TYPE)) .andExpect(status().isOk()) .andExpect(jsonPath("$.orderedItems", hasSize(20))) .andExpect(jsonPath("$.next", is("http://localhost:8080/u/ugnich/blog?before=" + midsPage.get(midsPage.size() - 1)))); @@ -1676,4 +1679,24 @@ public class ServerTests { .param("hash", userService.getHashByUID(ugnich.getUid())) .param("List-Unsubscribe", "One-Click")).andExpect(status().isOk()); } + @Test + public void ActivityDeserialization() throws IOException { + String followJsonStr = IOUtils.toString(URI.create("classpath:follow.json"), StandardCharsets.UTF_8); + Follow follow = (Follow)jsonMapper.readValue(followJsonStr, Context.class); + String personJsonStr = IOUtils.toString(URI.create("classpath:person.json"), StandardCharsets.UTF_8); + Person person = (Person)jsonMapper.readValue(personJsonStr, Context.class); + } + @Test + public void signingSpec() throws IOException { + Key fromKey = new Key(); + fromKey.setId("to-key-id"); + Person from = new Person(); + from.setPublicKey(fromKey); + Person to = new Person(); + to.setInbox("http://localhost:8080/api/inbox"); + Follow follow = new Follow(); + follow.setActor("http://localhost:8080/u/freefd"); + follow.setObject("http://localhost:8080/u/ugnich"); + signatureManager.post(from, to, follow); + } } diff --git a/juick-server/src/test/resources/follow.json b/juick-server/src/test/resources/follow.json new file mode 100644 index 00000000..93d46c24 --- /dev/null +++ b/juick-server/src/test/resources/follow.json @@ -0,0 +1,42 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "https://mastodon.social/970f0d76-9ea7-46cd-a3e9-278e255f082d", + "type": "Follow", + "actor": "https://mastodon.social/users/xwatt", + "object": "https://x.juick.com/u/gegege", + "signature": { + "type": "RsaSignature2017", + "creator": "https://mastodon.social/users/xwatt#main-key", + "created": "2018-10-02T09:39:29Z", + "signatureValue": "lkxaKueSjT0nxCnT15hR8e1yQ7RsUCF0gBaiSAtXmN0tT3g7OcQPZUzUvCFF2aXB8xGFHMv+7Rp+jegR8rszuNRIghUxsOfYL5da2mD5UrpIlxiW4FxZjbni0klUF9GhRWfBYLIMumUsl9UElZPxtpYjlDQ7kCzYqnwbGgUiI0ehBJrHQJHET0pcyeSdGoRlXwD3I4c59nbr22CT026FBRNSJIxJj865ij5vg0j0q0/2ep+8ztya3x0+aYSrFn8WGO4Y2muCJtKurH2ROv8yyVgaIyFaUx6uvBf6pO3oGfWrm5if0P924LLlReXBItbleZrp0y2jPE7RriZsZmuFbg==" + } +} \ No newline at end of file diff --git a/juick-server/src/test/resources/person.json b/juick-server/src/test/resources/person.json new file mode 100644 index 00000000..67e88257 --- /dev/null +++ b/juick-server/src/test/resources/person.json @@ -0,0 +1,54 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "https://mastodon.social/users/xwatt", + "type": "Person", + "following": "https://mastodon.social/users/xwatt/following", + "followers": "https://mastodon.social/users/xwatt/followers", + "inbox": "https://mastodon.social/users/xwatt/inbox", + "outbox": "https://mastodon.social/users/xwatt/outbox", + "featured": "https://mastodon.social/users/xwatt/collections/featured", + "preferredUsername": "xwatt", + "name": "", + "summary": "\u003cp\u003e\u003c/p\u003e", + "url": "https://mastodon.social/@xwatt", + "manuallyApprovesFollowers": false, + "publicKey": { + "id": "https://mastodon.social/users/xwatt#main-key", + "owner": "https://mastodon.social/users/xwatt", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuCYg1WrzerteFgLcbnRC\n1/pL5jFY05iuB4ycRlxxCpwpDihKdcmJ8nVEpFc/CIRtRRA3Oq1a+yF4L5X3Bwi8\nA8ajKHNtiPd4eeGdGvEJidf8cR8Bmfmrzt669Tmja+5Cr1CaFX9mYXhQoY6CqIxR\nDrPAAUb0CHJV+Ta6QkieCaGxYsvdg6Gg+8aw6k60vBswS6fmNsykH9xrovqtBb9M\ncKglyOA2W2FgswYtzRRKT5QQU4x/hfWMYuIEMhnke3U5k2gzb/qnJM2otaR0NzJ0\nkW+Fu7av5E6Ur1sUe1hTHpDxaAmNC+br19wTn6zh4Wt1UJp+Os56hBTSq50WKcfW\nhQIDAQAB\n-----END PUBLIC KEY-----\n" + }, + "tag": [], + "attachment": [], + "endpoints": { + "sharedInbox": "https://mastodon.social/inbox" + } +} \ No newline at end of file diff --git a/juick-server/src/test/resources/undo.json b/juick-server/src/test/resources/undo.json new file mode 100644 index 00000000..371c6bd6 --- /dev/null +++ b/juick-server/src/test/resources/undo.json @@ -0,0 +1,47 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": { + "@id": "as:movedTo", + "@type": "@id" + }, + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji", + "focalPoint": { + "@container": "@list", + "@id": "toot:focalPoint" + }, + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value" + } + ], + "id": "https://mastodon.social/users/xwatt#follows/1553133/undo", + "type": "Undo", + "actor": "https://mastodon.social/users/xwatt", + "object": { + "id": "https://mastodon.social/c5cfbc0b-3e4b-423a-aa51-1c38e1202371", + "type": "Follow", + "actor": "https://mastodon.social/users/xwatt", + "object": "https://x.juick.com/u/gegege" + }, + "signature": { + "type": "RsaSignature2017", + "creator": "https://mastodon.social/users/xwatt#main-key", + "created": "2018-10-02T10:27:33Z", + "signatureValue": "OOK3WDLgVMo6u1l/I1o4hrcOf12X2ryOa/xAeuYf7ncKQJbzFXohUYCrBtgUKjnOQJLHY/HbhhFE1SBXMCMUbPNF8KeztxWKqWnXtXNSHVv6Shxl+9yxZoGaAgpkYjn9qQGTAm4SXmV0RM49cz84PfLAJI1fUecoVclhVWXJuaSz4yZ/UteySjBMB5h5nPWGDmz4usviZ9EZTihr3xkFfkg+CPYwr5SYWDe5W1MxeKoosEck6Yhwt8OOf/eGB5guN81lp90O76oO6LGhblnYhMKxsOJf4ahF9qeCNajXk/qiwSfl6IwVADYlFB1GGTdIPXUUob5HhjX27Bpyah0lgA==" + } +} \ No newline at end of file -- cgit v1.2.3