diff options
author | 2018-10-04 12:18:42 +0300 | |
---|---|---|
committer | 2018-10-04 09:35:24 +0000 | |
commit | 5be22ee8963cf45190b13b41dc2dac7b7b0bfb01 (patch) | |
tree | 2ace48b2d11decb816638514157f71269c95e791 /juick-server/src/main/java/com/juick/server | |
parent | 7f9187d8a87a5cd6e2720eac0d03f1c2fcc507ed (diff) |
ActivityPub: persist followers and forward message event to them
Diffstat (limited to 'juick-server/src/main/java/com/juick/server')
4 files changed, 140 insertions, 38 deletions
diff --git a/juick-server/src/main/java/com/juick/server/ActivityPubManager.java b/juick-server/src/main/java/com/juick/server/ActivityPubManager.java index 362754fd..ded04313 100644 --- a/juick-server/src/main/java/com/juick/server/ActivityPubManager.java +++ b/juick-server/src/main/java/com/juick/server/ActivityPubManager.java @@ -1,37 +1,148 @@ package com.juick.server; +import com.juick.Message; +import com.juick.User; +import com.juick.server.api.activity.model.Link; +import com.juick.server.api.activity.model.Note; import com.juick.server.api.activity.model.Person; import com.juick.server.api.activity.model.activities.Accept; +import com.juick.server.api.activity.model.activities.Create; +import com.juick.service.SocialService; import com.juick.service.activities.FollowEvent; +import com.juick.service.component.*; +import com.juick.util.MessageUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; import javax.annotation.Nonnull; +import javax.annotation.PostConstruct; import javax.inject.Inject; import java.io.IOException; import java.net.URI; +import java.util.Collections; @Component -public class ActivityPubManager implements ApplicationListener<FollowEvent> { +public class ActivityPubManager implements ApplicationListener<FollowEvent>, NotificationListener { private static final Logger logger = LoggerFactory.getLogger(ActivityPubManager.class); @Inject SignatureManager signatureManager; + @Inject + ActivityPubManager activityPubManager; + @Inject + SocialService socialService; + @Value("${ap_base_uri:http://localhost:8080/}") + private String baseUri; + + private UriComponentsBuilder uri; + + @PostConstruct + public void init() { + uri = UriComponentsBuilder.fromUriString(baseUri); + } + @Override public void onApplicationEvent(@Nonnull FollowEvent followEvent) { - logger.info("received follower request"); - // automatically accept follower requests - Person me = (Person) signatureManager.getContext(URI.create((String)followEvent.getRequest().getObject())); - Person follower = (Person) signatureManager.getContext(URI.create(followEvent.getRequest().getActor())); - Accept accept = new Accept(); - accept.setActor(me.getId()); - accept.setObject(followEvent.getRequest()); - try { - signatureManager.post(me, follower, accept); - } catch (IOException e) { - logger.info("activitypub exception", e); + String acct = (String)followEvent.getRequest().getObject(); + logger.info("received follower request to {}", acct); + User followedUser = socialService.getUserByAccountUri(acct); + if (!followedUser.isAnonymous()) { + // automatically accept follower requests + Person me = (Person) signatureManager.getContext(URI.create(acct)); + Person follower = (Person) signatureManager.getContext(URI.create(followEvent.getRequest().getActor())); + Accept accept = new Accept(); + accept.setActor(me.getId()); + accept.setObject(followEvent.getRequest()); + try { + signatureManager.post(me, follower, accept); + socialService.addFollower(followedUser, follower.getId()); + logger.info("Follower added for {}", followedUser.getName()); + } catch (IOException e) { + logger.info("activitypub exception", e); + } } + } + + @Override + public void processMessageEvent(MessageEvent messageEvent) { + Message msg = messageEvent.getMessage(); + User user = msg.getUser(); + String userUri = personUri(user); + Note note = makeNote(msg); + Person me = (Person) signatureManager.getContext(URI.create(userUri)); + socialService.getFollowers(user).forEach(acct -> { + Person follower = (Person) signatureManager.getContext(URI.create(acct)); + Create create = new Create(); + create.setId(note.getId()); + create.setActor(me.getId()); + create.setPublished(note.getPublished()); + create.setObject(note); + try { + logger.info("Posting to follower {}", follower.getId()); + signatureManager.post(me, follower, create); + } catch (IOException e) { + logger.warn("activitypub exception", e); + } + }); + } + + public String inboxUri() { + return uri.replacePath("/api/inbox").toUriString(); + } + + public String outboxUri(User user) { + return uri.replacePath(String.format("/u/%s/blog/toc", user.getName())).toUriString(); + } + + public String personUri(User user) { + return uri.replacePath(String.format("/u/%s", user.getName())).toUriString(); + } + + public String followersUri(User user) { + return uri.replacePath(String.format("/u/%s/followers/toc", user.getName())).toUriString(); + } + + public String followingUri(User user) { + return uri.replacePath(String.format("/u/%s/following/toc", user.getName())).toUriString(); + } + + public Note makeNote(Message msg) { + Note note = new Note(); + note.setId(uri.replacePath(String.format("/m/%d", msg.getMid())).toUriString()); + note.setAttributedTo(personUri(msg.getUser())); + note.setTo(Collections.singletonList("https://www.w3.org/ns/activitystreams#Public")); + note.setCc(Collections.singletonList(followersUri(msg.getUser()))); + note.setPublished(msg.getTimestamp()); + note.setContent(MessageUtils.formatMessage(msg.getText())); + if (StringUtils.isNotBlank(msg.getAttachmentType())) { + Link attachment = new Link(); + attachment.setHref(msg.getAttachment().getMedium().getUrl()); + note.setAttachment(attachment); + } + return note; + } + + @Override + public void processSubscribeEvent(SubscribeEvent subscribeEvent) { + + } + + @Override + public void processLikeEvent(LikeEvent likeEvent) { + + } + + @Override + public void processPingEvent(PingEvent pingEvent) { + + } + + @Override + public void processMessageReadEvent(MessageReadEvent messageReadEvent) { } } diff --git a/juick-server/src/main/java/com/juick/server/SignatureManager.java b/juick-server/src/main/java/com/juick/server/SignatureManager.java index d89919f0..268b6543 100644 --- a/juick-server/src/main/java/com/juick/server/SignatureManager.java +++ b/juick-server/src/main/java/com/juick/server/SignatureManager.java @@ -52,7 +52,7 @@ public class SignatureManager { //boolean valid = verifySignature(Signature.fromString(requestHeaders.getFirst("Signature")), // keystoreManager.getPublicKey(), "POST", inbox.getPath(), headers); ResponseEntity<Void> response = new RestTemplate().postForEntity(inbox, request, Void.class); - logger.info("accepted follower: {}", response.getStatusCode().is2xxSuccessful()); + logger.info("accepted follower: {}", response.getStatusCodeValue()); } public boolean verifySignature(String signatureString, URI actor, String method, String path, Map<String, String> headers) { Context context = getContext(actor); diff --git a/juick-server/src/main/java/com/juick/server/api/activity/Profile.java b/juick-server/src/main/java/com/juick/server/api/activity/Profile.java index 656d85dd..7b854d52 100644 --- a/juick-server/src/main/java/com/juick/server/api/activity/Profile.java +++ b/juick-server/src/main/java/com/juick/server/api/activity/Profile.java @@ -1,6 +1,7 @@ package com.juick.server.api.activity; import com.juick.User; +import com.juick.server.ActivityPubManager; import com.juick.server.KeystoreManager; import com.juick.server.SignatureManager; import com.juick.server.api.activity.model.*; @@ -43,6 +44,8 @@ public class Profile { @Inject private SignatureManager signatureManager; @Inject + private ActivityPubManager activityPubManager; + @Inject private ApplicationEventPublisher applicationEventPublisher; @Value("${web_domain:localhost}") private String domain; @@ -55,11 +58,9 @@ public class Profile { public Person getUser(@PathVariable String userName) { User user = userService.getUserByName(userName); if (!user.isAnonymous()) { - UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri); Person person = new Person(); - uri.replacePath(String.format("/u/%s", userName)); - person.setId(uri.toUriString()); - person.setUrl(uri.toUriString()); + person.setId(activityPubManager.personUri(user)); + person.setUrl(activityPubManager.personUri(user)); person.setName(userName); person.setPreferredUsername(userName); Key publicKey = new Key(); @@ -67,11 +68,10 @@ public class Profile { publicKey.setOwner(person.getId()); publicKey.setPublicKeyPem(keystoreManager.getPublicKeyPem()); person.setPublicKey(publicKey); - uri.replacePath("/api/inbox"); - person.setInbox(uri.toUriString()); - person.setOutbox(uri.replacePath(String.format("/u/%s/blog/toc", userName)).toUriString()); - person.setFollowers(uri.replacePath(String.format("/u/%s/followers/toc", userName)).toUriString()); - person.setFollowing(uri.replacePath(String.format("/u/%s/following/toc", userName)).toUriString()); + person.setInbox(activityPubManager.inboxUri()); + person.setOutbox(activityPubManager.outboxUri(user)); + person.setFollowers(activityPubManager.followersUri(user)); + person.setFollowing(activityPubManager.followingUri(user)); UriComponentsBuilder image = UriComponentsBuilder.fromUriString(baseImagesUri); image.path(String.format("/a/%d.png", user.getUid())); Image avatar = new Image(); @@ -103,23 +103,9 @@ public class Profile { if (!user.isAnonymous()) { UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri); String personUri = uri.path(String.format("/u/%s", userName)).toUriString(); - String followersUri = uri.replacePath(String.format("/u/%s/followers/toc", userName)).toUriString(); + String followersUri = activityPubManager.followersUri(user); List<Integer> mids = messagesService.getUserBlog(user.getUid(), 0, before); - List<Note> notes = messagesService.getMessages(visitor, mids).stream().map(m -> { - Note note = new Note(); - note.setId(uri.replacePath(String.format("/m/%d", m.getMid())).toUriString()); - note.setAttributedTo(personUri); - note.setTo(Collections.singletonList("https://www.w3.org/ns/activitystreams#Public")); - note.setCc(Collections.singletonList(followersUri)); - note.setPublished(m.getTimestamp()); - note.setContent(MessageUtils.formatMessage(m.getText())); - if (StringUtils.isNotBlank(m.getAttachmentType())) { - Link attachment = new Link(); - attachment.setHref(m.getAttachment().getMedium().getUrl()); - note.setAttachment(attachment); - } - return note; - }).collect(Collectors.toList()); + List<Note> notes = messagesService.getMessages(visitor, mids).stream().map(activityPubManager::makeNote).collect(Collectors.toList()); Person person = new Person(); person.setName(user.getName()); OrderedCollectionPage page = new OrderedCollectionPage(); diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/Note.java b/juick-server/src/main/java/com/juick/server/api/activity/model/Note.java index ff64c4b9..c15cd8d3 100644 --- a/juick-server/src/main/java/com/juick/server/api/activity/model/Note.java +++ b/juick-server/src/main/java/com/juick/server/api/activity/model/Note.java @@ -1,5 +1,10 @@ package com.juick.server.api.activity.model; +import com.juick.Message; +import com.juick.util.MessageUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; import java.util.List; public class Note extends Context { |