diff options
Diffstat (limited to 'packages/backend/src/server/api/endpoints/ap')
| -rw-r--r-- | packages/backend/src/server/api/endpoints/ap/show.ts | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 19ca3ceb8e..fc19e18e59 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -4,11 +4,10 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import ms from 'ms'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { MiNote } from '@/models/Note.js'; import type { MiLocalUser, MiUser } from '@/models/User.js'; -import { isActor, isPost, getApId } from '@/core/activitypub/type.js'; +import { isActor, isPost, getApId, getNullableApId, ObjectWithId } from '@/core/activitypub/type.js'; import type { SchemaType } from '@/misc/json-schema.js'; import { ApResolverService } from '@/core/activitypub/ApResolverService.js'; import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js'; @@ -18,6 +17,8 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; +import { ApRequestService } from '@/core/activitypub/ApRequestService.js'; +import { InstanceActorService } from '@/core/InstanceActorService.js'; import { ApiError } from '../../error.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; @@ -27,9 +28,10 @@ export const meta = { requireCredential: true, kind: 'read:account', + // Up to 30 calls, then 1 per 1/2 second limit: { - duration: ms('1minute'), max: 30, + dripRate: 500, }, errors: { @@ -120,6 +122,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- private apDbResolverService: ApDbResolverService, private apPersonService: ApPersonService, private apNoteService: ApNoteService, + private readonly apRequestService: ApRequestService, + private readonly instanceActorService: InstanceActorService, ) { super(meta, paramDef, async (ps, me) => { const object = await this.fetchAny(ps.uri, me); @@ -146,6 +150,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- ])); if (local != null) return local; + // No local object found with that uri. + // Before we fetch, resolve the URI in case it has a cross-origin redirect or anything like that. + // Resolver.resolve() uses strict verification, which is overly paranoid for a user-provided lookup. + uri = await this.resolveCanonicalUri(uri); // eslint-disable-line no-param-reassign + if (!this.utilityService.isFederationAllowedUri(uri)) return null; + const host = this.utilityService.extractDbHost(uri); // local object, not found in db? fail @@ -228,4 +238,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- return null; } + + /** + * Resolves an arbitrary URI to its canonical, post-redirect form. + */ + private async resolveCanonicalUri(uri: string): Promise<string> { + const user = await this.instanceActorService.getInstanceActor(); + const res = await this.apRequestService.signedGet(uri, user, true) as ObjectWithId; + return getNullableApId(res) ?? uri; + } } |