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
|
@ -1,8 +1,20 @@
|
||||||
import config from '@/config/index.js';
|
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',
|
* Renders a block into its ActivityPub representation.
|
||||||
actor: `${config.url}/users/${blocker.id}`,
|
*
|
||||||
object: blockee.uri,
|
* @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) => {
|
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 = {
|
const follow = {
|
||||||
|
id: requestId ?? `${config.url}/follows/${follower.id}/${followee.id}`,
|
||||||
type: 'Follow',
|
type: 'Follow',
|
||||||
actor: Users.isLocalUser(follower) ? `${config.url}/users/${follower.id}` : follower.uri,
|
actor: Users.isLocalUser(follower) ? `${config.url}/users/${follower.id}` : follower.uri,
|
||||||
object: Users.isLocalUser(followee) ? `${config.url}/users/${followee.id}` : followee.uri,
|
object: Users.isLocalUser(followee) ? `${config.url}/users/${followee.id}` : followee.uri,
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
if (requestId) follow.id = requestId;
|
|
||||||
|
|
||||||
return follow;
|
return follow;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,9 +15,10 @@ import { inbox as processInbox } from '@/queue/index.js';
|
||||||
import { isSelfHost } from '@/misc/convert-host.js';
|
import { isSelfHost } from '@/misc/convert-host.js';
|
||||||
import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js';
|
import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js';
|
||||||
import { ILocalUser, User } from '@/models/entities/user.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 { renderLike } from '@/remote/activitypub/renderer/like.js';
|
||||||
import { getUserKeypair } from '@/misc/keypair-store.js';
|
import { getUserKeypair } from '@/misc/keypair-store.js';
|
||||||
|
import renderFollow from '@/remote/activitypub/renderer/follow.js';
|
||||||
|
|
||||||
// Init router
|
// Init router
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
@ -224,4 +225,30 @@ router.get('/likes/:like', async ctx => {
|
||||||
setResponseType(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;
|
export default router;
|
||||||
|
|
|
@ -2,9 +2,10 @@ import { publishMainStream, publishUserEvent } from '@/services/stream.js';
|
||||||
import { renderActivity } from '@/remote/activitypub/renderer/index.js';
|
import { renderActivity } from '@/remote/activitypub/renderer/index.js';
|
||||||
import renderFollow from '@/remote/activitypub/renderer/follow.js';
|
import renderFollow from '@/remote/activitypub/renderer/follow.js';
|
||||||
import renderUndo from '@/remote/activitypub/renderer/undo.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 { deliver } from '@/queue/index.js';
|
||||||
import renderReject from '@/remote/activitypub/renderer/reject.js';
|
import renderReject from '@/remote/activitypub/renderer/reject.js';
|
||||||
|
import { Blocking } from '@/models/entities/blocking.js';
|
||||||
import { User } from '@/models/entities/user.js';
|
import { User } from '@/models/entities/user.js';
|
||||||
import { Blockings, Users, FollowRequests, Followings, UserListJoinings, UserLists } from '@/models/index.js';
|
import { Blockings, Users, FollowRequests, Followings, UserListJoinings, UserLists } from '@/models/index.js';
|
||||||
import { perUserFollowingChart } from '@/services/chart/index.js';
|
import { perUserFollowingChart } from '@/services/chart/index.js';
|
||||||
|
@ -22,15 +23,19 @@ export default async function(blocker: User, blockee: User) {
|
||||||
removeFromList(blockee, blocker),
|
removeFromList(blockee, blocker),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await Blockings.insert({
|
const blocking = {
|
||||||
id: genId(),
|
id: genId(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
|
blocker,
|
||||||
blockerId: blocker.id,
|
blockerId: blocker.id,
|
||||||
|
blockee,
|
||||||
blockeeId: blockee.id,
|
blockeeId: blockee.id,
|
||||||
});
|
} as Blocking;
|
||||||
|
|
||||||
|
await Blockings.insert(blocking);
|
||||||
|
|
||||||
if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) {
|
if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) {
|
||||||
const content = renderActivity(renderBlock(blocker, blockee));
|
const content = renderActivity(renderBlock(blocking));
|
||||||
deliver(blocker, content, blockee.inbox);
|
deliver(blocker, content, blockee.inbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { renderActivity } from '@/remote/activitypub/renderer/index.js';
|
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 renderUndo from '@/remote/activitypub/renderer/undo.js';
|
||||||
import { deliver } from '@/queue/index.js';
|
import { deliver } from '@/queue/index.js';
|
||||||
import Logger from '../logger.js';
|
import Logger from '../logger.js';
|
||||||
|
@ -19,11 +19,16 @@ export default async function(blocker: CacheableUser, blockee: CacheableUser) {
|
||||||
return;
|
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);
|
Blockings.delete(blocking.id);
|
||||||
|
|
||||||
// deliver if remote bloking
|
// deliver if remote bloking
|
||||||
if (Users.isLocalUser(blocker) && Users.isRemoteUser(blockee)) {
|
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);
|
deliver(blocker, content, blockee.inbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue