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) => { | ||||
| 	// 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); | ||||
| 	if (!localUid) { | ||||
| 		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); | ||||
| 	if (isFollowed) { | ||||
| 		// No additional parsing required | ||||
| @@ -51,15 +51,14 @@ inbox.accept = async (req) => { | ||||
| 	let { actor, object } = req.body; | ||||
| 	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') { | ||||
| 		// 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.id), | ||||
| @@ -72,15 +71,14 @@ inbox.undo = async (req) => { | ||||
| 	let { actor, object } = req.body; | ||||
| 	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') { | ||||
| 		// 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([ | ||||
| 			db.sortedSetRemove(`followingRemote:${uid}`, actor.id), | ||||
| 			db.decrObjectField(`user:${uid}`, 'followingRemoteCount'), | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const nconf = require('nconf'); | ||||
| const winston = require('winston'); | ||||
| const { createHash, createSign, createVerify } = require('crypto'); | ||||
|  | ||||
| const request = require('../request'); | ||||
| @@ -14,7 +15,7 @@ const ActivityPub = module.exports; | ||||
| ActivityPub.helpers = require('./helpers'); | ||||
| ActivityPub.inbox = require('./inbox'); | ||||
|  | ||||
| ActivityPub.getActor = async (input) => { | ||||
| ActivityPub.getActor = async (uid, input) => { | ||||
| 	// Can be a webfinger id, uri, or object, handle as appropriate | ||||
| 	let uri; | ||||
| 	if (ActivityPub.helpers.isUri(input)) { | ||||
| @@ -33,7 +34,7 @@ ActivityPub.getActor = async (input) => { | ||||
| 		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 | ||||
| 	if (typeof actor === 'string' || actor.hasOwnProperty('error')) { | ||||
| @@ -41,8 +42,8 @@ ActivityPub.getActor = async (input) => { | ||||
| 	} | ||||
|  | ||||
| 	const [followers, following] = await Promise.all([ | ||||
| 		actor.followers ? ActivityPub.get(actor.followers) : { totalItems: 0 }, | ||||
| 		actor.following ? ActivityPub.get(actor.following) : { totalItems: 0 }, | ||||
| 		actor.followers ? ActivityPub.get(uid, actor.followers) : { totalItems: 0 }, | ||||
| 		actor.following ? ActivityPub.get(uid, actor.following) : { totalItems: 0 }, | ||||
| 	]); | ||||
|  | ||||
| 	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) => { | ||||
| 		// convert uri to actor object | ||||
| 		if (typeof actor === 'string' && ActivityPub.helpers.isUri(actor)) { | ||||
| 			actor = await ActivityPub.getActor(actor); | ||||
| 			actor = await ActivityPub.getActor(callerUid, actor); | ||||
| 		} | ||||
|  | ||||
| 		if (!actor) { | ||||
| @@ -111,8 +112,8 @@ ActivityPub.mockProfile = async (actors, callerUid = 0) => { | ||||
| 	return single ? profiles.pop() : profiles; | ||||
| }; | ||||
|  | ||||
| ActivityPub.resolveInboxes = async ids => await Promise.all(ids.map(async (id) => { | ||||
| 	const actor = await ActivityPub.getActor(id); | ||||
| ActivityPub.resolveInboxes = async (uid, ids) => await Promise.all(ids.map(async (id) => { | ||||
| 	const actor = await ActivityPub.getActor(uid, id); | ||||
| 	return actor.inbox; | ||||
| })); | ||||
|  | ||||
| @@ -222,13 +223,22 @@ ActivityPub.verify = async (req) => { | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| ActivityPub.get = async (uri) => { | ||||
| 	const { body } = await request.get(uri, { | ||||
| ActivityPub.get = async (uid, uri) => { | ||||
| 	const headers = uid > 0 ? await ActivityPub.sign(uid, uri) : {}; | ||||
| 	const { response, body } = await request.get(uri, { | ||||
| 		headers: { | ||||
| 			...headers, | ||||
| 			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; | ||||
| }; | ||||
|  | ||||
| @@ -238,7 +248,7 @@ ActivityPub.send = async (uid, targets, payload) => { | ||||
| 	} | ||||
|  | ||||
| 	const userslug = await user.getUserField(uid, 'userslug'); | ||||
| 	const inboxes = await ActivityPub.resolveInboxes(targets); | ||||
| 	const inboxes = await ActivityPub.resolveInboxes(uid, targets); | ||||
|  | ||||
| 	payload = { | ||||
| 		'@context': 'https://www.w3.org/ns/activitystreams', | ||||
|   | ||||
| @@ -17,7 +17,7 @@ const user = require('../user'); | ||||
| const activitypubApi = module.exports; | ||||
|  | ||||
| activitypubApi.follow = async (caller, { actorId } = {}) => { | ||||
| 	const object = await activitypub.getActor(actorId); | ||||
| 	const object = await activitypub.getActor(caller.uid, actorId); | ||||
| 	if (!object) { | ||||
| 		throw new Error('[[error:invalid-uid]]'); // should be activitypub-specific | ||||
| 	} | ||||
| @@ -29,7 +29,7 @@ activitypubApi.follow = 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'); | ||||
| 	if (!object) { | ||||
| 		throw new Error('[[error:invalid-uid]]'); // should be activitypub-specific | ||||
|   | ||||
		Reference in New Issue
	
	Block a user