From e6eec4cb972d6866382c19539847d1151010e093 Mon Sep 17 00:00:00 2001 From: pen <121443048+penginn-net@users.noreply.github.com> Date: Sat, 30 Nov 2024 23:44:59 +0900 Subject: [PATCH] =?UTF-8?q?Fix:=20Person=E3=81=AEserchableBy=E3=81=8C?= =?UTF-8?q?=E6=AD=A3=E3=81=97=E3=81=8F=E9=80=A3=E5=90=88=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=81=A6=E3=81=84=E3=81=AA=E3=81=84=E3=81=AE=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=20(#556)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG_YOJO.md | 2 + .../src/core/activitypub/ApAudienceService.ts | 18 +------- .../src/core/activitypub/ApRendererService.ts | 4 +- .../src/core/activitypub/misc/searchableBy.ts | 44 +++++++++++++++++++ .../core/activitypub/models/ApNoteService.ts | 3 +- .../activitypub/models/ApPersonService.ts | 19 +++----- packages/backend/src/core/activitypub/type.ts | 1 + 7 files changed, 60 insertions(+), 31 deletions(-) create mode 100644 packages/backend/src/core/activitypub/misc/searchableBy.ts diff --git a/CHANGELOG_YOJO.md b/CHANGELOG_YOJO.md index 72015778cd..714306c1ca 100644 --- a/CHANGELOG_YOJO.md +++ b/CHANGELOG_YOJO.md @@ -1,8 +1,10 @@ ## 1.2.0 + ### General - Fix: ノートを編集する時に検索許可範囲を記憶する [#558](https://github.com/yojo-art/cherrypick/pull/558) ### Server +- Fix: PersonのserchableByが正しく連合できていないのを修正[#556](https://github.com/yojo-art/cherrypick/pull/556) - Enhance: `/users/${id}`に`Accept: application/ld+json`ではないリクエストが来たとき`/@${username}`にリダイレクトするように [#554](https://github.com/yojo-art/cherrypick/pull/554) ## 1.1.0 diff --git a/packages/backend/src/core/activitypub/ApAudienceService.ts b/packages/backend/src/core/activitypub/ApAudienceService.ts index 480cc7a14e..5a5a76f7d6 100644 --- a/packages/backend/src/core/activitypub/ApAudienceService.ts +++ b/packages/backend/src/core/activitypub/ApAudienceService.ts @@ -8,7 +8,6 @@ import promiseLimit from 'promise-limit'; import type { MiRemoteUser, MiUser } from '@/models/User.js'; import { concat, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; -import { searchableTypes } from '@/types.js'; import { getApIds } from './type.js'; import { ApPersonService } from './models/ApPersonService.js'; import type { ApObject } from './type.js'; @@ -73,22 +72,7 @@ export class ApAudienceService { visibleUsers: mentionedUsers, }; } - public async parseSearchableBy (actor: MiRemoteUser, searchableBy?: string[]): Promise<'public' | 'followersAndReacted' | 'reactedOnly' | 'private' | null> { - if (!searchableBy) { - return null; - } - console.log(searchableBy); - if (searchableBy.includes('https://www.w3.org/ns/activitystreams#Public')) { - return 'public'; - } else if (actor.followersUri && searchableBy.includes(actor.followersUri)) { - return 'followersAndReacted'; - } else if (searchableBy.includes(actor.uri)) { - return 'reactedOnly'; - } else if (searchableBy.includes('as:Limited') || searchableBy.includes('kmyblue:Limited')) { - return 'private'; - } - return null; - } + @bindThis private groupingAudience(ids: string[], actor: MiRemoteUser): GroupedAudience { const groups: GroupedAudience = { diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 0f808d9aae..44db51f305 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -32,6 +32,7 @@ import { searchableTypes } from '@/types.js'; import { JsonLdService } from './JsonLdService.js'; import { ApMfmService } from './ApMfmService.js'; import { CONTEXT } from './misc/contexts.js'; +import { toSerchableByProperty } from './misc/searchableBy.js'; import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IApReversi, IBlock, ICreate, IDelete, IFlag, IFollow, IInvite, IJoin, IKey, ILeave, ILike, IMove, IObject, IPost, IQuestion, IRead, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js'; @Injectable() @@ -541,6 +542,7 @@ export class ApRendererService { ]; const keypair = await this.userKeypairService.getUserKeypair(user.id); + const searchableByData = toSerchableByProperty(this.config.url, user.id, user.searchableBy); const person: any = { type: isSystem ? 'Application' : user.isBot ? 'Service' : 'Person', @@ -564,7 +566,7 @@ export class ApRendererService { manuallyApprovesFollowers: user.isLocked, discoverable: user.isExplorable, indexable: user.isIndexable, - searchableBy: [`${this.config.url}/users/${user.id}`], + ...( searchableByData ? { searchableBy: searchableByData } : {}), publicKey: this.renderKey(user, keypair, '#main-key'), isCat: user.isCat, attachment: attachment.length ? attachment : undefined, diff --git a/packages/backend/src/core/activitypub/misc/searchableBy.ts b/packages/backend/src/core/activitypub/misc/searchableBy.ts new file mode 100644 index 0000000000..090f7e3115 --- /dev/null +++ b/packages/backend/src/core/activitypub/misc/searchableBy.ts @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project, yojo-art team + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export function parseSearchableByFromTags(tags: string[]): 'public' | 'followersAndReacted' | 'reactedOnly' | 'private' | null { + if (tags.includes('searchable_by_all_users')) return 'public'; + if (tags.includes('searchable_by_followers_only')) return 'followersAndReacted'; + if (tags.includes('searchable_by_reacted_users_only')) return 'followersAndReacted'; + if (tags.includes('searchable_by_nobody')) return 'private'; + return null; +} + +export function parseSearchableByFromProperty (uri: string, followersUri?: string, searchableBy?: string[]): 'public' | 'followersAndReacted' | 'reactedOnly' | 'private' | null { + if (!searchableBy) { + return null; + } + + if (searchableBy.includes('https://www.w3.org/ns/activitystreams#Public')) { + return 'public'; + } else if (followersUri && searchableBy.includes(followersUri)) { + return 'followersAndReacted'; + } else if (searchableBy.includes(uri)) { + return 'reactedOnly'; + } else if (searchableBy.includes('as:Limited') || searchableBy.includes('kmyblue:Limited')) { + return 'private'; + } + return null; +} + +export function toSerchableByProperty (configUrl: string, userId: string, serchableType: 'public' | 'followersAndReacted' | 'reactedOnly' | 'private' | null) : string[] | null { + switch (serchableType) { + case 'public' : + return ['https://www.w3.org/ns/activitystreams#Public']; + case 'followersAndReacted' : + return [`${configUrl}/${userId}/followers`]; + case 'reactedOnly' : + return [`${configUrl}/users/${userId}`]; + case 'private' : + return ['as:Limited', 'kmyblue:Limited']; + default : + return null; + } +} diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index e5afc57a81..5c725be8b5 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -31,6 +31,7 @@ import { ApMfmService } from '../ApMfmService.js'; import { ApDbResolverService } from '../ApDbResolverService.js'; import { ApResolverService } from '../ApResolverService.js'; import { ApAudienceService } from '../ApAudienceService.js'; +import { parseSearchableByFromProperty } from '../misc/searchableBy.js'; import { ApPersonService } from './ApPersonService.js'; import { extractApHashtags } from './tag.js'; import { ApMentionService } from './ApMentionService.js'; @@ -209,7 +210,7 @@ export class ApNoteService { } const noteAudience = await this.apAudienceService.parseAudience(actor, note.to, note.cc, resolver); - const searchableBy = await this.apAudienceService.parseSearchableBy(actor, note.searchableBy); + const searchableBy = parseSearchableByFromProperty(actor.uri, actor.followersUri ?? undefined, note.searchableBy); let visibility = noteAudience.visibility; const visibleUsers = noteAudience.visibleUsers; diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 6665d868e7..a4d45fb3f0 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -39,8 +39,8 @@ import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.j import type { AccountMoveService } from '@/core/AccountMoveService.js'; import { checkHttps } from '@/misc/check-https.js'; import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; -import { searchableTypes } from '@/types.js'; import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js'; +import { parseSearchableByFromTags, parseSearchableByFromProperty } from '../misc/searchableBy.js'; import { extractApHashtags } from './tag.js'; import type { OnModuleInit } from '@nestjs/common'; import type { ApNoteService } from './ApNoteService.js'; @@ -410,7 +410,9 @@ export class ApPersonService implements OnModuleInit { alsoKnownAs: person.alsoKnownAs, isExplorable: person.discoverable, isIndexable: person.indexable ?? true, - searchableBy: this.getSearchableType(tags), + searchableBy: person.searchableBy ? + parseSearchableByFromProperty(uri, person.followers ? getApId(person.followers) : undefined, person.searchableBy) : + parseSearchableByFromTags(tags), username: person.preferredUsername, usernameLower: person.preferredUsername?.toLowerCase(), host, @@ -656,7 +658,9 @@ export class ApPersonService implements OnModuleInit { const role_policy = await this.roleService.getUserPolicies(exist.id); const updates = { lastFetchedAt: new Date(), - searchableBy: this.getSearchableType(tags), + searchableBy: person.searchableBy ? + parseSearchableByFromProperty(uri, person.followers ? getApId(person.followers) : undefined, person.searchableBy) : + parseSearchableByFromTags(tags), inbox: person.inbox, sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox, outbox: typeof person.outbox === 'string' ? person.outbox : null, @@ -1006,13 +1010,4 @@ export class ApPersonService implements OnModuleInit { return false; } - - @bindThis - private getSearchableType(tags: string[]): 'public' | 'followersAndReacted' | 'reactedOnly' | 'private' | null { - if (tags.includes('searchable_by_all_users')) return 'public'; - if (tags.includes('searchable_by_followers_only')) return 'followersAndReacted'; - if (tags.includes('searchable_by_reacted_users_only')) return 'followersAndReacted'; - if (tags.includes('searchable_by_nobody')) return 'private'; - return null; - } } diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index 061621f73b..e2888779c0 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -198,6 +198,7 @@ export interface IActor extends IObject { alsoKnownAs?: string[]; discoverable?: boolean; indexable?: boolean; + searchableBy?: string[]; inbox: string; sharedInbox?: string; // 後方互換性のため publicKey?: {