diff --git a/src/activitypub/actors.js b/src/activitypub/actors.js index 917efa4531..5a67012c22 100644 --- a/src/activitypub/actors.js +++ b/src/activitypub/actors.js @@ -30,13 +30,13 @@ Actors.assert = async (ids, options = {}) => { const actors = await Promise.all(ids.map(async (id) => { try { - const actor = (typeof id === 'object' && id.hasOwnProperty('id')) ? id : await activitypub.get(0, id); + const actor = (typeof id === 'object' && id.hasOwnProperty('id')) ? id : await activitypub.get('uid', 0, id); // Follow counts try { const [followers, following] = await Promise.all([ - actor.followers ? activitypub.get(0, actor.followers) : { totalItems: 0 }, - actor.following ? activitypub.get(0, actor.following) : { totalItems: 0 }, + actor.followers ? activitypub.get('uid', 0, actor.followers) : { totalItems: 0 }, + actor.following ? activitypub.get('uid', 0, actor.following) : { totalItems: 0 }, ]); actor.followerCount = followers.totalItems; actor.followingCount = following.totalItems; @@ -46,7 +46,7 @@ Actors.assert = async (ids, options = {}) => { } // Post count - const outbox = actor.outbox ? await activitypub.get(0, actor.outbox) : { totalItems: 0 }; + const outbox = actor.outbox ? await activitypub.get('uid', 0, actor.outbox) : { totalItems: 0 }; actor.postcount = outbox.totalItems; return actor; diff --git a/src/activitypub/helpers.js b/src/activitypub/helpers.js index 7cc91f97ad..49f42dba31 100644 --- a/src/activitypub/helpers.js +++ b/src/activitypub/helpers.js @@ -63,8 +63,8 @@ Helpers.query = async (id) => { return { username, hostname, actorUri, publicKey }; }; -Helpers.generateKeys = async (uid) => { - winston.verbose(`[activitypub] Generating RSA key-pair for uid ${uid}`); +Helpers.generateKeys = async (type, id) => { + winston.verbose(`[activitypub] Generating RSA key-pair for ${type} ${id}`); const { publicKey, privateKey, @@ -80,47 +80,41 @@ Helpers.generateKeys = async (uid) => { }, }); - await db.setObject(`uid:${uid}:keys`, { publicKey, privateKey }); + await db.setObject(`${type}:${id}:keys`, { publicKey, privateKey }); return { publicKey, privateKey }; }; -Helpers.resolveLocalUid = async (input) => { - let slug; - const protocols = ['https']; - if (process.env.CI === 'true') { - protocols.push('http'); - } +Helpers.resolveLocalId = async (input) => { if (Helpers.isUri(input)) { const { host, pathname } = new URL(input); if (host === nconf.get('url_parsed').host) { - const [type, value] = pathname.replace(nconf.get('relative_path'), '').split('/').filter(Boolean); - if (type === 'uid') { - return value; + const [prefix, value] = pathname.replace(nconf.get('relative_path'), '').split('/').filter(Boolean); + + switch (prefix) { + case 'uid': + return { type: 'user', id: value }; + + case 'post': + return { type: 'post', id: value }; + + case 'category': + return { type: 'category', id: value }; + + case 'user': { + const uid = await user.getUidByUserslug(value); + return { type: 'user', id: uid }; + } } - slug = value; + throw new Error('[[error:activitypub.invalid-id]]'); } else { throw new Error('[[error:activitypub.invalid-id]]'); } } else if (input.indexOf('@') !== -1) { // Webfinger - ([slug] = input.replace(/^acct:/, '').split('@')); - } else { - throw new Error('[[error:activitypub.invalid-id]]'); - } - - return await user.getUidByUserslug(slug); -}; - -Helpers.resolveLocalPid = async (uri) => { - const { host, pathname } = new URL(uri); - if (host === nconf.get('url_parsed').host) { - const [type, value] = pathname.replace(nconf.get('relative_path'), '').split('/').filter(Boolean); - if (type !== 'post') { - throw new Error('[[error:activitypub.invalid-id]]'); - } - - return value; + const [slug] = input.replace(/^acct:/, '').split('@'); + const uid = await user.getUidByUserslug(slug); + return { type: 'user', id: uid }; } throw new Error('[[error:activitypub.invalid-id]]'); diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index a4928a1caa..c2d1d60247 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -5,6 +5,7 @@ const winston = require('winston'); const db = require('../database'); const user = require('../user'); const posts = require('../posts'); +const categories = require('../categories'); const activitypub = require('.'); const helpers = require('./helpers'); @@ -56,16 +57,19 @@ inbox.update = async (req) => { inbox.like = async (req) => { const { actor, object } = req.body; - const pid = await activitypub.helpers.resolveLocalPid(object); + const { type, id } = await activitypub.helpers.resolveLocalId(object); + if (type !== 'post' || await posts.exists(id)) { + throw new Error('[[error:activitypub.invalid-id]]'); + } - await posts.upvote(pid, actor); + await posts.upvote(id, actor); }; inbox.follow = async (req) => { // Sanity checks - const localUid = await helpers.resolveLocalUid(req.body.object); - if (!localUid) { - throw new Error('[[error:invalid-uid]]'); + const { type, id } = await helpers.resolveLocalId(req.body.object); + if (!['category', 'user'].includes(type)) { + throw new Error('[[error:activitypub.invalid-id]]'); } const assertion = await activitypub.actors.assert(req.body.actor); @@ -73,24 +77,53 @@ inbox.follow = async (req) => { throw new Error('[[error:activitypub.invalid-id]]'); } - const isFollowed = await inbox.isFollowed(req.body.actor, localUid); - if (isFollowed) { - // No additional parsing required - return; + if (type === 'user') { + const exists = await user.exists(id); + if (!exists) { + throw new Error('[[error:invalid-uid]]'); + } + + const isFollowed = await inbox.isFollowed(req.body.actor, id); + if (isFollowed) { + // No additional parsing required + return; + } + + const now = Date.now(); + await db.sortedSetAdd(`followersRemote:${id}`, now, req.body.actor); + + const followerRemoteCount = await db.sortedSetCard(`followersRemote:${id}`); + await user.setUserField(id, 'followerRemoteCount', followerRemoteCount); + + await activitypub.send('uid', id, req.body.actor, { + type: 'Accept', + object: { + type: 'Follow', + actor: req.body.actor, + }, + }); + } else if (type === 'category') { + const exists = await categories.exists(id); + if (!exists) { + throw new Error('[[error:invalid-cid]]'); + } + + const watchState = await categories.getWatchState([id], req.body.actor); + if (watchState === categories.watchStates.tracking) { + // No additional parsing required + return; + } + + await user.setCategoryWatchState(req.body.actor, id, categories.watchStates.tracking); + + await activitypub.send('cid', id, req.body.actor, { + type: 'Accept', + object: { + type: 'Follow', + actor: req.body.actor, + }, + }); } - - const now = Date.now(); - await db.sortedSetAdd(`followersRemote:${localUid}`, now, req.body.actor); - await activitypub.send(localUid, req.body.actor, { - type: 'Accept', - object: { - type: 'Follow', - actor: req.body.actor, - }, - }); - - const followerRemoteCount = await db.sortedSetCard(`followersRemote:${localUid}`); - await user.setUserField(localUid, 'followerRemoteCount', followerRemoteCount); }; inbox.isFollowed = async (actorId, uid) => { @@ -104,8 +137,8 @@ inbox.accept = async (req) => { const { actor, object } = req.body; const { type } = object; - const uid = await helpers.resolveLocalUid(object.actor); - if (!uid) { + const { type: localType, id: uid } = await helpers.resolveLocalId(object.actor); + if (localType !== 'user' || !uid) { throw new Error('[[error:invalid-uid]]'); } @@ -124,6 +157,7 @@ inbox.accept = async (req) => { }; inbox.undo = async (req) => { + // todo: "actor" in this case should be the one in object, no? const { actor, object } = req.body; const { type } = object; @@ -132,23 +166,45 @@ inbox.undo = async (req) => { throw new Error('[[error:activitypub.invalid-id]]'); } + const { type: localType, id } = await helpers.resolveLocalId(object.object); + switch (type) { case 'Follow': { - const uid = await helpers.resolveLocalUid(object.object); - if (!uid) { - throw new Error('[[error:invalid-uid]]'); + switch (localType) { + case 'user': { + const exists = await user.exists(id); + if (!exists) { + throw new Error('[[error:invalid-uid]]'); + } + + await Promise.all([ + db.sortedSetRemove(`followersRemote:${id}`, actor), + db.decrObjectField(`user:${id}`, 'followerRemoteCount'), + ]); + break; + } + + case 'category': { + const exists = await categories.exists(id); + if (!exists) { + throw new Error('[[error:invalid-cid]]'); + } + + await user.setCategoryWatchState(actor, id, categories.watchStates.notwatching); + break; + } } - await Promise.all([ - db.sortedSetRemove(`followersRemote:${uid}`, actor), - db.decrObjectField(`user:${uid}`, 'followerRemoteCount'), - ]); break; } case 'Like': { - const pid = await helpers.resolveLocalPid(object.object); - await posts.unvote(pid, actor); + const exists = await posts.exists(id); + if (localType !== 'post' || !exists) { + throw new Error('[[error:invalid-pid]]'); + } + + await posts.unvote(id, actor); break; } } diff --git a/src/activitypub/index.js b/src/activitypub/index.js index 4957217f72..63ec8eca49 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -37,28 +37,40 @@ ActivityPub.resolveInboxes = async (ids) => { return Array.from(inboxes); }; -ActivityPub.getPublicKey = async (uid) => { +ActivityPub.getPublicKey = async (type, id) => { let publicKey; try { - ({ publicKey } = await db.getObject(`uid:${uid}:keys`)); + ({ publicKey } = await db.getObject(`uid:${id}:keys`)); } catch (e) { - ({ publicKey } = await ActivityPub.helpers.generateKeys(uid)); + ({ publicKey } = await ActivityPub.helpers.generateKeys(type, id)); } return publicKey; }; -ActivityPub.getPrivateKey = async (uid) => { +ActivityPub.getPrivateKey = async (type, id) => { + // Sanity checking + if (!['cid', 'uid'].includes(type) || !utils.isNumber(id) || parseInt(id, 10) < 0) { + throw new Error('[[error:invalid-data]]'); + } + id = parseInt(id, 10); let privateKey; try { - ({ privateKey } = await db.getObject(`uid:${uid}:keys`)); + ({ privateKey } = await db.getObject(`${type}:${id}:keys`)); } catch (e) { - ({ privateKey } = await ActivityPub.helpers.generateKeys(uid)); + ({ privateKey } = await ActivityPub.helpers.generateKeys(type, id)); } - return privateKey; + let keyId; + if (type === 'uid') { + keyId = `${nconf.get('url')}${id > 0 ? `/uid/${id}` : '/actor'}#key`; + } else { + keyId = `${nconf.get('url')}/category/${id}#key`; + } + + return { key: privateKey, keyId }; }; ActivityPub.fetchPublicKey = async (uri) => { @@ -76,18 +88,10 @@ ActivityPub.fetchPublicKey = async (uri) => { return body.publicKey; }; -ActivityPub.sign = async (uid, url, payload) => { - // Sanity checking - if (!utils.isNumber(uid) || parseInt(uid, 10) < 0) { - throw new Error('[[error:invalid-uid]]'); - } - uid = parseInt(uid, 10); - +ActivityPub.sign = async ({ key, keyId }, url, payload) => { // Returns string for use in 'Signature' header const { host, pathname } = new URL(url); const date = new Date().toUTCString(); - const key = await ActivityPub.getPrivateKey(uid); - const keyId = `${nconf.get('url')}${uid > 0 ? `/uid/${uid}` : '/actor'}#key`; let digest = null; let headers = '(request-target) host date'; @@ -156,13 +160,14 @@ ActivityPub.verify = async (req) => { } }; -ActivityPub.get = async (uid, uri) => { - const cacheKey = [uid, uri].join(';'); +ActivityPub.get = async (type, id, uri) => { + const cacheKey = [id, uri].join(';'); if (requestCache.has(cacheKey)) { return requestCache.get(cacheKey); } - const headers = uid >= 0 ? await ActivityPub.sign(uid, uri) : {}; + const keyData = await ActivityPub.getPrivateKey(type, id); + const headers = id >= 0 ? await ActivityPub.sign(keyData, uri) : {}; winston.verbose(`[activitypub/get] ${uri}`); const { response, body } = await request.get(uri, { headers: { @@ -184,7 +189,7 @@ ActivityPub.get = async (uid, uri) => { return body; }; -ActivityPub.send = async (uid, targets, payload) => { +ActivityPub.send = async (type, id, targets, payload) => { if (!Array.isArray(targets)) { targets = [targets]; } @@ -193,12 +198,14 @@ ActivityPub.send = async (uid, targets, payload) => { payload = { '@context': 'https://www.w3.org/ns/activitystreams', - actor: `${nconf.get('url')}/uid/${uid}`, + actor: `${nconf.get('url')}/uid/${id}`, ...payload, }; await Promise.all(inboxes.map(async (uri) => { - const headers = await ActivityPub.sign(uid, uri, payload); + const keyData = await ActivityPub.getPrivateKey(type, id); + const headers = await ActivityPub.sign(keyData, uri, payload); + winston.verbose(`[activitypub/send] ${uri}`); const { response } = await request.post(uri, { headers: { ...headers, diff --git a/src/activitypub/mocks.js b/src/activitypub/mocks.js index 04c6c2aefc..1e4e017f10 100644 --- a/src/activitypub/mocks.js +++ b/src/activitypub/mocks.js @@ -118,7 +118,7 @@ Mocks.actors = {}; Mocks.actors.user = async (uid) => { let { username, userslug, displayname: name, aboutme, picture, 'cover:url': cover } = await user.getUserData(uid); - const publicKey = await activitypub.getPublicKey(uid); + const publicKey = await activitypub.getPublicKey('uid', uid); if (picture) { const imagePath = await user.getLocalAvatarPath(uid); diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 75735cbde1..f49cb5113a 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -12,7 +12,7 @@ const activitypub = module.parent.exports; const Notes = module.exports; Notes.resolveId = async (uid, id) => { - ({ id } = await activitypub.get(uid, id)); + ({ id } = await activitypub.get('uid', uid, id)); return id; }; @@ -30,7 +30,7 @@ Notes.assert = async (uid, input, options = {}) => { let postData; winston.verbose(`[activitypub/notes.assert] Not found, saving note to database`); if (activitypub.helpers.isUri(item)) { - const object = await activitypub.get(uid, item); + const object = await activitypub.get('uid', uid, item); postData = await activitypub.mocks.post(object); } else { postData = item; @@ -60,7 +60,7 @@ Notes.getParentChain = async (uid, input) => { await traverse(uid, postData.toPid); } } else { - let object = await activitypub.get(uid, id); + let object = await activitypub.get('uid', uid, id); object = await activitypub.mocks.post(object); if (object) { chain.add(object); diff --git a/src/api/activitypub.js b/src/api/activitypub.js index 2152a75444..857e0a0184 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -22,7 +22,7 @@ activitypubApi.follow = async (caller, { uid } = {}) => { throw new Error('[[error:activitypub.invalid-id]]'); } - await activitypub.send(caller.uid, [result.actorUri], { + await activitypub.send('uid', caller.uid, [result.actorUri], { type: 'Follow', object: result.actorUri, }); @@ -35,7 +35,7 @@ activitypubApi.unfollow = async (caller, { uid }) => { throw new Error('[[error:activitypub.invalid-id]]'); } - await activitypub.send(caller.uid, [result.actorUri], { + await activitypub.send('uid', caller.uid, [result.actorUri], { type: 'Undo', object: { type: 'Follow', @@ -81,7 +81,7 @@ activitypubApi.create.post = async (caller, { pid }) => { object, }; - await activitypub.send(caller.uid, Array.from(targets), payload); + await activitypub.send('uid', caller.uid, Array.from(targets), payload); }; activitypubApi.update = {}; @@ -92,7 +92,7 @@ activitypubApi.update.profile = async (caller, { uid }) => { db.getSortedSetMembers(`followersRemote:${caller.uid}`), ]); - await activitypub.send(caller.uid, followers, { + await activitypub.send('uid', caller.uid, followers, { type: 'Update', to: [activitypub._constants.publicAddress], cc: [], @@ -111,7 +111,7 @@ activitypubApi.update.note = async (caller, { post }) => { object, }; - await activitypub.send(caller.uid, Array.from(targets), payload); + await activitypub.send('uid', caller.uid, Array.from(targets), payload); }; activitypubApi.like = {}; @@ -126,7 +126,7 @@ activitypubApi.like.note = async (caller, { pid }) => { return; } - await activitypub.send(caller.uid, [uid], { + await activitypub.send('uid', caller.uid, [uid], { type: 'Like', object: pid, }); @@ -146,7 +146,7 @@ activitypubApi.undo.like = async (caller, { pid }) => { return; } - await activitypub.send(caller.uid, [uid], { + await activitypub.send('uid', caller.uid, [uid], { type: 'Undo', object: { actor: `${nconf.get('url')}/uid/${caller.uid}`, diff --git a/src/categories/watch.js b/src/categories/watch.js index f80d0bf15d..4f53ea01e5 100644 --- a/src/categories/watch.js +++ b/src/categories/watch.js @@ -2,6 +2,7 @@ const db = require('../database'); const user = require('../user'); +const activitypub = require('../activitypub'); module.exports = function (Categories) { Categories.watchStates = { @@ -20,7 +21,7 @@ module.exports = function (Categories) { }; Categories.getWatchState = async function (cids, uid) { - if (!(parseInt(uid, 10) > 0)) { + if (!activitypub.helpers.isUri(uid) && !(parseInt(uid, 10) > 0)) { return cids.map(() => Categories.watchStates.notwatching); } if (!Array.isArray(cids) || !cids.length) { diff --git a/src/controllers/activitypub/actors.js b/src/controllers/activitypub/actors.js index adf7758157..b14b46c380 100644 --- a/src/controllers/activitypub/actors.js +++ b/src/controllers/activitypub/actors.js @@ -10,7 +10,7 @@ const activitypub = require('../../activitypub'); const Actors = module.exports; Actors.application = async function (req, res) { - const publicKey = await activitypub.getPublicKey(0); + const publicKey = await activitypub.getPublicKey('uid', 0); const name = meta.config.title || 'NodeBB'; res.status(200).json({ diff --git a/src/user/categories.js b/src/user/categories.js index 1bae181ef5..137cf595e3 100644 --- a/src/user/categories.js +++ b/src/user/categories.js @@ -4,11 +4,12 @@ const _ = require('lodash'); const db = require('../database'); const categories = require('../categories'); +const activitypub = require('../activitypub'); const plugins = require('../plugins'); module.exports = function (User) { User.setCategoryWatchState = async function (uid, cids, state) { - if (!(parseInt(uid, 10) > 0)) { + if (!activitypub.helpers.isUri(uid) && !(parseInt(uid, 10) > 0)) { return; } const isStateValid = Object.values(categories.watchStates).includes(parseInt(state, 10)); diff --git a/src/user/settings.js b/src/user/settings.js index 9d8c92fdc3..27d999b7cf 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -5,6 +5,7 @@ const validator = require('validator'); const meta = require('../meta'); const db = require('../database'); +const activitypub = require('../activitypub'); const plugins = require('../plugins'); const notifications = require('../notifications'); const languages = require('../languages'); @@ -16,6 +17,10 @@ module.exports = function (User) { postsPerPage: 20, topicsPerPage: 20, }; + const remoteDefaultSettings = Object.freeze({ + categoryWatchState: 'notwatching', + }); + User.getSettings = async function (uid) { if (parseInt(uid, 10) <= 0) { const isSpider = parseInt(uid, 10) === -1; @@ -90,6 +95,8 @@ module.exports = function (User) { function getSetting(settings, key, defaultValue) { if (settings[key] || settings[key] === 0) { return settings[key]; + } else if (activitypub.helpers.isUri(settings.uid) && remoteDefaultSettings[key]) { + return remoteDefaultSettings[key]; } else if (meta.config[key] || meta.config[key] === 0) { return meta.config[key]; } diff --git a/test/activitypub.js b/test/activitypub.js index a2af8bf50e..d065563cc9 100644 --- a/test/activitypub.js +++ b/test/activitypub.js @@ -88,7 +88,7 @@ describe('ActivityPub integration', () => { }); - describe('.resolveLocalUid()', () => { + describe('.resolveLocalId()', () => { let uid; let slug; @@ -99,29 +99,29 @@ describe('ActivityPub integration', () => { it('should throw when an invalid input is passed in', async () => { await assert.rejects( - activitypub.helpers.resolveLocalUid('ncl28h3qwhoiclwnevoinw3u'), + activitypub.helpers.resolveLocalId('ncl28h3qwhoiclwnevoinw3u'), { message: '[[error:activitypub.invalid-id]]' } ); }); it('should return null when valid input is passed but does not resolve', async () => { - const uid = await activitypub.helpers.resolveLocalUid(`acct:foobar@${nconf.get('url_parsed').host}`); - assert.strictEqual(uid, null); + const { id } = await activitypub.helpers.resolveLocalId(`acct:foobar@${nconf.get('url_parsed').host}`); + assert.strictEqual(id, null); }); it('should resolve to a local uid when given a webfinger-style string', async () => { - const found = await activitypub.helpers.resolveLocalUid(`acct:${slug}@${nconf.get('url_parsed').host}`); - assert.strictEqual(found, uid); + const { id } = await activitypub.helpers.resolveLocalId(`acct:${slug}@${nconf.get('url_parsed').host}`); + assert.strictEqual(id, uid); }); it('should resolve even without the "acct:" prefix', async () => { - const found = await activitypub.helpers.resolveLocalUid(`${slug}@${nconf.get('url_parsed').host}`); - assert.strictEqual(found, uid); + const { id } = await activitypub.helpers.resolveLocalId(`${slug}@${nconf.get('url_parsed').host}`); + assert.strictEqual(id, uid); }); it('should resolve when passed a full URL', async () => { - const found = await activitypub.helpers.resolveLocalUid(`${nconf.get('url')}/user/${slug}`); - assert.strictEqual(found, uid); + const { id } = await activitypub.helpers.resolveLocalId(`${nconf.get('url')}/user/${slug}`); + assert.strictEqual(id, uid); }); }); }); @@ -274,7 +274,8 @@ describe('ActivityPub integration', () => { it('should create a key-pair for a user if the user does not have one already', async () => { const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`; - await activitypub.sign(uid, endpoint); + const keyData = await activitypub.getPrivateKey('uid', uid); + await activitypub.sign(keyData, endpoint); const { publicKey, privateKey } = await db.getObject(`uid:${uid}:keys`); assert(publicKey); @@ -283,7 +284,8 @@ describe('ActivityPub integration', () => { it('should return an object with date, a null digest, and signature, if no payload is passed in', async () => { const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`; - const { date, digest, signature } = await activitypub.sign(uid, endpoint); + const keyData = await activitypub.getPrivateKey('uid', uid); + const { date, digest, signature } = await activitypub.sign(keyData, endpoint); const dateObj = new Date(date); assert(signature); @@ -294,7 +296,8 @@ describe('ActivityPub integration', () => { it('should also return a digest hash if payload is passed in', async () => { const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`; const payload = { foo: 'bar' }; - const { digest } = await activitypub.sign(uid, endpoint, payload); + const keyData = await activitypub.getPrivateKey('uid', uid); + const { digest } = await activitypub.sign(keyData, endpoint, payload); const hash = createHash('sha256'); hash.update(JSON.stringify(payload)); const checksum = hash.digest('base64'); @@ -305,7 +308,8 @@ describe('ActivityPub integration', () => { it('should create a key for NodeBB itself if a uid of 0 is passed in', async () => { const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`; - await activitypub.sign(0, endpoint); + const keyData = await activitypub.getPrivateKey('uid', 0); + await activitypub.sign(keyData, endpoint); const { publicKey, privateKey } = await db.getObject(`uid:0:keys`); assert(publicKey); @@ -314,7 +318,8 @@ describe('ActivityPub integration', () => { it('should return headers with an appropriate key id uri', async () => { const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`; - const { signature } = await activitypub.sign(uid, endpoint); + const keyData = await activitypub.getPrivateKey('uid', uid); + const { signature } = await activitypub.sign(keyData, endpoint); const [keyId] = signature.split(','); assert(signature); @@ -323,7 +328,8 @@ describe('ActivityPub integration', () => { it('should return the instance key id when uid is 0', async () => { const endpoint = `${nconf.get('url')}/uid/${uid}/inbox`; - const { signature } = await activitypub.sign(0, endpoint); + const keyData = await activitypub.getPrivateKey('uid', 0); + const { signature } = await activitypub.sign(keyData, endpoint); const [keyId] = signature.split(','); assert(signature); @@ -355,7 +361,8 @@ describe('ActivityPub integration', () => { it('should return true when the proper signature and relevant headers are passed in', async () => { const endpoint = `${nconf.get('url')}/user/${username}/inbox`; const path = `/user/${username}/inbox`; - const signature = await activitypub.sign(uid, endpoint); + const keyData = await activitypub.getPrivateKey('uid', uid); + const signature = await activitypub.sign(keyData, endpoint); const { host } = nconf.get('url_parsed'); const req = { ...mockReqBase, @@ -372,7 +379,8 @@ describe('ActivityPub integration', () => { it('should return true when a digest is also passed in', async () => { const endpoint = `${nconf.get('url')}/user/${username}/inbox`; const path = `/user/${username}/inbox`; - const signature = await activitypub.sign(uid, endpoint, { foo: 'bar' }); + const keyData = await activitypub.getPrivateKey('uid', uid); + const signature = await activitypub.sign(keyData, endpoint, { foo: 'bar' }); const { host } = nconf.get('url_parsed'); const req = { ...mockReqBase, @@ -412,7 +420,7 @@ describe('ActivityPub integration', () => { const post = (await posts.getPostSummaryByPids([postData.pid], uid, { stripTags: false })).pop(); note = await activitypub.mocks.note(post); - await activitypub.send(uid, [`${nconf.get('url')}/uid/${uid}`], { + await activitypub.send('uid', uid, [`${nconf.get('url')}/uid/${uid}`], { type: 'Create', object: note, });