From 95c76c2880ceb27cbcc486a8757b594066899701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=82=8F=E3=82=8F=E3=82=8F=E3=81=A8=E3=83=BC?= =?UTF-8?q?=E3=81=AB=E3=82=85?= <17376330+u1-liquid@users.noreply.github.com> Date: Sat, 28 Dec 2024 11:19:13 +0900 Subject: [PATCH 1/2] cleanup(backend): refactor UtilityService --- .../backend/src/core/CustomEmojiService.ts | 4 +- packages/backend/src/core/EmailService.ts | 4 +- .../src/core/FederatedInstanceService.ts | 2 +- .../backend/src/core/NoteCreateService.ts | 2 +- packages/backend/src/core/ReactionService.ts | 2 +- .../src/core/RemoteUserResolveService.ts | 6 +-- packages/backend/src/core/SignupService.ts | 2 +- .../backend/src/core/UserFollowingService.ts | 2 +- packages/backend/src/core/UtilityService.ts | 50 ++++++------------- .../core/activitypub/ApDbResolverService.ts | 5 +- .../src/core/activitypub/ApInboxService.ts | 8 +-- .../src/core/activitypub/ApRequestService.ts | 2 +- .../src/core/activitypub/ApResolverService.ts | 8 +-- .../core/activitypub/models/ApNoteService.ts | 25 +++++----- .../activitypub/models/ApPersonService.ts | 49 +++++++++--------- .../backend/src/core/chart/charts/instance.ts | 12 ++--- .../core/entities/DriveFileEntityService.ts | 2 +- .../core/entities/InstanceEntityService.ts | 6 +-- .../processors/DeliverProcessorService.ts | 4 +- .../ImportBlockingProcessorService.ts | 2 +- .../ImportFollowingProcessorService.ts | 2 +- .../ImportMutingProcessorService.ts | 2 +- .../ImportUserListsProcessorService.ts | 2 +- .../queue/processors/InboxProcessorService.ts | 12 ++--- .../api/endpoints/admin/emoji/list-remote.ts | 2 +- .../refresh-remote-instance-metadata.ts | 2 +- .../admin/federation/update-instance.ts | 2 +- .../src/server/api/endpoints/ap/show.ts | 4 +- .../api/endpoints/federation/show-instance.ts | 2 +- .../server/api/endpoints/users/followers.ts | 2 +- .../server/api/endpoints/users/following.ts | 2 +- 31 files changed, 106 insertions(+), 125 deletions(-) diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 27b85b10b98f..29e543ee3df6 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -311,7 +311,7 @@ export class CustomEmojiService implements OnApplicationShutdown { : this.utilityService.isSelfHost(src) ? null // 自ホスト指定 : (src || noteUserHost); // 指定されたホスト || ノートなどの所有者のホスト (こっちがリアクションにマッチすることはない) - host = this.utilityService.toPunyNullable(host); + host = host ? this.utilityService.normalizeHost(host) : null; return host; } @@ -324,7 +324,7 @@ export class CustomEmojiService implements OnApplicationShutdown { const name = match[1]; // ホスト正規化 - const host = this.utilityService.toPunyNullable(this.normalizeHost(match[2], noteUserHost)); + const host = this.normalizeHost(match[2], noteUserHost); return { name, host }; } diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index 832c2d55ef1f..37c9c736eaf4 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -236,7 +236,7 @@ export class EmailService { } const emailDomain: string = emailAddress.split('@')[1]; - const isBanned = this.utilityService.isBlockedHost(meta.bannedEmailDomains, emailDomain); + const isBanned = this.utilityService.isItemListedIn(emailDomain, meta.bannedEmailDomains); if (isBanned) { return { @@ -304,7 +304,7 @@ export class EmailService { reason: 'mx', }; } - if (json.mx_host?.some(host => this.utilityService.isBlockedHost(meta.bannedEmailDomains, host))) { + if (json.mx_host?.some(host => this.utilityService.isItemListedIn(host, meta.bannedEmailDomains))) { return { valid: false, reason: 'mx', diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts index 66db2067d9f8..5b267ebc2548 100644 --- a/packages/backend/src/core/FederatedInstanceService.ts +++ b/packages/backend/src/core/FederatedInstanceService.ts @@ -47,7 +47,7 @@ export class FederatedInstanceService implements OnApplicationShutdown { @bindThis public async fetch(host: string): Promise { - host = this.utilityService.toPuny(host); + host = this.utilityService.normalizeHost(host); const cached = await this.federatedInstanceCache.get(host); if (cached) return cached; diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 20c7f3e2b75a..ea8b9432f522 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -285,7 +285,7 @@ export class NoteCreateService implements OnApplicationShutdown { throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Notes including prohibited words are not allowed.'); } - const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host); + const inSilencedInstance = this.utilityService.isItemListedIn(user.host, meta.silencedHosts); if (data.visibility === 'public' && inSilencedInstance && user.host !== null) { data.visibility = 'home'; diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 59e8fa8f62c2..2e5ca049bffd 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -129,7 +129,7 @@ export class ReactionService { } else if (_reaction) { const custom = reaction.match(isCustomEmojiRegexp); if (custom) { - const reacterHost = this.utilityService.toPunyNullable(user.host); + const reacterHost = user.host ? this.utilityService.normalizeHost(user.host) : null; const name = custom[1]; const emoji = reacterHost == null diff --git a/packages/backend/src/core/RemoteUserResolveService.ts b/packages/backend/src/core/RemoteUserResolveService.ts index c7f5effd2e8f..d9d97458ffc9 100644 --- a/packages/backend/src/core/RemoteUserResolveService.ts +++ b/packages/backend/src/core/RemoteUserResolveService.ts @@ -54,9 +54,7 @@ export class RemoteUserResolveService { }) as MiLocalUser; } - host = this.utilityService.toPuny(host); - - if (host === this.utilityService.toPuny(this.config.host)) { + if (this.utilityService.isSelfHost(host)) { this.logger.info(`return local user: ${usernameLower}`); return await this.usersRepository.findOneBy({ usernameLower, host: IsNull() }).then(u => { if (u == null) { @@ -67,6 +65,8 @@ export class RemoteUserResolveService { }) as MiLocalUser; } + host = this.utilityService.normalizeHost(host); + const user = await this.usersRepository.findOneBy({ usernameLower, host }) as MiRemoteUser | null; const acctLower = `${usernameLower}@${host}`; diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts index 76c1dc322b8a..514b0d2b2eb5 100644 --- a/packages/backend/src/core/SignupService.ts +++ b/packages/backend/src/core/SignupService.ts @@ -141,7 +141,7 @@ export class SignupService { id: this.idService.gen(), username: username, usernameLower: username.toLowerCase(), - host: this.utilityService.toPunyNullable(host), + host: host ? this.utilityService.normalizeHost(host) : null, token: secret, isRoot: isTheFirstUser, })); diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 753eb3592eab..5a32484581f5 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -173,7 +173,7 @@ export class UserFollowingService implements OnModuleInit { followee.isLocked || (followeeProfile.carefulBot && follower.isBot) || (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee) && process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING !== 'true') || - (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower) && this.utilityService.isSilencedHost((await this.metaService.fetch()).silencedHosts, follower.host)) + (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower) && this.utilityService.isItemListedIn(follower.host, (await this.metaService.fetch()).silencedHosts)) ) { let autoAccept = false; diff --git a/packages/backend/src/core/UtilityService.ts b/packages/backend/src/core/UtilityService.ts index 7d3a74cf578d..2b35e86f4eb8 100644 --- a/packages/backend/src/core/UtilityService.ts +++ b/packages/backend/src/core/UtilityService.ts @@ -5,8 +5,8 @@ import { URL } from 'node:url'; import punycode from 'punycode.js'; -import { Inject, Injectable } from '@nestjs/common'; import RE2 from 're2'; +import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { bindThis } from '@/decorators.js'; @@ -21,36 +21,26 @@ export class UtilityService { @bindThis public getFullApAccount(username: string, host: string | null): string { - return host ? `${username}@${this.toPuny(host)}` : `${username}@${this.toPuny(this.config.host)}`; + return host ? `${username}@${this.normalizeHost(host)}` : `${username}@${this.normalizeHost(this.config.host)}`; } @bindThis public isSelfHost(host: string | null): boolean { if (host == null) return true; - return this.toPuny(this.config.host) === this.toPuny(host); + return this.normalizeHost(this.config.host) === this.normalizeHost(host); } @bindThis public isUriLocal(uri: string): boolean { - return this.punyHost(uri) === this.toPuny(this.config.host); - } - - @bindThis - public isBlockedHost(blockedHosts: string[], host: string | null): boolean { - if (host == null) return false; - return blockedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`)); - } - - @bindThis - public isSilencedHost(silencedHosts: string[] | undefined, host: string | null): boolean { - if (!silencedHosts || host == null) return false; - return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`)); + return this.normalizeHost(this.config.hostname) === this.extractHost(uri); } @bindThis - public isSensitiveMediaHost(sensitiveMediaHosts: string[] | undefined, host: string | null): boolean { - if (!sensitiveMediaHosts || host == null) return false; - return sensitiveMediaHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`)); + public isItemListedIn(item: string | null, list: string[] | undefined): boolean { + if (!list || !item) return false; + list = list.map(x => '.' + this.normalizeHost(x).split(':')[0]); + item = '.' + this.normalizeHost(item).split(':')[0]; + return list.some(x => item.endsWith(x)); } @bindThis @@ -93,26 +83,14 @@ export class UtilityService { } @bindThis - public extractDbHost(uri: string): string { - const url = new URL(uri); - return this.toPuny(url.host); - } - - @bindThis - public toPuny(host: string): string { - return punycode.toASCII(host.toLowerCase()); - } - - @bindThis - public toPunyNullable(host: string | null | undefined): string | null { - if (host == null) return null; + public normalizeHost(host: string): string { return punycode.toASCII(host.toLowerCase()); } @bindThis - public punyHost(url: string): string { - const urlObj = new URL(url); - const host = `${this.toPuny(urlObj.hostname)}${urlObj.port.length > 0 ? ':' + urlObj.port : ''}`; - return host; + public extractHost(uri: string): string { + // ASCII String で返されるので punycode 化はいらない + // ref: https://url.spec.whatwg.org/#host-serializing + return new URL(uri).host; } } diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 5c16744a7750..427dc5f816d0 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -64,8 +64,9 @@ export class ApDbResolverService implements OnApplicationShutdown { public parseUri(value: string | IObject): UriParseResult { const separator = '/'; - const uri = new URL(getApId(value)); - if (this.utilityService.toPuny(uri.host) !== this.utilityService.toPuny(this.config.host)) { + const apId = getApId(value); + const uri = new URL(apId); + if (!this.utilityService.isUriLocal(apId)) { return { local: false, uri: uri.href }; } diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 4d0342752989..9542eabe572e 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -100,12 +100,12 @@ export class ApInboxService { const items = toArray(isCollection(activity) ? activity.items : activity.orderedItems); if (items.length >= resolver.getRecursionLimit()) { - throw new Error(`skipping activity: collection would surpass recursion limit: ${this.utilityService.extractDbHost(actor.uri)}`); + throw new Error(`skipping activity: collection would surpass recursion limit: ${this.utilityService.extractHost(actor.uri)}`); } for (const item of items) { const act = await resolver.resolve(item); - if (act.id == null || this.utilityService.extractDbHost(act.id) !== this.utilityService.extractDbHost(actor.uri)) { + if (act.id == null || this.utilityService.extractHost(act.id) !== this.utilityService.extractHost(actor.uri)) { this.logger.warn('skipping activity: activity id is null or mismatching'); continue; } @@ -310,7 +310,7 @@ export class ApInboxService { // アナウンス先をブロックしてたら中断 const meta = await this.metaService.fetch(); - if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.extractDbHost(uri))) return 'skip: blocked host'; + if (this.utilityService.isItemListedIn(this.utilityService.extractHost(uri), meta.blockedHosts)) return 'skip: blocked host'; const unlock = await this.appLockService.getApLock(uri); @@ -432,7 +432,7 @@ export class ApInboxService { } if (typeof note.id === 'string') { - if (this.utilityService.extractDbHost(actor.uri) !== this.utilityService.extractDbHost(note.id)) { + if (this.utilityService.extractHost(actor.uri) !== this.utilityService.extractHost(note.id)) { return 'skip: host in actor.uri !== note.id'; } } else { diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index f59fabba3c7d..4e4d7e8d523e 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -220,7 +220,7 @@ export class ApRequestService { const alternate = fragment.querySelector('head > link[rel="alternate"][type="application/activity+json"]'); if (alternate) { const href = alternate.getAttribute('href'); - if (href && this.utilityService.punyHost(url) === this.utilityService.punyHost(href)) { + if (href && this.utilityService.extractHost(url) === this.utilityService.extractHost(href)) { return await this.signedGet(href, user, false); } } diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index 000f9d59f26e..2e00d98d14b5 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -89,18 +89,18 @@ export class Resolver { } if (this.history.size > this.recursionLimit) { - throw new Error(`hit recursion limit: ${this.utilityService.extractDbHost(value)}`); + throw new Error(`hit recursion limit: ${this.utilityService.extractHost(value)}`); } this.history.add(value); - const host = this.utilityService.extractDbHost(value); + const host = this.utilityService.extractHost(value); if (this.utilityService.isSelfHost(host)) { return await this.resolveLocal(value); } const meta = await this.metaService.fetch(); - if (this.utilityService.isBlockedHost(meta.blockedHosts, host)) { + if (this.utilityService.isItemListedIn(host, meta.blockedHosts)) { throw new Error('Instance is blocked'); } @@ -128,7 +128,7 @@ export class Resolver { throw new Error('invalid AP object: missing id'); } - if (this.utilityService.punyHost(object.id) !== this.utilityService.punyHost(value)) { + if (this.utilityService.extractHost(object.id) !== this.utilityService.extractHost(value)) { throw new Error(`invalid AP object ${value}: id ${object.id} has different host`); } diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index 3ce588e18c03..8bba1994e694 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -81,20 +81,21 @@ export class ApNoteService { @bindThis public validateNote(object: IObject, uri: string, actor?: MiRemoteUser): Error | null { - const expectHost = this.utilityService.extractDbHost(uri); + const expectedHost = this.utilityService.extractHost(uri); const apType = getApType(object); if (apType == null || !validPost.includes(apType)) { return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: invalid object type ${apType ?? 'undefined'}`); } - if (object.id && this.utilityService.extractDbHost(object.id) !== expectHost) { - return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: id has different host. expected: ${expectHost}, actual: ${this.utilityService.extractDbHost(object.id)}`); + let actualHost = object.id && this.utilityService.extractHost(object.id); + if (actualHost && expectedHost !== actualHost) { + return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: id has different host. expected: ${expectedHost}, actual: ${actualHost}`); } - const actualHost = object.attributedTo && this.utilityService.extractDbHost(getOneApId(object.attributedTo)); - if (object.attributedTo && actualHost !== expectHost) { - return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${actualHost}`); + actualHost = object.attributedTo && this.utilityService.extractHost(getOneApId(object.attributedTo)); + if (actualHost && expectedHost !== actualHost) { + return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: attributedTo has different host. expected: ${expectedHost}, actual: ${actualHost}`); } if (object.published && !this.idService.isSafeT(new Date(object.published).valueOf())) { @@ -165,8 +166,8 @@ export class ApNoteService { throw new Error('unexpected schema of note url: ' + url); } - if (this.utilityService.punyHost(url) !== this.utilityService.punyHost(note.id)) { - throw new Error(`note url & uri host mismatch: note url: ${url}, note uri: ${note.id}`); + if (this.utilityService.extractHost(note.id) !== this.utilityService.extractHost(url)) { + throw new Error(`note id and url have different host: ${note.id} - ${url}`); } } @@ -234,7 +235,7 @@ export class ApNoteService { } } - const isSensitiveMediaHost = this.utilityService.isSensitiveMediaHost(meta.sensitiveMediaHosts, this.utilityService.extractDbHost(note.id ?? entryUri)); + const isSensitiveMediaHost = this.utilityService.isItemListedIn(this.utilityService.extractHost(note.id ?? entryUri), meta.sensitiveMediaHosts); // 添付ファイル const files: MiDriveFile[] = []; @@ -349,7 +350,7 @@ export class ApNoteService { this.logger.info('The note is already inserted while creating itself, reading again'); const duplicate = await this.fetchNote(value); if (!duplicate) { - throw new Error('The note creation failed with duplication error even when there is no duplication'); + throw new Error(`The note creation failed with duplication error even when there is no duplication: ${entryUri}`); } return duplicate; } @@ -367,7 +368,7 @@ export class ApNoteService { // ブロックしていたら中断 const meta = await this.metaService.fetch(); - if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.extractDbHost(uri))) { + if (this.utilityService.isItemListedIn(this.utilityService.extractHost(uri), meta.blockedHosts)) { throw new StatusError('blocked host', 451); } @@ -396,7 +397,7 @@ export class ApNoteService { @bindThis public async extractEmojis(tags: IObject | IObject[], host: string): Promise { // eslint-disable-next-line no-param-reassign - host = this.utilityService.toPuny(host); + host = this.utilityService.normalizeHost(host); const eomjiTags = toArray(tags).filter(isEmoji); diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 88c2dc5d2b5e..cbebdfebd2dc 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -137,7 +137,7 @@ export class ApPersonService implements OnModuleInit { */ @bindThis private validateActor(x: IObject, uri: string): IActor { - const expectHost = this.utilityService.punyHost(uri); + const expectedHost = this.utilityService.extractHost(uri); if (!isActor(x)) { throw new Error(`invalid Actor type '${x.type}'`); @@ -151,15 +151,18 @@ export class ApPersonService implements OnModuleInit { throw new Error('invalid Actor: wrong inbox'); } - if (this.utilityService.punyHost(x.inbox) !== expectHost) { - throw new Error('invalid Actor: inbox has different host'); + let actualHost = this.utilityService.extractHost(x.inbox); + if (expectedHost !== actualHost) { + throw new Error(`invalid Actor: inbox has different host. expected: ${expectedHost}, actual: ${actualHost}`); } const sharedInboxObject = x.sharedInbox ?? (x.endpoints ? x.endpoints.sharedInbox : undefined); if (sharedInboxObject != null) { const sharedInbox = getApId(sharedInboxObject); - if (!(typeof sharedInbox === 'string' && sharedInbox.length > 0 && this.utilityService.punyHost(sharedInbox) === expectHost)) { - throw new Error('invalid Actor: wrong shared inbox'); + if (!sharedInbox) throw new Error('invalid Actor: wrong shared inbox'); + actualHost = this.utilityService.extractHost(sharedInbox); + if (expectedHost !== actualHost) { + throw new Error(`invalid Actor: shared inbox has different host. expected: ${expectedHost}, actual: ${actualHost}`); } } @@ -167,12 +170,10 @@ export class ApPersonService implements OnModuleInit { const xCollection = (x as IActor)[collection]; if (xCollection != null) { const collectionUri = getApId(xCollection); - if (typeof collectionUri === 'string' && collectionUri.length > 0) { - if (this.utilityService.punyHost(collectionUri) !== expectHost) { - throw new Error(`invalid Actor: ${collection} has different host`); - } - } else if (collectionUri != null) { - throw new Error(`invalid Actor: wrong ${collection}`); + if (!collectionUri) throw new Error(`invalid Actor: wrong ${collection}`); + actualHost = this.utilityService.extractHost(collectionUri); + if (expectedHost !== actualHost) { + throw new Error(`invalid Actor: ${collection} has different host. expected: ${expectedHost}, actual: ${actualHost}`); } } } @@ -200,9 +201,9 @@ export class ApPersonService implements OnModuleInit { x.summary = truncate(x.summary, summaryLength); } - const idHost = this.utilityService.punyHost(x.id); - if (idHost !== expectHost) { - throw new Error('invalid Actor: id has different host'); + actualHost = this.utilityService.extractHost(x.id); + if (expectedHost !== actualHost) { + throw new Error(`invalid Actor: id has different host. expected: ${expectedHost}, actual: ${actualHost}`); } if (x.publicKey) { @@ -210,9 +211,9 @@ export class ApPersonService implements OnModuleInit { throw new Error('invalid Actor: publicKey.id is not a string'); } - const publicKeyIdHost = this.utilityService.punyHost(x.publicKey.id); - if (publicKeyIdHost !== expectHost) { - throw new Error('invalid Actor: publicKey.id has different host'); + actualHost = this.utilityService.extractHost(x.publicKey.id); + if (expectedHost !== actualHost) { + throw new Error(`invalid Actor: publicKey.id has different host. expected: ${expectedHost}, actual: ${actualHost}`); } } @@ -258,7 +259,7 @@ export class ApPersonService implements OnModuleInit { if (Array.isArray(img)) { img = img.find(item => item && item.url) ?? null; } - + // if we have an explicitly missing image, return an // explicitly-null set of values if ((img == null) || (typeof img === 'object' && img.url == null)) { @@ -296,8 +297,7 @@ export class ApPersonService implements OnModuleInit { public async createPerson(uri: string, resolver?: Resolver): Promise { if (typeof uri !== 'string') throw new Error('uri is not string'); - const host = this.utilityService.punyHost(uri); - if (host === this.utilityService.toPuny(this.config.host)) { + if (this.utilityService.isUriLocal(uri)) { throw new StatusError('cannot resolve local user', 400, 'cannot resolve local user'); } @@ -345,13 +345,14 @@ export class ApPersonService implements OnModuleInit { throw new Error('unexpected schema of person url: ' + url); } - if (this.utilityService.punyHost(url) !== this.utilityService.punyHost(person.id)) { - throw new Error(`person url <> uri host mismatch: ${url} <> ${person.id}`); + if (this.utilityService.extractHost(person.id) !== this.utilityService.extractHost(url)) { + throw new Error(`person id and url have different host: ${person.id} - ${url}`); } } // Create user let user: MiRemoteUser | null = null; + const host = this.utilityService.extractHost(uri); //#region カスタム絵文字取得 const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], host) @@ -542,8 +543,8 @@ export class ApPersonService implements OnModuleInit { throw new Error('unexpected schema of person url: ' + url); } - if (this.utilityService.punyHost(url) !== this.utilityService.punyHost(person.id)) { - throw new Error(`person url <> uri host mismatch: ${url} <> ${person.id}`); + if (this.utilityService.extractHost(person.id) !== this.utilityService.extractHost(url)) { + throw new Error(`person id and url have different host: ${person.id} - ${url}`); } } diff --git a/packages/backend/src/core/chart/charts/instance.ts b/packages/backend/src/core/chart/charts/instance.ts index 97f3bc6f2bd1..037c4dd08281 100644 --- a/packages/backend/src/core/chart/charts/instance.ts +++ b/packages/backend/src/core/chart/charts/instance.ts @@ -77,7 +77,7 @@ export default class InstanceChart extends Chart { // eslint-disa public async requestReceived(host: string): Promise { await this.commit({ 'requests.received': 1, - }, this.utilityService.toPuny(host)); + }, this.utilityService.normalizeHost(host)); } @bindThis @@ -85,7 +85,7 @@ export default class InstanceChart extends Chart { // eslint-disa await this.commit({ 'requests.succeeded': isSucceeded ? 1 : 0, 'requests.failed': isSucceeded ? 0 : 1, - }, this.utilityService.toPuny(host)); + }, this.utilityService.normalizeHost(host)); } @bindThis @@ -93,7 +93,7 @@ export default class InstanceChart extends Chart { // eslint-disa await this.commit({ 'users.total': 1, 'users.inc': 1, - }, this.utilityService.toPuny(host)); + }, this.utilityService.normalizeHost(host)); } @bindThis @@ -106,7 +106,7 @@ export default class InstanceChart extends Chart { // eslint-disa 'notes.diffs.renote': note.renoteId != null ? (isAdditional ? 1 : -1) : 0, 'notes.diffs.reply': note.replyId != null ? (isAdditional ? 1 : -1) : 0, 'notes.diffs.withFile': note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, - }, this.utilityService.toPuny(host)); + }, this.utilityService.normalizeHost(host)); } @bindThis @@ -115,7 +115,7 @@ export default class InstanceChart extends Chart { // eslint-disa 'following.total': isAdditional ? 1 : -1, 'following.inc': isAdditional ? 1 : 0, 'following.dec': isAdditional ? 0 : 1, - }, this.utilityService.toPuny(host)); + }, this.utilityService.normalizeHost(host)); } @bindThis @@ -124,7 +124,7 @@ export default class InstanceChart extends Chart { // eslint-disa 'followers.total': isAdditional ? 1 : -1, 'followers.inc': isAdditional ? 1 : 0, 'followers.dec': isAdditional ? 0 : 1, - }, this.utilityService.toPuny(host)); + }, this.utilityService.normalizeHost(host)); } @bindThis diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts index 75e4dda50594..289f267c4b3a 100644 --- a/packages/backend/src/core/entities/DriveFileEntityService.ts +++ b/packages/backend/src/core/entities/DriveFileEntityService.ts @@ -158,7 +158,7 @@ export class DriveFileEntityService { public async calcDriveUsageOfHost(host: string): Promise { const { sum } = await this.driveFilesRepository .createQueryBuilder('file') - .where('file.userHost = :host', { host: this.utilityService.toPuny(host) }) + .where('file.userHost = :host', { host: this.utilityService.normalizeHost(host) }) .andWhere('file.isLink = FALSE') .select('SUM(file.size)', 'sum') .getRawOne(); diff --git a/packages/backend/src/core/entities/InstanceEntityService.ts b/packages/backend/src/core/entities/InstanceEntityService.ts index c63f3ca5e42f..bbe48c0333e7 100644 --- a/packages/backend/src/core/entities/InstanceEntityService.ts +++ b/packages/backend/src/core/entities/InstanceEntityService.ts @@ -40,7 +40,7 @@ export class InstanceEntityService { followersCount: instance.followersCount, isNotResponding: instance.isNotResponding, isSuspended: instance.isSuspended, - isBlocked: this.utilityService.isBlockedHost(meta.blockedHosts, instance.host), + isBlocked: this.utilityService.isItemListedIn(instance.host, meta.blockedHosts), softwareName: instance.softwareName, softwareVersion: instance.softwareVersion, openRegistrations: instance.openRegistrations, @@ -48,8 +48,8 @@ export class InstanceEntityService { description: instance.description, maintainerName: instance.maintainerName, maintainerEmail: instance.maintainerEmail, - isSilenced: this.utilityService.isSilencedHost(meta.silencedHosts, instance.host), - isSensitiveMedia: this.utilityService.isSensitiveMediaHost(meta.sensitiveMediaHosts, instance.host), + isSilenced: this.utilityService.isItemListedIn(instance.host, meta.silencedHosts), + isSensitiveMedia: this.utilityService.isItemListedIn(instance.host, meta.sensitiveMediaHosts), iconUrl: instance.iconUrl, faviconUrl: instance.faviconUrl, themeColor: instance.themeColor, diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts index 6f0cd718ddbf..378b9e17c86e 100644 --- a/packages/backend/src/queue/processors/DeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts @@ -53,7 +53,7 @@ export class DeliverProcessorService { // ブロックしてたら中断 const meta = await this.metaService.fetch(); - if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.toPuny(host))) { + if (this.utilityService.isItemListedIn(host, meta.blockedHosts)) { return 'skip (blocked)'; } @@ -67,7 +67,7 @@ export class DeliverProcessorService { }); this.suspendedHostsCache.set(suspendedHosts); } - if (suspendedHosts.map(x => x.host).includes(this.utilityService.toPuny(host))) { + if (suspendedHosts.map(x => x.host).includes(this.utilityService.normalizeHost(host))) { return 'skip (suspended)'; } diff --git a/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts b/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts index b78229c648e3..1a9a2b717156 100644 --- a/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts @@ -76,7 +76,7 @@ export class ImportBlockingProcessorService { host: IsNull(), usernameLower: username.toLowerCase(), }) : await this.usersRepository.findOneBy({ - host: this.utilityService.toPuny(host), + host: this.utilityService.normalizeHost(host), usernameLower: username.toLowerCase(), }); diff --git a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts index 70c9f3a09679..7129bb40d0dc 100644 --- a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts @@ -76,7 +76,7 @@ export class ImportFollowingProcessorService { host: IsNull(), usernameLower: username.toLowerCase(), }) : await this.usersRepository.findOneBy({ - host: this.utilityService.toPuny(host), + host: this.utilityService.normalizeHost(host), usernameLower: username.toLowerCase(), }); diff --git a/packages/backend/src/queue/processors/ImportMutingProcessorService.ts b/packages/backend/src/queue/processors/ImportMutingProcessorService.ts index ec9d2b6c4ce5..6088904cbd77 100644 --- a/packages/backend/src/queue/processors/ImportMutingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportMutingProcessorService.ts @@ -71,7 +71,7 @@ export class ImportMutingProcessorService { host: IsNull(), usernameLower: username.toLowerCase(), }) : await this.usersRepository.findOneBy({ - host: this.utilityService.toPuny(host), + host: this.utilityService.normalizeHost(host), usernameLower: username.toLowerCase(), }); diff --git a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts index a5992c28c846..cdd070a1ad1a 100644 --- a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts @@ -90,7 +90,7 @@ export class ImportUserListsProcessorService { host: IsNull(), usernameLower: username.toLowerCase(), }) : await this.usersRepository.findOneBy({ - host: this.utilityService.toPuny(host!), + host: this.utilityService.normalizeHost(host!), usernameLower: username.toLowerCase(), }); diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index 70f3e30c5c49..1a50319383a3 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -65,11 +65,11 @@ export class InboxProcessorService implements OnApplicationShutdown { this.logger.debug(JSON.stringify(info, null, 2)); //#endregion - const host = this.utilityService.toPuny(new URL(signature.keyId).hostname); + const host = this.utilityService.extractHost(signature.keyId); // ブロックしてたら中断 const meta = await this.metaService.fetch(); - if (this.utilityService.isBlockedHost(meta.blockedHosts, host)) { + if (this.utilityService.isItemListedIn(host, meta.blockedHosts)) { return `Blocked request: ${host}`; } @@ -164,8 +164,8 @@ export class InboxProcessorService implements OnApplicationShutdown { } // ブロックしてたら中断 - const ldHost = this.utilityService.extractDbHost(authUser.user.uri); - if (this.utilityService.isBlockedHost(meta.blockedHosts, ldHost)) { + const ldHost = this.utilityService.extractHost(authUser.user.uri); + if (this.utilityService.isItemListedIn(ldHost, meta.blockedHosts)) { throw new Bull.UnrecoverableError(`Blocked request: ${ldHost}`); } } else { @@ -175,8 +175,8 @@ export class InboxProcessorService implements OnApplicationShutdown { // activity.idがあればホストが署名者のホストであることを確認する if (typeof activity.id === 'string') { - const signerHost = this.utilityService.extractDbHost(authUser.user.uri!); - const activityIdHost = this.utilityService.extractDbHost(activity.id); + const signerHost = this.utilityService.extractHost(authUser.user.uri!); + const activityIdHost = this.utilityService.extractHost(activity.id); if (signerHost !== activityIdHost) { throw new Bull.UnrecoverableError(`skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`); } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index 12bb914bee0c..779cd375cfc6 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -94,7 +94,7 @@ export default class extends Endpoint { // eslint- if (ps.host == null) { q.andWhere('emoji.host IS NOT NULL'); } else { - q.andWhere('emoji.host = :host', { host: this.utilityService.toPuny(ps.host) }); + q.andWhere('emoji.host = :host', { host: this.utilityService.normalizeHost(ps.host) }); } if (ps.query) { diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index 556e291025d9..6c4e835fac4e 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -36,7 +36,7 @@ export default class extends Endpoint { // eslint- private fetchInstanceMetadataService: FetchInstanceMetadataService, ) { super(meta, paramDef, async (ps, me) => { - const instance = await this.instancesRepository.findOneBy({ host: this.utilityService.toPuny(ps.host) }); + const instance = await this.instancesRepository.findOneBy({ host: this.utilityService.normalizeHost(ps.host) }); if (instance == null) { throw new Error('instance not found'); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index 0bcdc2a4b81e..e2f1ff6efe1c 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -40,7 +40,7 @@ export default class extends Endpoint { // eslint- private moderationLogService: ModerationLogService, ) { super(meta, paramDef, async (ps, me) => { - const instance = await this.instancesRepository.findOneBy({ host: this.utilityService.toPuny(ps.host) }); + const instance = await this.instancesRepository.findOneBy({ host: this.utilityService.normalizeHost(ps.host) }); if (instance == null) { throw new Error('instance not found'); diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index cc7e24515688..889c2193335c 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -114,7 +114,7 @@ export default class extends Endpoint { // eslint- private async fetchAny(uri: string, me: MiLocalUser | null | undefined): Promise | null> { // ブロックしてたら中断 const fetchedMeta = await this.metaService.fetch(); - if (this.utilityService.isBlockedHost(fetchedMeta.blockedHosts, this.utilityService.extractDbHost(uri))) return null; + if (this.utilityService.isItemListedIn(this.utilityService.extractHost(uri), fetchedMeta.blockedHosts)) return null; let local = await this.mergePack(me, ...await Promise.all([ this.apDbResolverService.getUserFromApId(uri), @@ -122,7 +122,7 @@ export default class extends Endpoint { // eslint- ])); if (local != null) return local; - const host = this.utilityService.extractDbHost(uri); + const host = this.utilityService.extractHost(uri); // local object, not found in db? fail if (this.utilityService.isSelfHost(host)) return null; diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index 2972861a4bae..3133ce7e49de 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -41,7 +41,7 @@ export default class extends Endpoint { // eslint- ) { super(meta, paramDef, async (ps, me) => { const instance = await this.instancesRepository - .findOneBy({ host: this.utilityService.toPuny(ps.host) }); + .findOneBy({ host: this.utilityService.normalizeHost(ps.host) }); return instance ? await this.instanceEntityService.pack(instance, me) : null; }); diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index a8b4319a61c1..397487b678df 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -87,7 +87,7 @@ export default class extends Endpoint { // eslint- super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy(ps.userId != null ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: this.utilityService.toPunyNullable(ps.host) ?? IsNull() }); + : { usernameLower: ps.username!.toLowerCase(), host: ps.host ? this.utilityService.normalizeHost(ps.host) : IsNull() }); if (user == null) { throw new ApiError(meta.errors.noSuchUser); diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index ee2e17a0e6a6..1fd94c4bdcca 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -99,7 +99,7 @@ export default class extends Endpoint { // eslint- super(meta, paramDef, async (ps, me) => { const user = await this.usersRepository.findOneBy(ps.userId != null ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: this.utilityService.toPunyNullable(ps.host) ?? IsNull() }); + : { usernameLower: ps.username!.toLowerCase(), host: ps.host ? this.utilityService.normalizeHost(ps.host) : IsNull() }); if (user == null) { throw new ApiError(meta.errors.noSuchUser); From c4352a223b690e83bb03f3878af2715987ff9beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=82=8F=E3=82=8F=E3=82=8F=E3=81=A8=E3=83=BC?= =?UTF-8?q?=E3=81=AB=E3=82=85?= <17376330+u1-liquid@users.noreply.github.com> Date: Sat, 28 Dec 2024 11:39:09 +0900 Subject: [PATCH 2/2] Update InboxProcessorService.ts --- packages/backend/src/queue/processors/InboxProcessorService.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index 1a50319383a3..beef889fc9dc 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -3,7 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { URL } from 'node:url'; import { Injectable, OnApplicationShutdown } from '@nestjs/common'; import httpSignature from '@peertube/http-signature'; import * as Bull from 'bullmq';