diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index 096bb481d6..de64dcde6c 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -2,6 +2,7 @@ const db = require('../database'); const user = require('../user'); +const activitypub = require('.'); const helpers = require('./helpers'); @@ -24,8 +25,8 @@ inbox.isFollowed = async (actorId, uid) => { async function handleFollow(type, actorId, objectId) { // Sanity checks - const actorExists = await helpers.query(actorId); - if (!actorId || !actorExists) { + const from = await helpers.query(actorId); + if (!actorId || !from) { throw new Error('[[error:invalid-uid]]'); // should probably be AP specific } @@ -46,13 +47,64 @@ async function handleFollow(type, actorId, objectId) { } const now = Date.now(); await db.sortedSetAdd(`followersRemote:${localUid}`, now, actorId); + await activitypub.send(localUid, actorId, { + type: 'Accept', + object: { + type: 'Follow', + actor: from.actorUri, + }, + }); } else { if (!isFollowed) { throw new Error('[[error:not-following]]'); } await db.sortedSetRemove(`followersRemote:${localUid}`, actorId); + await activitypub.send(localUid, actorId, { + type: 'Undo', + object: { + type: 'Follow', + actor: from.actorUri, + }, + }); } const followerRemoteCount = await db.sortedSetCard(`followersRemote:${localUid}`); await user.setUserField(localUid, 'followerRemoteCount', followerRemoteCount); } + +inbox.accept = async (req) => { + const { actor, object } = req.body; + const { type } = object; + + if (type === 'Follow') { + // todo: should check that actor and object.actor are the same person? + const uid = await helpers.resolveLocalUid(object.actor); + if (!uid) { + throw new Error('[[error:invalid-uid]]'); + } + + const now = Date.now(); + await Promise.all([ + db.sortedSetAdd(`followingRemote:${uid}`, now, actor.name), + db.incrObjectField(`user:${uid}`, 'followingRemoteCount'), + ]); + } +}; + +inbox.undo = async (req) => { + const { actor, object } = req.body; + const { type } = object; + + if (type === 'Follow') { + // todo: should check that actor and object.actor are the same person? + const uid = await helpers.resolveLocalUid(object.actor); + if (!uid) { + throw new Error('[[error:invalid-uid]]'); + } + + await Promise.all([ + db.sortedSetRemove(`followingRemote:${uid}`, actor.name), + db.decrObjectField(`user:${uid}`, 'followingRemoteCount'), + ]); + } +}; diff --git a/src/activitypub/index.js b/src/activitypub/index.js index b257a7e5cf..40370b4981 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -178,12 +178,10 @@ ActivityPub.send = async (uid, targets, payload) => { const inboxes = await ActivityPub.resolveInboxes(targets); payload = { - ...{ - '@context': 'https://www.w3.org/ns/activitystreams', - actor: { - type: 'Person', - name: `${userslug}@${nconf.get('url_parsed').host}`, - }, + '@context': 'https://www.w3.org/ns/activitystreams', + actor: { + type: 'Person', + name: `${userslug}@${nconf.get('url_parsed').host}`, }, ...payload, }; diff --git a/src/controllers/activitypub/index.js b/src/controllers/activitypub/index.js index bfa07d33e3..153f97d701 100644 --- a/src/controllers/activitypub/index.js +++ b/src/controllers/activitypub/index.js @@ -113,6 +113,21 @@ Controller.postInbox = async (req, res) => { await activitypub.inbox.unfollow(req.body.actor.name, req.body.object.name); break; } + + case 'Accept': { + await activitypub.inbox.accept(req); + break; + } + + case 'Undo': { + await activitypub.inbox.undo(req); + break; + } + + default: { + console.log('Unhandled Activity!!!'); + console.log(req.body); + } } res.sendStatus(201);