From 6432033c3294a134b50f2803158832ed1ea443eb Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:00:38 +0900 Subject: [PATCH] wip --- locales/index.d.ts | 12 ++++++++++++ locales/ja-JP.yml | 4 ++++ ...729333924409-signinRequiredForShowContents.js | 16 ++++++++++++++++ .../src/core/entities/NoteEntityService.ts | 4 ++++ .../src/core/entities/UserEntityService.ts | 1 + packages/backend/src/models/User.ts | 5 +++++ packages/backend/src/models/json-schema/user.ts | 4 ++++ .../backend/src/server/api/endpoints/i/update.ts | 2 ++ .../src/server/api/endpoints/notes/show.ts | 10 ++++++++++ .../src/server/api/endpoints/users/notes.ts | 6 ++++++ .../src/server/web/ClientServerService.ts | 11 +++++++---- packages/frontend/src/pages/settings/privacy.vue | 6 ++++++ packages/misskey-js/src/autogen/types.ts | 2 ++ 13 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 packages/backend/migration/1729333924409-signinRequiredForShowContents.js diff --git a/locales/index.d.ts b/locales/index.d.ts index b5af5909a3..6d147d6f34 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5190,6 +5190,18 @@ export interface Locale extends ILocale { * 名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。 */ "yourNameContainsProhibitedWordsDescription": string; + "_accountSettings": { + /** + * コンテンツの閲覧にログインを必須にする + */ + "signinRequiredForShowContents": string; + /** + * あなたのプロフィールやノートなどの作成したコンテンツの閲覧にログイン必須にします。 + * クローラーから情報を収集されるのを防ぐ効果が期待できます。 + * URLのプレビューや、コンテンツの埋め込みも使用不可になります。 + */ + "signinRequiredForShowContentsDescription": string; + }; "_abuseUserReport": { /** * 転送 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index c448d4d50a..2a6768b96d 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1294,6 +1294,10 @@ prohibitedWordsForNameOfUserDescription: "このリストに含まれる文字 yourNameContainsProhibitedWords: "変更しようとした名前に禁止された文字列が含まれています" yourNameContainsProhibitedWordsDescription: "名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。" +_accountSettings: + signinRequiredForShowContents: "コンテンツの閲覧にログインを必須にする" + signinRequiredForShowContentsDescription: "あなたのプロフィールやノートなどの作成したコンテンツの閲覧にログイン必須にします。\nクローラーから情報を収集されるのを防ぐ効果が期待できます。\nURLのプレビューや、コンテンツの埋め込みも使用不可になります。" + _abuseUserReport: forward: "転送" forwardDescription: "匿名のシステムアカウントとして、リモートサーバーに通報を転送します。" diff --git a/packages/backend/migration/1729333924409-signinRequiredForShowContents.js b/packages/backend/migration/1729333924409-signinRequiredForShowContents.js new file mode 100644 index 0000000000..bf77dd0daa --- /dev/null +++ b/packages/backend/migration/1729333924409-signinRequiredForShowContents.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SigninRequiredForShowContents1729333924409 { + name = 'SigninRequiredForShowContents1729333924409' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "signinRequiredForShowContents" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "signinRequiredForShowContents"`); + } +} diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 3e1f094fce..22e3263c9f 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -149,6 +149,10 @@ export class NoteEntityService implements OnModuleInit { } } + if (packedNote.user.signinRequiredForShowContents && meId == null) { + hide = true; + } + if (hide) { packedNote.visibleUserIds = undefined; packedNote.fileIds = []; diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index c9939adf11..9c62f4e425 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -490,6 +490,7 @@ export class UserEntityService implements OnModuleInit { }))) : [], isBot: user.isBot, isCat: user.isCat, + signinRequiredForShowContents: user.signinRequiredForShowContents === false ? undefined : true, instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? { name: instance.name, softwareName: instance.softwareName, diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 805a1e75ae..a2affb698f 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -202,6 +202,11 @@ export class MiUser { }) public isHibernated: boolean; + @Column('boolean', { + default: false, + }) + public signinRequiredForShowContents: boolean; + // アカウントが削除されたかどうかのフラグだが、完全に削除される際は物理削除なので実質削除されるまでの「削除が進行しているかどうか」のフラグ @Column('boolean', { default: false, diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 9cffd680f2..8e0d8440a9 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -115,6 +115,10 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + signinRequiredForShowContents: { + type: 'boolean', + nullable: false, optional: true, + }, instance: { type: 'object', nullable: false, optional: true, diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 0b35005a87..3ae3f9160b 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -179,6 +179,7 @@ export const paramDef = { autoAcceptFollowed: { type: 'boolean' }, noCrawle: { type: 'boolean' }, preventAiLearning: { type: 'boolean' }, + signinRequiredForShowContents: { type: 'boolean' }, isBot: { type: 'boolean' }, isCat: { type: 'boolean' }, injectFeaturedNote: { type: 'boolean' }, @@ -334,6 +335,7 @@ export default class extends Endpoint { // eslint- if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning; + if (typeof ps.signinRequiredForShowContents === 'boolean') updates.signinRequiredForShowContents = ps.signinRequiredForShowContents; if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat; if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index adcda30a7d..d8b6a6ff5f 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -26,6 +26,12 @@ export const meta = { code: 'NO_SUCH_NOTE', id: '24fcbfc6-2e37-42b6-8388-c29b3861a08d', }, + + signinRequired: { + message: 'Signin required.', + code: 'SIGNIN_REQUIRED', + id: '8e75455b-738c-471d-9f80-62693f33372e', + }, }, } as const; @@ -49,6 +55,10 @@ export default class extends Endpoint { // eslint- throw err; }); + if (note.user!.signinRequiredForShowContents && me == null) { + throw new ApiError(meta.errors.signinRequired); + } + return await this.noteEntityService.pack(note, me, { detail: true, }); diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 7fc11ba369..e9c334057e 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -42,6 +42,12 @@ export const meta = { code: 'BOTH_WITH_REPLIES_AND_WITH_FILES', id: '91c8cb9f-36ed-46e7-9ca2-7df96ed6e222', }, + + signinRequired: { + message: 'Signin required.', + code: 'SIGNIN_REQUIRED', + id: 'd1588a9e-4b4d-4c07-807f-16f1486577a2', + }, }, } as const; diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index c9c29e42a8..2fd5fbd397 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -601,12 +601,15 @@ export class ClientServerService { fastify.get<{ Params: { note: string; } }>('/notes/:note', async (request, reply) => { vary(reply.raw, 'Accept'); - const note = await this.notesRepository.findOneBy({ - id: request.params.note, - visibility: In(['public', 'home']), + const note = await this.notesRepository.findOne({ + where: { + id: request.params.note, + visibility: In(['public', 'home']), + }, + relations: ['user'], }); - if (note) { + if (note && !note.user!.signinRequiredForShowContents) { const _note = await this.noteEntityService.pack(note); const profile = await this.userProfilesRepository.findOneByOrFail({ userId: note.userId }); reply.header('Cache-Control', 'public, max-age=15'); diff --git a/packages/frontend/src/pages/settings/privacy.vue b/packages/frontend/src/pages/settings/privacy.vue index d418be624e..3e3e886b5e 100644 --- a/packages/frontend/src/pages/settings/privacy.vue +++ b/packages/frontend/src/pages/settings/privacy.vue @@ -43,6 +43,10 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.makeExplorable }} + + {{ i18n.ts._accountSettings.signinRequiredForShowContents }} + +
@@ -90,6 +94,7 @@ const autoAcceptFollowed = ref($i.autoAcceptFollowed); const noCrawle = ref($i.noCrawle); const preventAiLearning = ref($i.preventAiLearning); const isExplorable = ref($i.isExplorable); +const signinRequiredForShowContents = ref($i.signinRequiredForShowContents ?? false); const hideOnlineStatus = ref($i.hideOnlineStatus); const publicReactions = ref($i.publicReactions); const followingVisibility = ref($i.followingVisibility); @@ -107,6 +112,7 @@ function save() { noCrawle: !!noCrawle.value, preventAiLearning: !!preventAiLearning.value, isExplorable: !!isExplorable.value, + signinRequiredForShowContents: !!signinRequiredForShowContents.value, hideOnlineStatus: !!hideOnlineStatus.value, publicReactions: !!publicReactions.value, followingVisibility: followingVisibility.value, diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 698c08826a..d31a30b524 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -3736,6 +3736,7 @@ export type components = { }[]; isBot?: boolean; isCat?: boolean; + signinRequiredForShowContents?: boolean; instance?: { name: string | null; softwareName: string | null; @@ -19844,6 +19845,7 @@ export type operations = { autoAcceptFollowed?: boolean; noCrawle?: boolean; preventAiLearning?: boolean; + signinRequiredForShowContents?: boolean; isBot?: boolean; isCat?: boolean; injectFeaturedNote?: boolean;