| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * DEVELOPMENT NOTE | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS FILE IS UNDER ACTIVE DEVELOPMENT AND IS EXPLICITLY EXCLUDED FROM IMMUTABILITY GUARANTEES | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * If you use api methods in this file, be prepared that they may be removed or modified with no warning. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-22 15:53:04 -05:00
										 |  |  | const nconf = require('nconf'); | 
					
						
							| 
									
										
										
										
											2024-06-13 18:36:05 -04:00
										 |  |  | const winston = require('winston'); | 
					
						
							| 
									
										
										
										
											2023-12-22 15:53:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | const db = require('../database'); | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | const user = require('../user'); | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | const meta = require('../meta'); | 
					
						
							|  |  |  | const privileges = require('../privileges'); | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | const activitypub = require('../activitypub'); | 
					
						
							| 
									
										
										
										
											2024-01-24 11:44:10 -05:00
										 |  |  | const posts = require('../posts'); | 
					
						
							| 
									
										
										
										
											2024-05-07 12:43:27 -04:00
										 |  |  | const utils = require('../utils'); | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | const activitypubApi = module.exports; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | function enabledCheck(next) { | 
					
						
							|  |  |  | 	return async function (caller, params) { | 
					
						
							| 
									
										
										
										
											2024-06-06 21:10:24 -04:00
										 |  |  | 		if (meta.config.activitypubEnabled) { | 
					
						
							|  |  |  | 			await next(caller, params); | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | activitypubApi.follow = enabledCheck(async (caller, { type, id, actor } = {}) => { | 
					
						
							|  |  |  | 	// Privilege checks should be done upstream
 | 
					
						
							|  |  |  | 	const assertion = await activitypub.actors.assert(actor); | 
					
						
							|  |  |  | 	if (!assertion) { | 
					
						
							| 
									
										
										
										
											2024-01-08 14:30:09 -05:00
										 |  |  | 		throw new Error('[[error:activitypub.invalid-id]]'); | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | 	actor = actor.includes('@') ? await user.getUidByUserslug(actor) : actor; | 
					
						
							|  |  |  | 	const handle = await user.getUserField(actor, 'username'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	await activitypub.send(type, id, [actor], { | 
					
						
							| 
									
										
										
										
											2024-07-04 17:42:59 -04:00
										 |  |  | 		id: `${nconf.get('url')}/${type}/${id}#activity/follow/${handle}/${Date.now()}`, | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | 		type: 'Follow', | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | 		object: actor, | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2024-04-09 23:58:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | 	await db.sortedSetAdd(`followRequests:${type}.${id}`, Date.now(), actor); | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | // should be .undo.follow
 | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | activitypubApi.unfollow = enabledCheck(async (caller, { type, id, actor }) => { | 
					
						
							|  |  |  | 	const assertion = await activitypub.actors.assert(actor); | 
					
						
							|  |  |  | 	if (!assertion) { | 
					
						
							| 
									
										
										
										
											2024-01-08 14:30:09 -05:00
										 |  |  | 		throw new Error('[[error:activitypub.invalid-id]]'); | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | 	actor = actor.includes('@') ? await user.getUidByUserslug(actor) : actor; | 
					
						
							|  |  |  | 	const handle = await user.getUserField(actor, 'username'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const object = { | 
					
						
							|  |  |  | 		id: `${nconf.get('url')}/${type}/${id}#activity/follow/${handle}`, | 
					
						
							|  |  |  | 		type: 'Follow', | 
					
						
							|  |  |  | 		object: actor, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	if (type === 'uid') { | 
					
						
							|  |  |  | 		object.actor = `${nconf.get('url')}/uid/${id}`; | 
					
						
							|  |  |  | 	} else if (type === 'cid') { | 
					
						
							|  |  |  | 		object.actor = `${nconf.get('url')}/category/${id}`; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	await activitypub.send(type, id, [actor], { | 
					
						
							| 
									
										
										
										
											2024-06-11 22:55:45 +02:00
										 |  |  | 		id: `${nconf.get('url')}/${type}/${id}#activity/undo:follow/${handle}/${Date.now()}`, | 
					
						
							| 
									
										
										
										
											2023-12-22 15:53:04 -05:00
										 |  |  | 		type: 'Undo', | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | 		object, | 
					
						
							| 
									
										
										
										
											2023-12-08 10:55:16 -05:00
										 |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | 	if (type === 'uid') { | 
					
						
							|  |  |  | 		await Promise.all([ | 
					
						
							|  |  |  | 			db.sortedSetRemove(`followingRemote:${id}`, actor), | 
					
						
							|  |  |  | 			db.decrObjectField(`user:${id}`, 'followingRemoteCount'), | 
					
						
							|  |  |  | 		]); | 
					
						
							|  |  |  | 	} else if (type === 'cid') { | 
					
						
							|  |  |  | 		await Promise.all([ | 
					
						
							|  |  |  | 			db.sortedSetRemove(`cid:${id}:following`, actor), | 
					
						
							|  |  |  | 			db.sortedSetRemove(`followRequests:cid.${id}`, actor), | 
					
						
							| 
									
										
										
										
											2024-07-04 17:54:04 -04:00
										 |  |  | 			db.sortedSetRemove(`followersRemote:${actor}`, `cid|${id}`), | 
					
						
							| 
									
										
										
										
											2024-04-15 14:40:26 -04:00
										 |  |  | 		]); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2024-01-24 11:44:10 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | activitypubApi.create = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 15:14:32 -04:00
										 |  |  | async function buildRecipients(object, { pid, uid }) { | 
					
						
							| 
									
										
										
										
											2024-05-10 15:30:45 -04:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * - Builds a list of targets for activitypub.send to consume | 
					
						
							|  |  |  | 	 * - Extends to and cc since the activity can be addressed more widely | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | 	const followers = await db.getSortedSetMembers(`followersRemote:${uid}`); | 
					
						
							| 
									
										
										
										
											2024-03-09 21:09:50 -05:00
										 |  |  | 	let { to, cc } = object; | 
					
						
							|  |  |  | 	to = new Set(to); | 
					
						
							|  |  |  | 	cc = new Set(cc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const targets = new Set([...followers, ...to, ...cc]); | 
					
						
							| 
									
										
										
										
											2024-05-10 15:30:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Remove any ids that aren't asserted actors
 | 
					
						
							|  |  |  | 	const exists = await db.isSortedSetMembers('usersRemote:lastCrawled', [...targets]); | 
					
						
							|  |  |  | 	Array.from(targets).forEach((uri, idx) => { | 
					
						
							|  |  |  | 		if (!exists[idx]) { | 
					
						
							|  |  |  | 			targets.delete(uri); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2024-03-09 21:09:50 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 15:14:32 -04:00
										 |  |  | 	// Announcers and their followers
 | 
					
						
							|  |  |  | 	if (pid) { | 
					
						
							|  |  |  | 		const announcers = (await activitypub.notes.announce.list({ pid })).map(({ actor }) => actor); | 
					
						
							|  |  |  | 		const announcersFollowers = (await user.getUsersFields(announcers, ['followersUrl'])) | 
					
						
							|  |  |  | 			.filter(o => o.hasOwnProperty('followersUrl')) | 
					
						
							|  |  |  | 			.map(({ followersUrl }) => followersUrl); | 
					
						
							| 
									
										
										
										
											2024-05-07 12:34:07 -04:00
										 |  |  | 		[...announcers].forEach(uri => targets.add(uri)); | 
					
						
							|  |  |  | 		[...announcers, ...announcersFollowers].forEach(uri => cc.add(uri)); | 
					
						
							| 
									
										
										
										
											2024-05-06 15:14:32 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 15:30:45 -04:00
										 |  |  | 	return { | 
					
						
							|  |  |  | 		to: [...to], | 
					
						
							|  |  |  | 		cc: [...cc], | 
					
						
							|  |  |  | 		targets, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 14:32:00 -04:00
										 |  |  | activitypubApi.create.note = enabledCheck(async (caller, { pid }) => { | 
					
						
							| 
									
										
										
										
											2024-01-25 15:35:45 -05:00
										 |  |  | 	const post = (await posts.getPostSummaryByPids([pid], caller.uid, { stripTags: false })).pop(); | 
					
						
							|  |  |  | 	if (!post) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-08 20:45:54 -05:00
										 |  |  | 	const allowed = await privileges.posts.can('topics:read', pid, activitypub._constants.uid); | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | 	if (!allowed) { | 
					
						
							| 
									
										
										
										
											2024-06-07 12:13:28 -04:00
										 |  |  | 		// winston.verbose(`[activitypub/api] Not federating creation of pid ${pid} to the fediverse due to privileges.`);
 | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | 	const object = await activitypub.mocks.note(post); | 
					
						
							| 
									
										
										
										
											2024-05-10 15:30:45 -04:00
										 |  |  | 	const { to, cc, targets } = await buildRecipients(object, { uid: post.user.uid }); | 
					
						
							| 
									
										
										
										
											2024-03-22 14:39:18 -04:00
										 |  |  | 	const { cid } = post.category; | 
					
						
							|  |  |  | 	const followers = await activitypub.notes.getCategoryFollowers(cid); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-14 13:17:13 -04:00
										 |  |  | 	const payload = { | 
					
						
							|  |  |  | 		id: `${object.id}#activity/create/${Date.now()}`, | 
					
						
							|  |  |  | 		type: 'Create', | 
					
						
							|  |  |  | 		to, | 
					
						
							|  |  |  | 		cc, | 
					
						
							|  |  |  | 		object, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	await activitypub.send('uid', caller.uid, Array.from(targets), payload); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (followers.length) { | 
					
						
							| 
									
										
										
										
											2024-06-13 14:35:09 -04:00
										 |  |  | 		setTimeout(() => { // Delay sending to avoid potential race condition
 | 
					
						
							| 
									
										
										
										
											2024-06-14 13:37:46 -04:00
										 |  |  | 			Promise.all([payload, payload.object].map(async (object) => { | 
					
						
							|  |  |  | 				await activitypub.send('cid', cid, followers, { | 
					
						
							| 
									
										
										
										
											2024-06-25 12:19:24 -04:00
										 |  |  | 					id: `${object.object ? object.object.id : object.id}#activity/announce/${Date.now()}`, | 
					
						
							| 
									
										
										
										
											2024-06-14 13:37:46 -04:00
										 |  |  | 					type: 'Announce', | 
					
						
							|  |  |  | 					to: [activitypub._constants.publicAddress], | 
					
						
							|  |  |  | 					cc: [`${nconf.get('url')}/category/${cid}/followers`], | 
					
						
							|  |  |  | 					object, | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			})).catch(err => winston.error(err.stack)); | 
					
						
							| 
									
										
										
										
											2024-06-13 14:35:09 -04:00
										 |  |  | 		}, 5000); | 
					
						
							| 
									
										
										
										
											2024-03-22 15:28:01 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2024-01-24 20:10:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | activitypubApi.update = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | activitypubApi.update.profile = enabledCheck(async (caller, { uid }) => { | 
					
						
							| 
									
										
										
										
											2024-06-25 11:38:13 -04:00
										 |  |  | 	const [object, targets] = await Promise.all([ | 
					
						
							| 
									
										
										
										
											2024-02-02 17:19:59 -05:00
										 |  |  | 		activitypub.mocks.actors.user(uid), | 
					
						
							| 
									
										
										
										
											2024-06-25 11:38:13 -04:00
										 |  |  | 		db.getSortedSetMembers('usersRemote:lastCrawled'), | 
					
						
							| 
									
										
										
										
											2024-01-24 20:10:22 -05:00
										 |  |  | 	]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-25 11:38:13 -04:00
										 |  |  | 	await activitypub.send('uid', caller.uid, targets, { | 
					
						
							|  |  |  | 		id: `${object.id}#activity/update/${Date.now()}`, | 
					
						
							|  |  |  | 		type: 'Update', | 
					
						
							|  |  |  | 		to: [activitypub._constants.publicAddress], | 
					
						
							|  |  |  | 		cc: [], | 
					
						
							|  |  |  | 		object, | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | activitypubApi.update.category = enabledCheck(async (caller, { cid }) => { | 
					
						
							|  |  |  | 	const [object, targets] = await Promise.all([ | 
					
						
							|  |  |  | 		activitypub.mocks.actors.category(cid), | 
					
						
							|  |  |  | 		db.getSortedSetMembers('usersRemote:lastCrawled'), | 
					
						
							|  |  |  | 	]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	await activitypub.send('cid', cid, targets, { | 
					
						
							| 
									
										
										
										
											2024-04-12 16:43:33 +02:00
										 |  |  | 		id: `${object.id}#activity/update/${Date.now()}`, | 
					
						
							| 
									
										
										
										
											2024-01-24 20:10:22 -05:00
										 |  |  | 		type: 'Update', | 
					
						
							|  |  |  | 		to: [activitypub._constants.publicAddress], | 
					
						
							|  |  |  | 		cc: [], | 
					
						
							|  |  |  | 		object, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-06 01:18:46 +02:00
										 |  |  | activitypubApi.update.note = enabledCheck(async (caller, { post }) => { | 
					
						
							| 
									
										
										
										
											2024-05-07 12:43:27 -04:00
										 |  |  | 	// Only applies to local posts
 | 
					
						
							|  |  |  | 	if (!utils.isNumber(post.pid)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | 	const object = await activitypub.mocks.note(post); | 
					
						
							| 
									
										
										
										
											2024-05-10 15:30:45 -04:00
										 |  |  | 	const { to, cc, targets } = await buildRecipients(object, { pid: post.pid, uid: post.user.uid }); | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | 	const allowed = await privileges.posts.can('topics:read', post.pid, activitypub._constants.uid); | 
					
						
							|  |  |  | 	if (!allowed) { | 
					
						
							| 
									
										
										
										
											2024-06-07 12:13:28 -04:00
										 |  |  | 		// winston.verbose(
 | 
					
						
							|  |  |  | 		// `[activitypub/api] Not federating update of pid ${post.pid} to the fediverse due to privileges.`
 | 
					
						
							|  |  |  | 		// );
 | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | 	const payload = { | 
					
						
							| 
									
										
										
										
											2024-05-07 12:37:57 -04:00
										 |  |  | 		id: `${object.id}#activity/update/${post.edited || Date.now()}`, | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | 		type: 'Update', | 
					
						
							| 
									
										
										
										
											2024-05-10 15:30:45 -04:00
										 |  |  | 		to, | 
					
						
							|  |  |  | 		cc, | 
					
						
							| 
									
										
										
										
											2024-01-30 11:25:45 -05:00
										 |  |  | 		object, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-05 16:57:17 -05:00
										 |  |  | 	await activitypub.send('uid', caller.uid, Array.from(targets), payload); | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | activitypubApi.delete = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | activitypubApi.delete.note = enabledCheck(async (caller, { pid }) => { | 
					
						
							|  |  |  | 	// Only applies to local posts
 | 
					
						
							|  |  |  | 	if (!utils.isNumber(pid)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const id = `${nconf.get('url')}/post/${pid}`; | 
					
						
							| 
									
										
										
										
											2024-05-10 15:30:45 -04:00
										 |  |  | 	const post = (await posts.getPostSummaryByPids([pid], caller.uid, { stripTags: false })).pop(); | 
					
						
							|  |  |  | 	const object = await activitypub.mocks.note(post); | 
					
						
							| 
									
										
										
										
											2024-05-10 17:00:27 -04:00
										 |  |  | 	const { to, cc, targets } = await buildRecipients(object, { pid, uid: post.user.uid }); | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	const allowed = await privileges.posts.can('topics:read', pid, activitypub._constants.uid); | 
					
						
							|  |  |  | 	if (!allowed) { | 
					
						
							| 
									
										
										
										
											2024-06-07 12:13:28 -04:00
										 |  |  | 		// winston.verbose(`[activitypub/api] Not federating update of pid ${pid} to the fediverse due to privileges.`);
 | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const payload = { | 
					
						
							|  |  |  | 		id: `${id}#activity/delete/${Date.now()}`, | 
					
						
							|  |  |  | 		type: 'Delete', | 
					
						
							| 
									
										
										
										
											2024-05-10 15:30:45 -04:00
										 |  |  | 		to, | 
					
						
							|  |  |  | 		cc, | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | 		object: id, | 
					
						
							| 
									
										
										
										
											2024-05-10 17:00:27 -04:00
										 |  |  | 		origin: object.context, | 
					
						
							| 
									
										
										
										
											2024-05-09 15:48:58 -04:00
										 |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	await activitypub.send('uid', caller.uid, Array.from(targets), payload); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | activitypubApi.like = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | activitypubApi.like.note = enabledCheck(async (caller, { pid }) => { | 
					
						
							|  |  |  | 	if (!activitypub.helpers.isUri(pid)) { // remote only
 | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const uid = await posts.getPostField(pid, 'uid'); | 
					
						
							|  |  |  | 	if (!activitypub.helpers.isUri(uid)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-05 16:57:17 -05:00
										 |  |  | 	await activitypub.send('uid', caller.uid, [uid], { | 
					
						
							| 
									
										
										
										
											2024-04-22 11:40:31 +02:00
										 |  |  | 		id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`, | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | 		type: 'Like', | 
					
						
							|  |  |  | 		object: pid, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | activitypubApi.undo = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // activitypubApi.undo.follow =
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | activitypubApi.undo.like = enabledCheck(async (caller, { pid }) => { | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | 	if (!activitypub.helpers.isUri(pid)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const uid = await posts.getPostField(pid, 'uid'); | 
					
						
							|  |  |  | 	if (!activitypub.helpers.isUri(uid)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-05 16:57:17 -05:00
										 |  |  | 	await activitypub.send('uid', caller.uid, [uid], { | 
					
						
							| 
									
										
										
										
											2024-06-11 22:55:45 +02:00
										 |  |  | 		id: `${nconf.get('url')}/uid/${caller.uid}#activity/undo:like/${encodeURIComponent(pid)}/${Date.now()}`, | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | 		type: 'Undo', | 
					
						
							|  |  |  | 		object: { | 
					
						
							|  |  |  | 			actor: `${nconf.get('url')}/uid/${caller.uid}`, | 
					
						
							| 
									
										
										
										
											2024-04-22 11:40:31 +02:00
										 |  |  | 			id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`, | 
					
						
							| 
									
										
										
										
											2024-02-01 15:59:29 -05:00
										 |  |  | 			type: 'Like', | 
					
						
							|  |  |  | 			object: pid, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2024-02-26 15:39:09 -05:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2024-04-14 00:51:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | activitypubApi.flag = enabledCheck(async (caller, flag) => { | 
					
						
							|  |  |  | 	if (!activitypub.helpers.isUri(flag.targetId)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	const reportedIds = [flag.targetId]; | 
					
						
							|  |  |  | 	if (flag.type === 'post' && activitypub.helpers.isUri(flag.targetUid)) { | 
					
						
							|  |  |  | 		reportedIds.push(flag.targetUid); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-04-14 01:52:07 +02:00
										 |  |  | 	const reason = flag.reason || | 
					
						
							|  |  |  | 		(flag.reports && flag.reports.filter(report => report.reporter.uid === caller.uid).at(-1).value); | 
					
						
							| 
									
										
										
										
											2024-04-14 00:51:53 +02:00
										 |  |  | 	await activitypub.send('uid', caller.uid, reportedIds, { | 
					
						
							| 
									
										
										
										
											2024-04-14 01:52:07 +02:00
										 |  |  | 		id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/flag/${caller.uid}`, | 
					
						
							| 
									
										
										
										
											2024-04-14 00:51:53 +02:00
										 |  |  | 		type: 'Flag', | 
					
						
							|  |  |  | 		object: reportedIds, | 
					
						
							| 
									
										
										
										
											2024-04-14 01:52:07 +02:00
										 |  |  | 		content: reason, | 
					
						
							| 
									
										
										
										
											2024-04-14 00:51:53 +02:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2024-04-14 01:52:07 +02:00
										 |  |  | 	await db.sortedSetAdd(`flag:${flag.flagId}:remote`, Date.now(), caller.uid); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | activitypubApi.undo.flag = enabledCheck(async (caller, flag) => { | 
					
						
							|  |  |  | 	if (!activitypub.helpers.isUri(flag.targetId)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	const reportedIds = [flag.targetId]; | 
					
						
							|  |  |  | 	if (flag.type === 'post' && activitypub.helpers.isUri(flag.targetUid)) { | 
					
						
							|  |  |  | 		reportedIds.push(flag.targetUid); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	const reason = flag.reason || | 
					
						
							|  |  |  | 		(flag.reports && flag.reports.filter(report => report.reporter.uid === caller.uid).at(-1).value); | 
					
						
							|  |  |  | 	await activitypub.send('uid', caller.uid, reportedIds, { | 
					
						
							| 
									
										
										
										
											2024-06-11 22:55:45 +02:00
										 |  |  | 		id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/undo:flag/${caller.uid}/${Date.now()}`, | 
					
						
							| 
									
										
										
										
											2024-04-14 01:52:07 +02:00
										 |  |  | 		type: 'Undo', | 
					
						
							|  |  |  | 		object: { | 
					
						
							|  |  |  | 			id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/flag/${caller.uid}`, | 
					
						
							|  |  |  | 			actor: `${nconf.get('url')}/uid/${caller.uid}`, | 
					
						
							|  |  |  | 			type: 'Flag', | 
					
						
							|  |  |  | 			object: reportedIds, | 
					
						
							|  |  |  | 			content: reason, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 	await db.sortedSetRemove(`flag:${flag.flagId}:remote`, caller.uid); | 
					
						
							| 
									
										
										
										
											2024-04-14 00:51:53 +02:00
										 |  |  | }); |