From efe63de853e395bfc9fd653a1d50e47c7472ea0c Mon Sep 17 00:00:00 2001 From: tamaina Date: Sat, 30 Aug 2025 18:43:02 +0900 Subject: [PATCH] tabun ok --- .../src/core/RemoteUserResolveService.ts | 2 +- .../core/activitypub/ApDbResolverService.ts | 73 ++++++++++++++----- .../src/core/activitypub/ApResolverService.ts | 24 ++++-- 3 files changed, 74 insertions(+), 25 deletions(-) diff --git a/packages/backend/src/core/RemoteUserResolveService.ts b/packages/backend/src/core/RemoteUserResolveService.ts index a2f1b73cdb..97f9e11472 100644 --- a/packages/backend/src/core/RemoteUserResolveService.ts +++ b/packages/backend/src/core/RemoteUserResolveService.ts @@ -75,7 +75,7 @@ export class RemoteUserResolveService { const self = await this.resolveSelf(acctLower); if (this.utilityService.isUriLocal(self.href)) { - const local = this.apDbResolverService.parseUri(self.href); + const local = this.apDbResolverService.parseLocalUri(self.href); if (local.local && local.type === 'users') { // the LR points to local return (await this.apDbResolverService diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 5c16744a77..99baacf6ed 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -4,6 +4,8 @@ */ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; +import * as misskey from 'misskey-js'; +import { IsNull } from 'typeorm'; import { DI } from '@/di-symbols.js'; import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/_.js'; import type { Config } from '@/config.js'; @@ -32,6 +34,12 @@ export type UriParseResult = { local: false; /** uri in DB */ uri: string; +} | { + /** wether the URI was generated by us and acct.host points to us */ + local: boolean; + type: 'acct'; + /** Acct */ + acct: misskey.acct.Acct; }; @Injectable() @@ -60,15 +68,33 @@ export class ApDbResolverService implements OnApplicationShutdown { this.publicKeyByUserIdCache = new MemoryKVCache(1000 * 60 * 60 * 12); // 12h } + /** + * If provided uri's hostname points to this server, parse it. If not, return the uri as-is. + * @param value + * @returns + */ @bindThis - public parseUri(value: string | IObject): UriParseResult { + public parseLocalUri(value: string | IObject): UriParseResult { const separator = '/'; const uri = new URL(getApId(value)); - if (this.utilityService.toPuny(uri.host) !== this.utilityService.toPuny(this.config.host)) { + if (!this.utilityService.isSelfHost(uri.hostname)) { return { local: false, uri: uri.href }; } + try { + const acct = misskey.acct.parseUrl(uri.toString()); + if (acct) { + return { + local: this.utilityService.isSelfHost(acct.host), + type: 'acct', + acct, + }; + } + } finally { + // no-op + } + const [, type, id, ...rest] = uri.pathname.split(separator); return { local: true, @@ -83,19 +109,21 @@ export class ApDbResolverService implements OnApplicationShutdown { */ @bindThis public async getNoteFromApId(value: string | IObject): Promise { - const parsed = this.parseUri(value); + const parsed = this.parseLocalUri(value); - if (parsed.local) { - if (parsed.type !== 'notes') return null; - - return await this.notesRepository.findOneBy({ - id: parsed.id, - }); - } else { + if ('uri' in parsed) { return await this.notesRepository.findOneBy({ uri: parsed.uri, }); } + + if (parsed.type === 'notes') { + return await this.notesRepository.findOneBy({ + id: parsed.id, + }); + } + + return null; } /** @@ -103,21 +131,30 @@ export class ApDbResolverService implements OnApplicationShutdown { */ @bindThis public async getUserFromApId(value: string | IObject): Promise { - const parsed = this.parseUri(value); + const parsed = this.parseLocalUri(value); - if (parsed.local) { - if (parsed.type !== 'users') return null; + if ('acct' in parsed) { + return await this.usersRepository.findOneBy({ + usernameLower: parsed.acct.username.toLowerCase(), + host: (parsed.acct.host == null || parsed.local) ? IsNull() : this.utilityService.toPuny(parsed.acct.host), + }) as MiLocalUser | MiRemoteUser | null; + } - return await this.cacheService.userByIdCache.fetchMaybe( - parsed.id, - () => this.usersRepository.findOneBy({ id: parsed.id, isDeleted: false }).then(x => x ?? undefined), - ) as MiLocalUser | undefined ?? null; - } else { + if ('uri' in parsed) { return await this.cacheService.uriPersonCache.fetch( parsed.uri, () => this.usersRepository.findOneBy({ uri: parsed.uri, isDeleted: false }), ) as MiRemoteUser | null; } + + if (parsed.type === 'users') { + return await this.cacheService.userByIdCache.fetchMaybe( + parsed.id, + () => this.usersRepository.findOneBy({ id: parsed.id, isDeleted: false }).then(x => x ?? undefined), + ) as MiLocalUser | undefined ?? null; + } + + return null; } /** diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index 646150455b..f3185327c5 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -15,9 +15,10 @@ import { bindThis } from '@/decorators.js'; import { LoggerService } from '@/core/LoggerService.js'; import type Logger from '@/logger.js'; import { SystemAccountService } from '@/core/SystemAccountService.js'; +import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; import { isCollectionOrOrderedCollection } from './type.js'; -import { ApDbResolverService } from './ApDbResolverService.js'; +import { ApDbResolverService, type UriParseResult } from './ApDbResolverService.js'; import { ApRendererService } from './ApRendererService.js'; import { ApRequestService } from './ApRequestService.js'; import { FetchAllowSoftFailMask } from './misc/check-against-url.js'; @@ -42,6 +43,7 @@ export class Resolver { private httpRequestService: HttpRequestService, private apRendererService: ApRendererService, private apDbResolverService: ApDbResolverService, + private remoteUserResolveService: RemoteUserResolveService, private loggerService: LoggerService, private recursionLimit = 256, ) { @@ -96,8 +98,9 @@ export class Resolver { this.history.add(value); const host = this.utilityService.extractDbHost(value); - if (this.utilityService.isSelfHost(host)) { - return await this.resolveLocal(value); + const parsed = this.apDbResolverService.parseLocalUri(value); + if (parsed.local === true) { + return await this.resolveLocal(parsed); } if (!this.utilityService.isFederationAllowedHost(host)) { @@ -124,9 +127,18 @@ export class Resolver { } @bindThis - private resolveLocal(url: string): Promise { - const parsed = this.apDbResolverService.parseUri(url); - if (!parsed.local) throw new IdentifiableError('02b40cd0-fa92-4b0c-acc9-fb2ada952ab8', 'resolveLocal: not local'); + private resolveLocal(parsed: UriParseResult): Promise { + if (parsed.local === false || 'uri' in parsed) { + throw new IdentifiableError('02b40cd0-fa92-4b0c-acc9-fb2ada952ab8', 'resolveLocal: not local'); + } + + if ('acct' in parsed) { + return this.usersRepository.findOneByOrFail({ + usernameLower: parsed.acct.username.toLowerCase(), + host: IsNull(), + }) + .then(user => this.apRendererService.renderPerson(user as MiLocalUser)); + } switch (parsed.type) { case 'notes':