diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 16804a240d..66f649c9bd 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -18,6 +18,7 @@ import { getApId } from './type.js'; import { ApPersonService } from './models/ApPersonService.js'; import { ApLoggerService } from './ApLoggerService.js'; import type { IObject } from './type.js'; +import { UtilityService } from '../UtilityService.js'; export type UriParseResult = { /** wether the URI was generated by us */ @@ -56,11 +57,18 @@ export class ApDbResolverService implements OnApplicationShutdown { private cacheService: CacheService, private apPersonService: ApPersonService, private apLoggerService: ApLoggerService, + private utilityService: UtilityService, ) { this.publicKeyByUserIdCache = new MemoryKVCache(Infinity); this.logger = this.apLoggerService.logger.createSubLogger('db-resolver'); } + private punyHost(url: string): string { + const urlObj = new URL(url); + const host = `${this.utilityService.toPuny(urlObj.hostname)}${urlObj.port.length > 0 ? ':' + urlObj.port : ''}`; + return host; + } + @bindThis public parseUri(value: string | IObject): UriParseResult { const separator = '/'; @@ -137,9 +145,8 @@ export class ApDbResolverService implements OnApplicationShutdown { * AP Actor id => Misskey User and Key * @param uri AP Actor id * @param keyId Key id to find. If not specified, main key will be selected. - * keyIdがURLライクの場合、ハッシュを削除したkeyIdはuriと同一であることが期待される * @returns - * 1. uriとkeyIdが一致しない場合`null` + * 1. ユーザーとキーのホストが一致しない場合`null` * 2. userが見つからない場合`{ user: null, key: null }` * 3. keyが見つからない場合`{ user, key: null }` */ @@ -153,20 +160,19 @@ export class ApDbResolverService implements OnApplicationShutdown { } | null> { if (keyId) { - try { - const actorUrl = new URL(uri); - const keyUrl = new URL(keyId); - actorUrl.hash = ''; - keyUrl.hash = ''; - if (actorUrl.href !== keyUrl.href) { - // uriとkeyId(のhashなし)が一致しない場合、actorと鍵の所有者が一致していないということである - // その場合、そもそも署名は有効といえないのでキーの検索は無意味 - this.logger.warn(`actor uri and keyId are not matched uri=${uri} keyId=${keyId}`); - return null; - } - } catch (err) { - // キーがURLっぽくない場合はエラーになるはず。そういった場合はとりあえずキー検索してみる - this.logger.warn(`maybe actor uri or keyId are not url like: uri=${uri} keyId=${keyId}`, { err }); + if (this.punyHost(uri) !== this.punyHost(keyId)) { + /** + * keyIdはURL形式かつkeyIdのホストはuriのホストと一致するはず + * (ApPersonService.validateActorに由来) + * + * ただ、Mastodonはリプライ関連で他人のノートをHTTP Signature署名して送ってくることがある + * そのような署名は有効性に疑問があるので無視することにする + * ここではuriとkeyIdのホストが一致しない場合は無視する + * ハッシュをなくしたkeyIdとuriの同一性を比べてみてもいいが、`uri#*-key`というkeyIdを設定するのが + * 決まりごとというわけでもないため幅を持たせることにする + */ + this.logger.warn(`actor uri and keyId are not matched uri=${uri} keyId=${keyId}`); + return null; } }