From bc0c53b92b0ceba7617d9d02f54bbf7ccfc933d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:44:57 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix(frontend):=20Captcha=20=E3=81=AE?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=83=8F=E3=83=B3=E3=83=89=E3=83=AA?= =?UTF-8?q?=E3=83=B3=E3=82=B0=20(#14811)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): Captcha のエラーハンドリングを修正 (MisskeyIO#768) (cherry picked from commit 88912d0f8c63a762fbb1d43e5c1abf4fd9fc05d4) * Update Changelog * typo --------- Co-authored-by: riku6460 <17585784+riku6460@users.noreply.github.com> --- CHANGELOG.md | 2 ++ packages/frontend/src/components/MkCaptcha.vue | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04ae102227..c815e65ab3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751) - Enhance: ドライブでソートができるように - Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正 +- Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正 + (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768) ### Server - diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue index 82fc89e51c..264cf9af06 100644 --- a/packages/frontend/src/components/MkCaptcha.vue +++ b/packages/frontend/src/components/MkCaptcha.vue @@ -117,8 +117,8 @@ async function requestRender() { sitekey: props.sitekey, theme: defaultStore.state.darkMode ? 'dark' : 'light', callback: callback, - 'expired-callback': callback, - 'error-callback': callback, + 'expired-callback': () => callback(undefined), + 'error-callback': () => callback(undefined), }); } else if (props.provider === 'mcaptcha' && props.instanceUrl && props.sitekey) { const { default: Widget } = await import('@mcaptcha/vanilla-glue'); From 5c79d8db208da1fd7c5bc4900090c3d7b9512196 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:49:29 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=E3=83=8E=E3=83=BC=E3=83=88?= =?UTF-8?q?=E3=81=AE=E9=96=B2=E8=A6=A7=E3=81=AB=E3=83=AD=E3=82=B0=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E5=BF=85=E9=A0=88=E3=81=AB=E3=81=99=E3=82=8B=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=20(#14799)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * wip * wip * Update packages/frontend/src/pages/note.vue Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> * wip * Update WebhookTestService.ts * Update privacy.vue * wip * rename * Update locales/ja-JP.yml Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> * :art: * wip --------- Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> --- CHANGELOG.md | 2 +- locales/index.d.ts | 26 +++++++++++++++++++ locales/ja-JP.yml | 8 ++++++ ...333924409-signinRequiredForShowContents.js | 16 ++++++++++++ .../backend/src/core/WebhookTestService.ts | 1 + .../src/core/activitypub/ApRendererService.ts | 1 + .../src/core/activitypub/misc/contexts.ts | 1 + .../activitypub/models/ApPersonService.ts | 1 + packages/backend/src/core/activitypub/type.ts | 1 + .../src/core/entities/NoteEntityService.ts | 4 +++ .../src/core/entities/UserEntityService.ts | 1 + packages/backend/src/models/User.ts | 5 ++++ .../backend/src/models/json-schema/user.ts | 4 +++ .../backend/src/server/api/GetterService.ts | 11 ++++++++ .../src/server/api/endpoints/i/update.ts | 2 ++ .../src/server/api/endpoints/notes/show.ts | 12 ++++++++- .../src/server/api/endpoints/users/notes.ts | 6 +++++ .../src/server/web/ClientServerService.ts | 11 +++++--- .../src/components/MkFollowButton.vue | 4 +-- packages/frontend/src/components/MkNote.vue | 8 +++--- .../src/components/MkNoteDetailed.vue | 10 +++---- packages/frontend/src/components/MkPoll.vue | 6 ++--- packages/frontend/src/os.ts | 18 +++++++------ packages/frontend/src/pages/not-found.vue | 2 +- packages/frontend/src/pages/note.vue | 6 +++++ .../frontend/src/pages/settings/privacy.vue | 19 +++++++++++++- packages/frontend/src/scripts/please-login.ts | 14 ++++++---- packages/misskey-js/src/autogen/types.ts | 2 ++ 28 files changed, 167 insertions(+), 35 deletions(-) create mode 100644 packages/backend/migration/1729333924409-signinRequiredForShowContents.js diff --git a/CHANGELOG.md b/CHANGELOG.md index c815e65ab3..4d8c8ded3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## Unreleased ### General -- +- Feat: コンテンツの表示にログインを必須にできるように ### Client - Enhance: Bull DashboardでRelationship Queueの状態も確認できるように diff --git a/locales/index.d.ts b/locales/index.d.ts index fb010d9353..e002540307 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5190,6 +5190,32 @@ export interface Locale extends ILocale { * 名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。 */ "yourNameContainsProhibitedWordsDescription": string; + /** + * 投稿者により、表示にはログインが必要と設定されています + */ + "thisContentsAreMarkedAsSigninRequiredByAuthor": string; + /** + * ロックダウン + */ + "lockdown": string; + "_accountSettings": { + /** + * コンテンツの表示にログインを必須にする + */ + "requireSigninToViewContents": string; + /** + * あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。 + */ + "requireSigninToViewContentsDescription1": string; + /** + * URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。 + */ + "requireSigninToViewContentsDescription2": string; + /** + * リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。 + */ + "requireSigninToViewContentsDescription3": string; + }; "_abuseUserReport": { /** * 転送 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index c241a9e560..f3f7e5c77f 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1293,6 +1293,14 @@ prohibitedWordsForNameOfUser: "禁止ワード(ユーザーの名前)" prohibitedWordsForNameOfUserDescription: "このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。" yourNameContainsProhibitedWords: "変更しようとした名前に禁止された文字列が含まれています" yourNameContainsProhibitedWordsDescription: "名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。" +thisContentsAreMarkedAsSigninRequiredByAuthor: "投稿者により、表示にはログインが必要と設定されています" +lockdown: "ロックダウン" + +_accountSettings: + requireSigninToViewContents: "コンテンツの表示にログインを必須にする" + requireSigninToViewContentsDescription1: "あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。" + requireSigninToViewContentsDescription2: "URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。" + requireSigninToViewContentsDescription3: "リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。" _abuseUserReport: forward: "転送" diff --git a/packages/backend/migration/1729333924409-signinRequiredForShowContents.js b/packages/backend/migration/1729333924409-signinRequiredForShowContents.js new file mode 100644 index 0000000000..5d4d1fcce2 --- /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 "requireSigninToViewContents" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "requireSigninToViewContents"`); + } +} diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index 55c8a52705..254d961040 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -83,6 +83,7 @@ function generateDummyUser(override?: Partial): MiUser { isExplorable: true, isHibernated: false, isDeleted: false, + requireSigninToViewContents: false, emojis: [], score: 0, host: null, diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index fba8947f03..8235d7ba30 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -495,6 +495,7 @@ export class ApRendererService { summary: profile.description ? this.mfmService.toHtml(mfm.parse(profile.description)) : null, _misskey_summary: profile.description, _misskey_followedMessage: profile.followedMessage, + _misskey_requireSigninToViewContents: user.requireSigninToViewContents, icon: avatar ? this.renderImage(avatar) : null, image: banner ? this.renderImage(banner) : null, tag, diff --git a/packages/backend/src/core/activitypub/misc/contexts.ts b/packages/backend/src/core/activitypub/misc/contexts.ts index 3dd85b9b86..447f7ef3db 100644 --- a/packages/backend/src/core/activitypub/misc/contexts.ts +++ b/packages/backend/src/core/activitypub/misc/contexts.ts @@ -555,6 +555,7 @@ const extension_context_definition = { '_misskey_votes': 'misskey:_misskey_votes', '_misskey_summary': 'misskey:_misskey_summary', '_misskey_followedMessage': 'misskey:_misskey_followedMessage', + '_misskey_requireSigninToViewContents': 'misskey:_misskey_requireSigninToViewContents', 'isCat': 'misskey:isCat', // vcard vcard: 'http://www.w3.org/2006/vcard/ns#', diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 73281078e5..c7915ed94f 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -356,6 +356,7 @@ export class ApPersonService implements OnModuleInit { tags, isBot, isCat: (person as any).isCat === true, + requireSigninToViewContents: (person as any).requireSigninToViewContents === true, emojis, })) as MiRemoteUser; diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index 154965b9d5..8a860335fa 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -14,6 +14,7 @@ export interface IObject { summary?: string; _misskey_summary?: string; _misskey_followedMessage?: string | null; + _misskey_requireSigninToViewContents?: boolean; published?: string; cc?: ApObject; to?: ApObject; diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 3e1f094fce..62016936a2 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.requireSigninToViewContents && 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..747ffc780f 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, + requireSigninToViewContents: user.requireSigninToViewContents === 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..6fcff77854 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 requireSigninToViewContents: 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..817f8e9292 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, }, + requireSigninToViewContents: { + type: 'boolean', + nullable: false, optional: true, + }, instance: { type: 'object', nullable: false, optional: true, diff --git a/packages/backend/src/server/api/GetterService.ts b/packages/backend/src/server/api/GetterService.ts index bff3ab96f3..444e6db744 100644 --- a/packages/backend/src/server/api/GetterService.ts +++ b/packages/backend/src/server/api/GetterService.ts @@ -39,6 +39,17 @@ export class GetterService { return note; } + @bindThis + public async getNoteWithUser(noteId: MiNote['id']) { + const note = await this.notesRepository.findOne({ where: { id: noteId }, relations: ['user'] }); + + if (note == null) { + throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); + } + + return note; + } + /** * Get user for API processing */ diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 0b35005a87..6680c96f3f 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' }, + requireSigninToViewContents: { 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.requireSigninToViewContents === 'boolean') updates.requireSigninToViewContents = ps.requireSigninToViewContents; 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..11839bce36 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; @@ -44,11 +50,15 @@ export default class extends Endpoint { // eslint- private getterService: GetterService, ) { super(meta, paramDef, async (ps, me) => { - const note = await this.getterService.getNote(ps.noteId).catch(err => { + const note = await this.getterService.getNoteWithUser(ps.noteId).catch(err => { if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); throw err; }); + if (note.user!.requireSigninToViewContents && 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..4860ef3e12 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!.requireSigninToViewContents) { 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/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index ccea7cd453..cc07175907 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -37,13 +37,13 @@ SPDX-License-Identifier: AGPL-3.0-only