summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/ActivityPubServerService.ts
diff options
context:
space:
mode:
authorhutchisr <42283663+hutchisr@users.noreply.github.com>2023-04-12 04:22:50 -0700
committerGitHub <noreply@github.com>2023-04-12 20:22:50 +0900
commitb7d056fb2266a91c4d671f200ef6c9f744f9416f (patch)
tree7e6c03946ade2c51354e70e0360a7f7c0eacae88 /packages/backend/src/server/ActivityPubServerService.ts
parentfix type (diff)
downloadsharkey-b7d056fb2266a91c4d671f200ef6c9f744f9416f.tar.gz
sharkey-b7d056fb2266a91c4d671f200ef6c9f744f9416f.tar.bz2
sharkey-b7d056fb2266a91c4d671f200ef6c9f744f9416f.zip
Use unique identifier for each follow request (#10600)
Co-authored-by: anemone <anemoneya@icloud.com>
Diffstat (limited to 'packages/backend/src/server/ActivityPubServerService.ts')
-rw-r--r--packages/backend/src/server/ActivityPubServerService.ts88
1 files changed, 63 insertions, 25 deletions
diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts
index 5799622074..e13e9265ab 100644
--- a/packages/backend/src/server/ActivityPubServerService.ts
+++ b/packages/backend/src/server/ActivityPubServerService.ts
@@ -6,7 +6,7 @@ import { Brackets, In, IsNull, LessThan, Not } from 'typeorm';
import accepts from 'accepts';
import vary from 'vary';
import { DI } from '@/di-symbols.js';
-import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository } from '@/models/index.js';
+import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository, FollowRequestsRepository } from '@/models/index.js';
import * as url from '@/misc/prelude/url.js';
import type { Config } from '@/config.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
@@ -54,6 +54,9 @@ export class ActivityPubServerService {
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,
+ @Inject(DI.followRequestsRepository)
+ private followRequestsRepository: FollowRequestsRepository,
+
private utilityService: UtilityService,
private userEntityService: UserEntityService,
private apRendererService: ApRendererService,
@@ -205,22 +208,22 @@ export class ActivityPubServerService {
reply.code(400);
return;
}
-
+
const page = request.query.page === 'true';
-
+
const user = await this.usersRepository.findOneBy({
id: userId,
host: IsNull(),
});
-
+
if (user == null) {
reply.code(404);
return;
}
-
+
//#region Check ff visibility
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
-
+
if (profile.ffVisibility === 'private') {
reply.code(403);
reply.header('Cache-Control', 'public, max-age=30');
@@ -231,31 +234,31 @@ export class ActivityPubServerService {
return;
}
//#endregion
-
+
const limit = 10;
const partOf = `${this.config.url}/users/${userId}/following`;
-
+
if (page) {
const query = {
followerId: user.id,
} as FindOptionsWhere<Following>;
-
+
// カーソルが指定されている場合
if (cursor) {
query.id = LessThan(cursor);
}
-
+
// Get followings
const followings = await this.followingsRepository.find({
where: query,
take: limit + 1,
order: { id: -1 },
});
-
+
// 「次のページ」があるかどうか
const inStock = followings.length === limit + 1;
if (inStock) followings.pop();
-
+
const renderedFollowees = await Promise.all(followings.map(following => this.apRendererService.renderFollowUser(following.followeeId)));
const rendered = this.apRendererService.renderOrderedCollectionPage(
`${partOf}?${url.query({
@@ -269,7 +272,7 @@ export class ActivityPubServerService {
cursor: followings[followings.length - 1].id,
})}` : undefined,
);
-
+
this.setResponseType(request, reply);
return (this.apRendererService.addContext(rendered));
} else {
@@ -330,33 +333,33 @@ export class ActivityPubServerService {
reply.code(400);
return;
}
-
+
const untilId = request.query.until_id;
if (untilId != null && typeof untilId !== 'string') {
reply.code(400);
return;
}
-
+
const page = request.query.page === 'true';
-
+
if (countIf(x => x != null, [sinceId, untilId]) > 1) {
reply.code(400);
return;
}
-
+
const user = await this.usersRepository.findOneBy({
id: userId,
host: IsNull(),
});
-
+
if (user == null) {
reply.code(404);
return;
}
-
+
const limit = 20;
const partOf = `${this.config.url}/users/${userId}/outbox`;
-
+
if (page) {
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), sinceId, untilId)
.andWhere('note.userId = :userId', { userId: user.id })
@@ -365,11 +368,11 @@ export class ActivityPubServerService {
.orWhere('note.visibility = \'home\'');
}))
.andWhere('note.localOnly = FALSE');
-
+
const notes = await query.take(limit).getMany();
-
+
if (sinceId) notes.reverse();
-
+
const activities = await Promise.all(notes.map(note => this.packActivity(note)));
const rendered = this.apRendererService.renderOrderedCollectionPage(
`${partOf}?${url.query({
@@ -387,7 +390,7 @@ export class ActivityPubServerService {
until_id: notes[notes.length - 1].id,
})}` : undefined,
);
-
+
this.setResponseType(request, reply);
return (this.apRendererService.addContext(rendered));
} else {
@@ -457,7 +460,7 @@ export class ActivityPubServerService {
// note
fastify.get<{ Params: { note: string; } }>('/notes/:note', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
vary(reply.raw, 'Accept');
-
+
const note = await this.notesRepository.findOneBy({
id: request.params.note,
visibility: In(['public', 'home']),
@@ -639,6 +642,41 @@ export class ActivityPubServerService {
return (this.apRendererService.addContext(this.apRendererService.renderFollow(follower, followee)));
});
+ // follow
+ fastify.get<{ Params: { followRequestId: string ; } }>('/follows/:followRequestId', async (request, reply) => {
+ // This may be used before the follow is completed, so we do not
+ // check if the following exists and only check if the follow request exists.
+
+ const followRequest = await this.followRequestsRepository.findOneBy({
+ id: request.params.followRequestId,
+ });
+
+ if (followRequest == null) {
+ reply.code(404);
+ return;
+ }
+
+ const [follower, followee] = await Promise.all([
+ this.usersRepository.findOneBy({
+ id: followRequest.followerId,
+ host: IsNull(),
+ }),
+ this.usersRepository.findOneBy({
+ id: followRequest.followeeId,
+ host: Not(IsNull()),
+ }),
+ ]);
+
+ if (follower == null || followee == null) {
+ reply.code(404);
+ return;
+ }
+
+ reply.header('Cache-Control', 'public, max-age=180');
+ this.setResponseType(request, reply);
+ return (this.apRendererService.addContext(this.apRendererService.renderFollow(follower, followee)));
+ });
+
done();
}
}