mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-31 19:15:58 +01:00
refactor: update ActivityPub.get and all methods calling it to take a uid so that requests can be signed
This commit is contained in:
@@ -10,16 +10,16 @@ const inbox = module.exports;
|
|||||||
|
|
||||||
inbox.follow = async (req) => {
|
inbox.follow = async (req) => {
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
const from = await activitypub.getActor(req.body.actor);
|
|
||||||
if (!from) {
|
|
||||||
throw new Error('[[error:invalid-uid]]'); // should probably be AP specific
|
|
||||||
}
|
|
||||||
|
|
||||||
const localUid = await helpers.resolveLocalUid(req.body.object);
|
const localUid = await helpers.resolveLocalUid(req.body.object);
|
||||||
if (!localUid) {
|
if (!localUid) {
|
||||||
throw new Error('[[error:invalid-uid]]');
|
throw new Error('[[error:invalid-uid]]');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const from = await activitypub.getActor(localUid, req.body.actor);
|
||||||
|
if (!from) {
|
||||||
|
throw new Error('[[error:invalid-uid]]'); // should probably be AP specific
|
||||||
|
}
|
||||||
|
|
||||||
const isFollowed = await inbox.isFollowed(from.id, localUid);
|
const isFollowed = await inbox.isFollowed(from.id, localUid);
|
||||||
if (isFollowed) {
|
if (isFollowed) {
|
||||||
// No additional parsing required
|
// No additional parsing required
|
||||||
@@ -51,15 +51,14 @@ inbox.accept = async (req) => {
|
|||||||
let { actor, object } = req.body;
|
let { actor, object } = req.body;
|
||||||
const { type } = object;
|
const { type } = object;
|
||||||
|
|
||||||
actor = await activitypub.getActor(actor);
|
const uid = await helpers.resolveLocalUid(object.actor);
|
||||||
|
if (!uid) {
|
||||||
|
throw new Error('[[error:invalid-uid]]');
|
||||||
|
}
|
||||||
|
|
||||||
|
actor = await activitypub.getActor(uid, actor);
|
||||||
|
|
||||||
if (type === 'Follow') {
|
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();
|
const now = Date.now();
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.sortedSetAdd(`followingRemote:${uid}`, now, actor.id),
|
db.sortedSetAdd(`followingRemote:${uid}`, now, actor.id),
|
||||||
@@ -72,15 +71,14 @@ inbox.undo = async (req) => {
|
|||||||
let { actor, object } = req.body;
|
let { actor, object } = req.body;
|
||||||
const { type } = object;
|
const { type } = object;
|
||||||
|
|
||||||
actor = await activitypub.getActor(actor);
|
const uid = await helpers.resolveLocalUid(object.object);
|
||||||
|
if (!uid) {
|
||||||
|
throw new Error('[[error:invalid-uid]]');
|
||||||
|
}
|
||||||
|
|
||||||
|
actor = await activitypub.getActor(uid, actor);
|
||||||
|
|
||||||
if (type === 'Follow') {
|
if (type === 'Follow') {
|
||||||
// todo: should check that actor and object.actor are the same person?
|
|
||||||
const uid = await helpers.resolveLocalUid(object.object);
|
|
||||||
if (!uid) {
|
|
||||||
throw new Error('[[error:invalid-uid]]');
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.sortedSetRemove(`followingRemote:${uid}`, actor.id),
|
db.sortedSetRemove(`followingRemote:${uid}`, actor.id),
|
||||||
db.decrObjectField(`user:${uid}`, 'followingRemoteCount'),
|
db.decrObjectField(`user:${uid}`, 'followingRemoteCount'),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const nconf = require('nconf');
|
const nconf = require('nconf');
|
||||||
|
const winston = require('winston');
|
||||||
const { createHash, createSign, createVerify } = require('crypto');
|
const { createHash, createSign, createVerify } = require('crypto');
|
||||||
|
|
||||||
const request = require('../request');
|
const request = require('../request');
|
||||||
@@ -14,7 +15,7 @@ const ActivityPub = module.exports;
|
|||||||
ActivityPub.helpers = require('./helpers');
|
ActivityPub.helpers = require('./helpers');
|
||||||
ActivityPub.inbox = require('./inbox');
|
ActivityPub.inbox = require('./inbox');
|
||||||
|
|
||||||
ActivityPub.getActor = async (input) => {
|
ActivityPub.getActor = async (uid, input) => {
|
||||||
// Can be a webfinger id, uri, or object, handle as appropriate
|
// Can be a webfinger id, uri, or object, handle as appropriate
|
||||||
let uri;
|
let uri;
|
||||||
if (ActivityPub.helpers.isUri(input)) {
|
if (ActivityPub.helpers.isUri(input)) {
|
||||||
@@ -33,7 +34,7 @@ ActivityPub.getActor = async (input) => {
|
|||||||
return actorCache.get(uri);
|
return actorCache.get(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
const actor = await ActivityPub.get(uri);
|
const actor = await ActivityPub.get(uid, uri);
|
||||||
|
|
||||||
// todo: remove this after ActivityPub.get is updated to handle errors more effectively
|
// todo: remove this after ActivityPub.get is updated to handle errors more effectively
|
||||||
if (typeof actor === 'string' || actor.hasOwnProperty('error')) {
|
if (typeof actor === 'string' || actor.hasOwnProperty('error')) {
|
||||||
@@ -41,8 +42,8 @@ ActivityPub.getActor = async (input) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [followers, following] = await Promise.all([
|
const [followers, following] = await Promise.all([
|
||||||
actor.followers ? ActivityPub.get(actor.followers) : { totalItems: 0 },
|
actor.followers ? ActivityPub.get(uid, actor.followers) : { totalItems: 0 },
|
||||||
actor.following ? ActivityPub.get(actor.following) : { totalItems: 0 },
|
actor.following ? ActivityPub.get(uid, actor.following) : { totalItems: 0 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
actor.hostname = new URL(uri).hostname;
|
actor.hostname = new URL(uri).hostname;
|
||||||
@@ -64,7 +65,7 @@ ActivityPub.mockProfile = async (actors, callerUid = 0) => {
|
|||||||
const profiles = (await Promise.all(actors.map(async (actor) => {
|
const profiles = (await Promise.all(actors.map(async (actor) => {
|
||||||
// convert uri to actor object
|
// convert uri to actor object
|
||||||
if (typeof actor === 'string' && ActivityPub.helpers.isUri(actor)) {
|
if (typeof actor === 'string' && ActivityPub.helpers.isUri(actor)) {
|
||||||
actor = await ActivityPub.getActor(actor);
|
actor = await ActivityPub.getActor(callerUid, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!actor) {
|
if (!actor) {
|
||||||
@@ -111,8 +112,8 @@ ActivityPub.mockProfile = async (actors, callerUid = 0) => {
|
|||||||
return single ? profiles.pop() : profiles;
|
return single ? profiles.pop() : profiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
ActivityPub.resolveInboxes = async ids => await Promise.all(ids.map(async (id) => {
|
ActivityPub.resolveInboxes = async (uid, ids) => await Promise.all(ids.map(async (id) => {
|
||||||
const actor = await ActivityPub.getActor(id);
|
const actor = await ActivityPub.getActor(uid, id);
|
||||||
return actor.inbox;
|
return actor.inbox;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -222,13 +223,22 @@ ActivityPub.verify = async (req) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ActivityPub.get = async (uri) => {
|
ActivityPub.get = async (uid, uri) => {
|
||||||
const { body } = await request.get(uri, {
|
const headers = uid > 0 ? await ActivityPub.sign(uid, uri) : {};
|
||||||
|
const { response, body } = await request.get(uri, {
|
||||||
headers: {
|
headers: {
|
||||||
|
...headers,
|
||||||
Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!String(response.statusCode).startsWith('2')) {
|
||||||
|
winston.error(`[activitypub/get] Received ${response.statusCode} when querying ${uri}`);
|
||||||
|
if (body.hasOwnProperty('error')) {
|
||||||
|
winston.error(`[activitypub/get] Error received: ${body.error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -238,7 +248,7 @@ ActivityPub.send = async (uid, targets, payload) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const userslug = await user.getUserField(uid, 'userslug');
|
const userslug = await user.getUserField(uid, 'userslug');
|
||||||
const inboxes = await ActivityPub.resolveInboxes(targets);
|
const inboxes = await ActivityPub.resolveInboxes(uid, targets);
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const user = require('../user');
|
|||||||
const activitypubApi = module.exports;
|
const activitypubApi = module.exports;
|
||||||
|
|
||||||
activitypubApi.follow = async (caller, { actorId } = {}) => {
|
activitypubApi.follow = async (caller, { actorId } = {}) => {
|
||||||
const object = await activitypub.getActor(actorId);
|
const object = await activitypub.getActor(caller.uid, actorId);
|
||||||
if (!object) {
|
if (!object) {
|
||||||
throw new Error('[[error:invalid-uid]]'); // should be activitypub-specific
|
throw new Error('[[error:invalid-uid]]'); // should be activitypub-specific
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ activitypubApi.follow = async (caller, { actorId } = {}) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
activitypubApi.unfollow = async (caller, { actorId }) => {
|
activitypubApi.unfollow = async (caller, { actorId }) => {
|
||||||
const object = await activitypub.getActor(actorId);
|
const object = await activitypub.getActor(caller.uid, actorId);
|
||||||
const userslug = await user.getUserField(caller.uid, 'userslug');
|
const userslug = await user.getUserField(caller.uid, 'userslug');
|
||||||
if (!object) {
|
if (!object) {
|
||||||
throw new Error('[[error:invalid-uid]]'); // should be activitypub-specific
|
throw new Error('[[error:invalid-uid]]'); // should be activitypub-specific
|
||||||
|
|||||||
Reference in New Issue
Block a user