diff --git a/CHANGELOG.md b/CHANGELOG.md index 421237c32..7e25ef335 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ -## Unreleased +## 2024.10.2 ### General - Feat: コンテンツの表示にログインを必須にできるように +- Feat: 過去のノートを非公開化/フォロワーのみ表示可能にできるように ### Client - Enhance: Bull DashboardでRelationship Queueの状態も確認できるように @@ -14,8 +15,8 @@ - Fix: デッキのタイムラインカラムで「センシティブなファイルを含むノートを表示」設定が使用できなかった問題を修正 ### Server -- - +- Fix: Nested proxy requestsを検出した際にブロックするように + [ghsa-gq5q-c77c-v236](https://github.com/misskey-dev/misskey/security/advisories/ghsa-gq5q-c77c-v236) ## 2024.10.1 diff --git a/locales/en-US.yml b/locales/en-US.yml index 1fbfc5851..a8a5bcce2 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -947,6 +947,9 @@ oneHour: "One hour" oneDay: "One day" oneWeek: "One week" oneMonth: "One month" +threeMonths: "3 months" +oneYear: "1 year" +threeDays: "3 days" reflectMayTakeTime: "It may take some time for this to be reflected." failedToFetchAccountInformation: "Could not fetch account information" rateLimitExceeded: "Rate limit exceeded" @@ -1295,6 +1298,27 @@ passkeyVerificationFailed: "Passkey verification has failed." passkeyVerificationSucceededButPasswordlessLoginDisabled: "Passkey verification has succeeded but password-less login is disabled." messageToFollower: "Message to followers" target: "Target" +testCaptchaWarning: "This is a feature for CAPTCHA testing. **Do not use in production environment.**" +prohibitedWordsForNameOfUser: "Prohibited words (for user names)" +prohibitedWordsForNameOfUserDescription: "If a user's name contains any string in this list, the name change will be rejected. Users with moderator privileges are not affected by this restriction." +yourNameContainsProhibitedWords: "The name you attempted to change contains prohibited strings" +yourNameContainsProhibitedWordsDescription: "Your name contains prohibited strings. If you want to use this name, please contact the server administrator." +thisContentsAreMarkedAsSigninRequiredByAuthor: "The author has set this content to require login to view" +lockdown: "Lockdown" + +_accountSettings: + requireSigninToViewContents: "Require login to view contents" + requireSigninToViewContentsDescription1: "Requires login to view all content you create, such as notes. This can help prevent crawlers from collecting information." + requireSigninToViewContentsDescription2: "URL previews (OGP), web page embeds, and note quotes from servers that don't support these features will also be unavailable." + requireSigninToViewContentsDescription3: "These restrictions may not apply to content federated to remote servers." + makeNotesFollowersOnlyBefore: "Make past notes visible to followers only" + makeNotesFollowersOnlyBeforeDescription: "While this feature is enabled, notes that are older than the specified date/time or have passed the specified time period will be visible to followers only. When disabled, notes will return to their original visibility settings." + makeNotesHiddenBefore: "Make past notes private" + makeNotesHiddenBeforeDescription: "While this feature is enabled, notes that are older than the specified date/time or have passed the specified time period will be visible only to yourself (private). When disabled, notes will return to their original visibility settings." + mayNotEffectForFederatedNotes: "This may not affect notes that have been federated to remote servers." + notesHavePassedSpecifiedPeriod: "Notes that have passed the specified time period" + notesOlderThanSpecifiedDateAndTime: "Notes older than the specified date and time" + _mfm: intro: "MFM is a markup language used on Misskey, Sharkey, Firefish, Akkoma, and more that can be used in many places. Here you can view a list of all available MFM syntax." dummy: "Welcome to Pari Cafe" diff --git a/locales/index.d.ts b/locales/index.d.ts index d0825231a..f47722581 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -3806,6 +3806,18 @@ export interface Locale extends ILocale { * 1ヶ月 */ "oneMonth": string; + /** + * 3ヶ月 + */ + "threeMonths": string; + /** + * 1年 + */ + "oneYear": string; + /** + * 3日 + */ + "threeDays": string; /** * 反映されるまで時間がかかる場合があります。 */ @@ -5208,7 +5220,7 @@ export interface Locale extends ILocale { */ "requireSigninToViewContents": string; /** - * あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。 + * あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーに情報が収集されるのを防ぐ効果が期待できます。 */ "requireSigninToViewContentsDescription1": string; /** @@ -5219,6 +5231,34 @@ export interface Locale extends ILocale { * リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。 */ "requireSigninToViewContentsDescription3": string; + /** + * 過去のノートをフォロワーのみ表示可能にする + */ + "makeNotesFollowersOnlyBefore": string; + /** + * この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートがフォロワーのみ表示可能になります。無効に戻すと、ノートの公開状態も元に戻ります。 + */ + "makeNotesFollowersOnlyBeforeDescription": string; + /** + * 過去のノートを非公開化する + */ + "makeNotesHiddenBefore": string; + /** + * この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートが自分のみ表示可能(非公開化)になります。無効に戻すと、ノートの公開状態も元に戻ります。 + */ + "makeNotesHiddenBeforeDescription": string; + /** + * リモートサーバーに連合されたノートには効果が及ばない場合があります。 + */ + "mayNotEffectForFederatedNotes": string; + /** + * 指定した時間を経過しているノート + */ + "notesHavePassedSpecifiedPeriod": string; + /** + * 指定した日時より前のノート + */ + "notesOlderThanSpecifiedDateAndTime": string; }; "_abuseUserReport": { /** diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 5193947c4..803969712 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -947,6 +947,9 @@ oneHour: "1時間" oneDay: "1日" oneWeek: "1週間" oneMonth: "1ヶ月" +threeMonths: "3ヶ月" +oneYear: "1年" +threeDays: "3日" reflectMayTakeTime: "反映されるまで時間がかかる場合があります。" failedToFetchAccountInformation: "アカウント情報の取得に失敗しました" rateLimitExceeded: "レート制限を超えました" @@ -1299,9 +1302,16 @@ lockdown: "ロックダウン" _accountSettings: requireSigninToViewContents: "コンテンツの表示にログインを必須にする" - requireSigninToViewContentsDescription1: "あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。" + requireSigninToViewContentsDescription1: "あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーに情報が収集されるのを防ぐ効果が期待できます。" requireSigninToViewContentsDescription2: "URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。" requireSigninToViewContentsDescription3: "リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。" + makeNotesFollowersOnlyBefore: "過去のノートをフォロワーのみ表示可能にする" + makeNotesFollowersOnlyBeforeDescription: "この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートがフォロワーのみ表示可能になります。無効に戻すと、ノートの公開状態も元に戻ります。" + makeNotesHiddenBefore: "過去のノートを非公開化する" + makeNotesHiddenBeforeDescription: "この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートが自分のみ表示可能(非公開化)になります。無効に戻すと、ノートの公開状態も元に戻ります。" + mayNotEffectForFederatedNotes: "リモートサーバーに連合されたノートには効果が及ばない場合があります。" + notesHavePassedSpecifiedPeriod: "指定した時間を経過しているノート" + notesOlderThanSpecifiedDateAndTime: "指定した日時より前のノート" _abuseUserReport: forward: "転送" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index bb2ab742e..18e0236d5 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -947,6 +947,9 @@ oneHour: "1 小时" oneDay: "1 天" oneWeek: "1 周" oneMonth: "1 个月" +threeMonths: "3 个月" +oneYear: "1 年" +threeDays: "3 天" reflectMayTakeTime: "可能需要一些时间才能体现出效果。" failedToFetchAccountInformation: "获取账户信息失败" rateLimitExceeded: "已超过速率限制" @@ -1301,6 +1304,27 @@ prohibitedWordsForNameOfUser: "用户名中禁止的词" prohibitedWordsForNameOfUserDescription: "更改用户名时,如果用户名中包含此列表里的词汇,用户的改名请求将被拒绝。持有管理员权限的用户不受此限制。" yourNameContainsProhibitedWords: "目标用户名包含违禁词" yourNameContainsProhibitedWordsDescription: "用户名内含有违禁词。若想使用此用户名,请联系服务器管理员。" +testCaptchaWarning: "这是用于验证码测试的功能。**请勿在生产环境中使用。**" +prohibitedWordsForNameOfUser: "禁用词(用户名)" +prohibitedWordsForNameOfUserDescription: "如果用户名中包含此列表中的任何字符串,将拒绝用户名更改。具有版主权限的用户不受此限制影响。" +yourNameContainsProhibitedWords: "您尝试更改的名称包含禁用字符串" +yourNameContainsProhibitedWordsDescription: "您的名称包含禁用字符串。如果您想使用此名称,请联系服务器管理员。" +thisContentsAreMarkedAsSigninRequiredByAuthor: "作者已设置此内容需要登录才能查看" +lockdown: "封锁" + +_accountSettings: + requireSigninToViewContents: "需要登录才能查看内容" + requireSigninToViewContentsDescription1: "要求登录才能查看您创建的所有内容,如笔记等。这可以防止爬虫收集信息。" + requireSigninToViewContentsDescription2: "URL预览(OGP)、网页嵌入和不支持这些功能的服务器的笔记引用也将无法显示。" + requireSigninToViewContentsDescription3: "这些限制可能不适用于已联邦到远程服务器的内容。" + makeNotesFollowersOnlyBefore: "将过去的笔记设为仅关注者可见" + makeNotesFollowersOnlyBeforeDescription: "启用此功能期间,早于指定日期时间或已超过指定时间段的笔记将仅对关注者可见。禁用后,笔记将恢复到原始可见性设置。" + makeNotesHiddenBefore: "将过去的笔记设为私密" + makeNotesHiddenBeforeDescription: "启用此功能期间,早于指定日期时间或已超过指定时间段的笔记将仅对自己可见(私密)。禁用后,笔记将恢复到原始可见性设置。" + mayNotEffectForFederatedNotes: "这可能不会影响已联邦到远程服务器的笔记。" + notesHavePassedSpecifiedPeriod: "已超过指定时间段的笔记" + notesOlderThanSpecifiedDateAndTime: "早于指定日期和时间的笔记" + _mfm: intro: "MFM是一种在Misskey、Sharkey、Firefish、Akkoma等平台上使用的标记语言,可以在多处使用。在这里你可以查看所有可用的MFM语法。" dummy: "Welcome to Pari Cafe" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 39205b205..28d0e59ab 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -947,6 +947,9 @@ oneHour: "一小時" oneDay: "一天" oneWeek: "一週" oneMonth: "一個月" +threeMonths: "3 個月" +oneYear: "1 年" +threeDays: "3 天" reflectMayTakeTime: "可能需要一些時間才會出現效果。" failedToFetchAccountInformation: "取得帳戶資訊失敗" rateLimitExceeded: "已超過速率限制" @@ -1301,6 +1304,27 @@ prohibitedWordsForNameOfUser: "禁止使用的字詞(使用者名稱)" prohibitedWordsForNameOfUserDescription: "如果使用者名稱包含此清單中的任何字串,則拒絕重新命名使用者。 具有審查員權限的使用者不受此限制的影響。" yourNameContainsProhibitedWords: "您嘗試更改的名稱包含禁止的字串" yourNameContainsProhibitedWordsDescription: "名稱中包含禁止使用的字串。 如果您想使用此名稱,請聯絡您的伺服器管理員。" +testCaptchaWarning: "這是用於驗證碼測試的功能。**請勿在生產環境中使用。**" +prohibitedWordsForNameOfUser: "禁用詞(用戶名)" +prohibitedWordsForNameOfUserDescription: "如果用戶名中包含此列表中的任何字符串,將拒絕用戶名更改。具有版主權限的用戶不受此限制影響。" +yourNameContainsProhibitedWords: "您嘗試更改的名稱包含禁用字符串" +yourNameContainsProhibitedWordsDescription: "您的名稱包含禁用字符串。如果您想使用此名稱,請聯繫伺服器管理員。" +thisContentsAreMarkedAsSigninRequiredByAuthor: "作者已設置此內容需要登入才能查看" +lockdown: "封鎖" + +_accountSettings: + requireSigninToViewContents: "需要登入才能檢視內容" + requireSigninToViewContentsDescription1: "要求登入才能檢視您建立的所有內容,如筆記等。這可以防止爬蟲收集資訊。" + requireSigninToViewContentsDescription2: "URL預覽(OGP)、網頁嵌入和不支援這些功能的伺服器的筆記引用也將無法顯示。" + requireSigninToViewContentsDescription3: "這些限制可能不適用於已聯邦到遠端伺服器的內容。" + makeNotesFollowersOnlyBefore: "將過去的筆記設為僅關注者可見" + makeNotesFollowersOnlyBeforeDescription: "啟用此功能期間,早於指定日期時間或已超過指定時間段的筆記將僅對關注者可見。停用後,筆記將恢復到原始可見性設定。" + makeNotesHiddenBefore: "將過去的筆記設為私密" + makeNotesHiddenBeforeDescription: "啟用此功能期間,早於指定日期時間或已超過指定時間段的筆記將僅對自己可見(私密)。停用後,筆記將恢復到原始可見性設定。" + mayNotEffectForFederatedNotes: "這可能不會影響已聯邦到遠端伺服器的筆記。" + notesHavePassedSpecifiedPeriod: "已超過指定時間段的筆記" + notesOlderThanSpecifiedDateAndTime: "早於指定日期和時間的筆記" + _mfm: intro: "MFM是一種在Misskey、Sharkey、Firefish、Akkoma等平臺上使用的標記語言,可以在多處使用。在這裡你可以查看所有可用的MFM語法。" dummy: "Welcome to Pari Cafe" diff --git a/package.json b/package.json index cf385c3f6..ce74d1936 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2024.10.1-pari-Macaron", + "version": "2024.10.2-pari-Affogato", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/backend/migration/1729486255072-makeNotesHiddenBefore.js b/packages/backend/migration/1729486255072-makeNotesHiddenBefore.js new file mode 100644 index 000000000..5fe4886b0 --- /dev/null +++ b/packages/backend/migration/1729486255072-makeNotesHiddenBefore.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class MakeNotesHiddenBefore1729486255072 { + name = 'MakeNotesHiddenBefore1729486255072' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "makeNotesFollowersOnlyBefore" integer`); + await queryRunner.query(`ALTER TABLE "user" ADD "makeNotesHiddenBefore" integer`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "makeNotesHiddenBefore"`); + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "makeNotesFollowersOnlyBefore"`); + } +} diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index 254d96104..c826a2896 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -84,6 +84,8 @@ function generateDummyUser(override?: Partial): MiUser { isHibernated: false, isDeleted: false, requireSigninToViewContents: false, + makeNotesFollowersOnlyBefore: null, + makeNotesHiddenBefore: null, emojis: [], score: 0, host: null, diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 9a9144287..516da8d91 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -497,6 +497,8 @@ export class ApRendererService { _misskey_summary: profile.description, _misskey_followedMessage: profile.followedMessage, _misskey_requireSigninToViewContents: user.requireSigninToViewContents, + _misskey_makeNotesFollowersOnlyBefore: user.makeNotesFollowersOnlyBefore, + _misskey_makeNotesHiddenBefore: user.makeNotesHiddenBefore, 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 447f7ef3d..94cb0785c 100644 --- a/packages/backend/src/core/activitypub/misc/contexts.ts +++ b/packages/backend/src/core/activitypub/misc/contexts.ts @@ -556,6 +556,8 @@ const extension_context_definition = { '_misskey_summary': 'misskey:_misskey_summary', '_misskey_followedMessage': 'misskey:_misskey_followedMessage', '_misskey_requireSigninToViewContents': 'misskey:_misskey_requireSigninToViewContents', + '_misskey_makeNotesFollowersOnlyBefore': 'misskey:_misskey_makeNotesFollowersOnlyBefore', + '_misskey_makeNotesHiddenBefore': 'misskey:_misskey_makeNotesHiddenBefore', '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 c7915ed94..0e2934301 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -357,6 +357,8 @@ export class ApPersonService implements OnModuleInit { isBot, isCat: (person as any).isCat === true, requireSigninToViewContents: (person as any).requireSigninToViewContents === true, + makeNotesFollowersOnlyBefore: (person as any).makeNotesFollowersOnlyBefore ?? null, + makeNotesHiddenBefore: (person as any).makeNotesHiddenBefore ?? null, emojis, })) as MiRemoteUser; diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index 9674b0bee..6de1deb2e 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -15,6 +15,8 @@ export interface IObject { _misskey_summary?: string; _misskey_followedMessage?: string | null; _misskey_requireSigninToViewContents?: boolean; + _misskey_makeNotesFollowersOnlyBefore?: number | null; + _misskey_makeNotesHiddenBefore?: number | null; 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 14075707d..aaa85bca0 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -102,57 +102,83 @@ export class NoteEntityService implements OnModuleInit { } @bindThis - private async hideNote(packedNote: Packed<'Note'>, meId: MiUser['id'] | null) { + private async hideNote(packedNote: Packed<'Note'>, meId: MiUser['id'] | null): Promise { + // FIXME: このvisibility変更処理が当関数にあるのは若干不自然かもしれない(関数名を treatVisibility とかに変える手もある) + if (packedNote.visibility === 'public' || packedNote.visibility === 'home') { + const followersOnlyBefore = packedNote.user.makeNotesFollowersOnlyBefore; + if ((followersOnlyBefore != null) + && ( + (followersOnlyBefore <= 0 && (Date.now() - new Date(packedNote.createdAt).getTime() > 0 - (followersOnlyBefore * 1000))) + || (followersOnlyBefore > 0 && (new Date(packedNote.createdAt).getTime() < followersOnlyBefore * 1000)) + ) + ) { + packedNote.visibility = 'followers'; + } + } + + if (meId === packedNote.userId) return; + // TODO: isVisibleForMe を使うようにしても良さそう(型違うけど) let hide = false; - // visibility が specified かつ自分が指定されていなかったら非表示 - if (packedNote.visibility === 'specified') { - if (meId == null) { - hide = true; - } else if (meId === packedNote.userId) { - hide = false; - } else { - // 指定されているかどうか - const specified = packedNote.visibleUserIds!.some(id => meId === id); + if (packedNote.user.requireSigninToViewContents && meId == null) { + hide = true; + } - if (specified) { - hide = false; - } else { + if (!hide) { + const hiddenBefore = packedNote.user.makeNotesHiddenBefore; + if ((hiddenBefore != null) + && ( + (hiddenBefore <= 0 && (Date.now() - new Date(packedNote.createdAt).getTime() > 0 - (hiddenBefore * 1000))) + || (hiddenBefore > 0 && (new Date(packedNote.createdAt).getTime() < hiddenBefore * 1000)) + ) + ) { + hide = true; + } + } + + // visibility が specified かつ自分が指定されていなかったら非表示 + if (!hide) { + if (packedNote.visibility === 'specified') { + if (meId == null) { hide = true; + } else { + // 指定されているかどうか + const specified = packedNote.visibleUserIds!.some(id => meId === id); + + if (!specified) { + hide = true; + } } } } // visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示 - if (packedNote.visibility === 'followers') { - if (meId == null) { - hide = true; - } else if (meId === packedNote.userId) { - hide = false; - } else if (packedNote.reply && (meId === packedNote.reply.userId)) { - // 自分の投稿に対するリプライ - hide = false; - } else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) { - // 自分へのメンション - hide = false; - } else { - // フォロワーかどうか - const isFollowing = await this.followingsRepository.exists({ - where: { - followeeId: packedNote.userId, - followerId: meId, - }, - }); + if (!hide) { + if (packedNote.visibility === 'followers') { + if (meId == null) { + hide = true; + } else if (packedNote.reply && (meId === packedNote.reply.userId)) { + // 自分の投稿に対するリプライ + hide = false; + } else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) { + // 自分へのメンション + hide = false; + } else { + // フォロワーかどうか + // TODO: 当関数呼び出しごとにクエリが走るのは重そうだからなんとかする + const isFollowing = await this.followingsRepository.exists({ + where: { + followeeId: packedNote.userId, + followerId: meId, + }, + }); - hide = !isFollowing; + hide = !isFollowing; + } } } - if (packedNote.user.requireSigninToViewContents && meId == null) { - hide = true; - } - if (hide) { packedNote.visibleUserIds = undefined; packedNote.fileIds = []; @@ -161,6 +187,7 @@ export class NoteEntityService implements OnModuleInit { packedNote.poll = undefined; packedNote.cw = null; packedNote.isHidden = true; + // TODO: hiddenReason みたいなのを提供しても良さそう } } diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 36e2ebfd8..7ec9d8b2c 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -518,6 +518,8 @@ export class UserEntityService implements OnModuleInit { isBot: user.isBot, isCat: user.isCat, requireSigninToViewContents: user.requireSigninToViewContents === false ? undefined : true, + makeNotesFollowersOnlyBefore: user.makeNotesFollowersOnlyBefore ?? undefined, + makeNotesHiddenBefore: user.makeNotesHiddenBefore ?? undefined, 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 838bc95ce..5328131b9 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -208,6 +208,18 @@ export class MiUser { }) public requireSigninToViewContents: boolean; + // in sec, マイナスで相対時間 + @Column('integer', { + nullable: true, + }) + public makeNotesFollowersOnlyBefore: number | null; + + // in sec, マイナスで相対時間 + @Column('integer', { + nullable: true, + }) + public makeNotesHiddenBefore: number | null; + // アカウントが削除されたかどうかのフラグだが、完全に削除される際は物理削除なので実質削除されるまでの「削除が進行しているかどうか」のフラグ @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 817f8e929..38631f907 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -119,6 +119,14 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + makeNotesFollowersOnlyBefore: { + type: 'number', + nullable: true, optional: true, + }, + makeNotesHiddenBefore: { + type: 'number', + nullable: true, optional: true, + }, instance: { type: 'object', nullable: false, optional: true, diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index 6dc765402..1f9a3421a 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -319,6 +319,12 @@ export class FileServerService { ); } + if (!request.headers['user-agent']) { + throw new StatusError('User-Agent is required', 400, 'User-Agent is required'); + } else if (request.headers['user-agent'].toLowerCase().indexOf('misskey/') !== -1) { + throw new StatusError('Refusing to proxy a request from another proxy', 403, 'Proxy is recursive'); + } + // Create temp file const file = await this.getStreamAndTypeFromUrl(url); if (file === '404') { diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 6680c96f3..2183beac7 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -180,6 +180,8 @@ export const paramDef = { noCrawle: { type: 'boolean' }, preventAiLearning: { type: 'boolean' }, requireSigninToViewContents: { type: 'boolean' }, + makeNotesFollowersOnlyBefore: { type: 'integer', nullable: true }, + makeNotesHiddenBefore: { type: 'integer', nullable: true }, isBot: { type: 'boolean' }, isCat: { type: 'boolean' }, injectFeaturedNote: { type: 'boolean' }, @@ -336,6 +338,8 @@ export default class extends Endpoint { // eslint- 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.makeNotesFollowersOnlyBefore === 'number') || (ps.makeNotesFollowersOnlyBefore === null)) updates.makeNotesFollowersOnlyBefore = ps.makeNotesFollowersOnlyBefore; + if ((typeof ps.makeNotesHiddenBefore === 'number') || (ps.makeNotesHiddenBefore === null)) updates.makeNotesHiddenBefore = ps.makeNotesHiddenBefore; 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/frontend/src/components/MkSelect.vue b/packages/frontend/src/components/MkSelect.vue index 8bd02000e..eeadd4993 100644 --- a/packages/frontend/src/components/MkSelect.vue +++ b/packages/frontend/src/components/MkSelect.vue @@ -46,7 +46,7 @@ import type { MenuItem } from '@/types/menu.js'; import * as os from '@/os.js'; const props = defineProps<{ - modelValue: string | null; + modelValue: string | number | null; required?: boolean; readonly?: boolean; disabled?: boolean; diff --git a/packages/frontend/src/pages/settings/privacy.vue b/packages/frontend/src/pages/settings/privacy.vue index e277dfad7..da3d36b31 100644 --- a/packages/frontend/src/pages/settings/privacy.vue +++ b/packages/frontend/src/pages/settings/privacy.vue @@ -45,17 +45,89 @@ SPDX-License-Identifier: AGPL-3.0-only - +
- {{ i18n.ts._accountSettings.requireSigninToViewContents }}{{ i18n.ts.beta }} + {{ i18n.ts._accountSettings.requireSigninToViewContents }} + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ + +
@@ -87,7 +159,7 @@ SPDX-License-Identifier: AGPL-3.0-only