fix: add id for activitypub follows (#8689)
* add id for activitypub follows * fix lint * fix: follower must be local, followee must be remote Misskey will only use ActivityPub follow requests for users that are local and are requesting to follow a remote user. This check is to ensure that this endpoint can not be used by other services or instances. * fix: missing import * render block with id * fix comment
This commit is contained in:
		
							parent
							
								
									9954c054a7
								
							
						
					
					
						commit
						32dff28460
					
				
					 5 changed files with 63 additions and 15 deletions
				
			
		|  | @ -1,8 +1,20 @@ | |||
| import config from '@/config/index.js'; | ||||
| import { ILocalUser, IRemoteUser } from '@/models/entities/user.js'; | ||||
| import { Blocking } from '@/models/entities/blocking.js'; | ||||
| 
 | ||||
| export default (blocker: ILocalUser, blockee: IRemoteUser) => ({ | ||||
| 	type: 'Block', | ||||
| 	actor: `${config.url}/users/${blocker.id}`, | ||||
| 	object: blockee.uri, | ||||
| }); | ||||
| /** | ||||
|  * Renders a block into its ActivityPub representation. | ||||
|  * | ||||
|  * @param block The block to be rendered. The blockee relation must be loaded. | ||||
|  */ | ||||
| export function renderBlock(block: Blocking) { | ||||
| 	if (block.blockee?.url == null) { | ||||
| 		throw new Error('renderBlock: missing blockee uri'); | ||||
| 	} | ||||
| 
 | ||||
| 	return { | ||||
| 		type: 'Block', | ||||
| 		id: `${config.url}/blocks/${block.id}`, | ||||
| 		actor: `${config.url}/users/${block.blockerId}`, | ||||
| 		object: block.blockee.uri, | ||||
| 	}; | ||||
| } | ||||
|  |  | |||
|  | @ -4,12 +4,11 @@ import { Users } from '@/models/index.js'; | |||
| 
 | ||||
| export default (follower: { id: User['id']; host: User['host']; uri: User['host'] }, followee: { id: User['id']; host: User['host']; uri: User['host'] }, requestId?: string) => { | ||||
| 	const follow = { | ||||
| 		id: requestId ?? `${config.url}/follows/${follower.id}/${followee.id}`, | ||||
| 		type: 'Follow', | ||||
| 		actor: Users.isLocalUser(follower) ? `${config.url}/users/${follower.id}` : follower.uri, | ||||
| 		object: Users.isLocalUser(followee) ? `${config.url}/users/${followee.id}` : followee.uri, | ||||
| 	} as any; | ||||
| 
 | ||||
| 	if (requestId) follow.id = requestId; | ||||
| 
 | ||||
| 	return follow; | ||||
| }; | ||||
|  |  | |||
|  | @ -15,9 +15,10 @@ import { inbox as processInbox } from '@/queue/index.js'; | |||
| import { isSelfHost } from '@/misc/convert-host.js'; | ||||
| import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js'; | ||||
| import { ILocalUser, User } from '@/models/entities/user.js'; | ||||
| import { In, IsNull } from 'typeorm'; | ||||
| import { In, IsNull, Not } from 'typeorm'; | ||||
| import { renderLike } from '@/remote/activitypub/renderer/like.js'; | ||||
| import { getUserKeypair } from '@/misc/keypair-store.js'; | ||||
| import renderFollow from '@/remote/activitypub/renderer/follow.js'; | ||||
| 
 | ||||
| // Init router
 | ||||
| const router = new Router(); | ||||
|  | @ -224,4 +225,30 @@ router.get('/likes/:like', async ctx => { | |||
| 	setResponseType(ctx); | ||||
| }); | ||||
| 
 | ||||
| // follow
 | ||||
| router.get('/follows/:follower/:followee', async ctx => { | ||||
| 	// This may be used before the follow is completed, so we do not
 | ||||
| 	// check if the following exists.
 | ||||
| 
 | ||||
| 	const [follower, followee] = await Promise.all([ | ||||
| 		Users.findOneBy({ | ||||
| 			id: ctx.params.follower, | ||||
| 			host: IsNull(), | ||||
| 		}), | ||||
| 		Users.findOneBy({ | ||||
| 			id: ctx.params.followee, | ||||
| 			host: Not(IsNull()), | ||||
| 		}), | ||||
| 	]); | ||||
| 
 | ||||
| 	if (follower == null || followee == null) { | ||||
| 		ctx.status = 404; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.body = renderActivity(renderFollow(follower, followee)); | ||||
| 	ctx.set('Cache-Control', 'public, max-age=180'); | ||||
| 	setResponseType(ctx); | ||||
| }); | ||||
| 
 | ||||
| export default router; | ||||
|  |  | |||
|  | @ -2,9 +2,10 @@ import { publishMainStream, publishUserEvent } from '@/services/stream.js'; | |||
| import { renderActivity } from '@/remote/activitypub/renderer/index.js'; | ||||
| import renderFollow from '@/remote/activitypub/renderer/follow.js'; | ||||
| import renderUndo from '@/remote/activitypub/renderer/undo.js'; | ||||
| import renderBlock from '@/remote/activitypub/renderer/block.js'; | ||||
| import { renderBlock } from '@/remote/activitypub/renderer/block.js'; | ||||
| import { deliver } from '@/queue/index.js'; | ||||
| import renderReject from '@/remote/activitypub/renderer/reject.js'; | ||||
| import { Blocking } from '@/models/entities/blocking.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
| import { Blockings, Users, FollowRequests, Followings, UserListJoinings, UserLists } from '@/models/index.js'; | ||||
| import { perUserFollowingChart } from '@/services/chart/index.js'; | ||||
|  | @ -22,15 +23,19 @@ export default async function(blocker: User, blockee: User) { | |||
| 		removeFromList(blockee, blocker), | ||||
| 	]); | ||||
| 
 | ||||
| 	await Blockings.insert({ | ||||
| 	const blocking = { | ||||
| 		id: genId(), | ||||
| 		createdAt: new Date(), | ||||
| 		blocker, | ||||
| 		blockerId: blocker.id, | ||||
| 		blockee, | ||||
| 		blockeeId: blockee.id, | ||||
| 	}); | ||||
| 	} as Blocking; | ||||
| 
 | ||||
| 	await Blockings.insert(blocking); | ||||
| 
 | ||||
| 	if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) { | ||||
| 		const content = renderActivity(renderBlock(blocker, blockee)); | ||||
| 		const content = renderActivity(renderBlock(blocking)); | ||||
| 		deliver(blocker, content, blockee.inbox); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import { renderActivity } from '@/remote/activitypub/renderer/index.js'; | ||||
| import renderBlock from '@/remote/activitypub/renderer/block.js'; | ||||
| import { renderBlock } from '@/remote/activitypub/renderer/block.js'; | ||||
| import renderUndo from '@/remote/activitypub/renderer/undo.js'; | ||||
| import { deliver } from '@/queue/index.js'; | ||||
| import Logger from '../logger.js'; | ||||
|  | @ -19,11 +19,16 @@ export default async function(blocker: CacheableUser, blockee: CacheableUser) { | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// Since we already have the blocker and blockee, we do not need to fetch
 | ||||
| 	// them in the query above and can just manually insert them here.
 | ||||
| 	blocking.blocker = blocker; | ||||
| 	blocking.blockee = blockee; | ||||
| 
 | ||||
| 	Blockings.delete(blocking.id); | ||||
| 
 | ||||
| 	// deliver if remote bloking
 | ||||
| 	if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) { | ||||
| 		const content = renderActivity(renderUndo(renderBlock(blocker, blockee), blocker)); | ||||
| 		const content = renderActivity(renderUndo(renderBlock(blocking), blocker)); | ||||
| 		deliver(blocker, content, blockee.inbox); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue