diff --git a/.npmrc b/.npmrc index f43bec20e0..da702c3af5 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ -@sharkey:registry=https://git.joinsharkey.org/api/packages/Sharkey/npm/ \ No newline at end of file +@sharkey:registry=https://git.joinsharkey.org/api/packages/Sharkey/npm/ +engine-strict = true diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c21684e77..ac31bc0d28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,22 +15,23 @@ ## 2023.12.0 ### Note -- Node.js 20.10.0が最小要件になりました +- 依存関係の更新に伴い、Node.js 20.10.0が最小要件になりました - 絵文字の追加辞書を既にインストールしている場合は、お手数ですが再インストールのほどお願いします - 絵文字ピッカーにピン留め表示する絵文字設定が「リアクション用」と「絵文字入力用」に分かれました。以前の設定は「リアクション用」として使用されます。 **影響:** - それにより、投稿フォームから表示される絵文字ピッカーのピン留め絵文字がリセットされたように感じるかもしれません(新設された投稿用のピン留め絵文字が使われるため)。 + それにより、投稿フォームから表示される絵文字ピッカーのピン留め絵文字がリセットされたように感じるかもしれません(新設された"ピン留め(全般)"の設定が使われるため)。 投稿用のピン留め絵文字をアップデート前の状態にするには、以下の手順で操作します。 1. 「設定」メニューに移動し、「絵文字ピッカー」タブを選択します。 2. 「ピン留 (全般)」のタブを選択します。 - 3. 「リアクション設定からコピーする」ボタンを押すことで、アップデート前の状態に戻すことができます。 + 3. 「リアクション設定から上書きする」ボタンを押すことで、アップデート前の状態に戻すことができます。 ### General - Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed) - Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83) - Feat: TL上からノートが見えなくなるワードミュートであるハードミュートを追加 +- Enhance: 指定したドメインのメールアドレスの登録を弾くことができるように - Enhance: 公開ロールにアサインされたときに通知が作成されるように - Enhance: アイコンデコレーションを複数設定できるように - Enhance: アイコンデコレーションの位置を微調整できるように @@ -72,6 +73,7 @@ - Enhance: チャンネルに新規の投稿がある場合にバッジを表示させる - Enhance: サウンド設定に「サウンドを出力しない」と「Misskeyがアクティブな時のみサウンドを出力する」を追加 - Enhance: 設定したタグをトレンドに表示させないようにする項目を管理画面で設定できるように +- Enhance: 絵文字ピッカーのカテゴリに「/」を入れることでフォルダ分け表示できるように - Fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 - Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 - Fix: コードエディタが正しく表示されない問題を修正 @@ -242,7 +244,6 @@ ### Client - Enhance: TLの返信表示オプションを記憶するように - Enhance: 投稿されてから時間が経過しているノートであることを視覚的に分かりやすく -- Feat: 絵文字ピッカーのカテゴリに「/」を入れることでフォルダ分け表示できるように ### Server - Enhance: タイムライン取得時のパフォーマンスを向上 diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 7d3188038e..f5b65f4b77 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -1917,6 +1917,7 @@ _notification: pollEnded: "Sondages se cloturant" receiveFollowRequest: "Demande d'abonnement reçue" followRequestAccepted: "Demande d'abonnement acceptée" + roleAssigned: "Rôle reçu" achievementEarned: "Accomplissement" app: "Notifications provenant des apps" _actions: diff --git a/locales/index.d.ts b/locales/index.d.ts index fcd5820f49..02274cc086 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1783,6 +1783,7 @@ export interface Locale { "disposable": string; "mx": string; "smtp": string; + "banned": string; }; "_ffVisibility": { "public": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9d504db651..d6d6daec50 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1690,6 +1690,7 @@ _emailUnavailable: disposable: "恒久的に使用可能なアドレスではありません" mx: "正しいメールサーバーではありません" smtp: "メールサーバーが応答しません" + banned: "このメールアドレスでは登録できません" _ffVisibility: public: "公開" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index d8efa7f04e..6cdcc2c246 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -2193,6 +2193,7 @@ _notification: pollEnded: "투표가 종료됨" receiveFollowRequest: "팔로우 요청을 받았을 때" followRequestAccepted: "팔로우 요청이 승인되었을 때" + roleAssigned: "역할이 부여 됨" achievementEarned: "도전 과제 획득" app: "연동된 앱을 통한 알림" _actions: diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index d05691d42e..51ba42e66c 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -2193,6 +2193,7 @@ _notification: pollEnded: "問卷調查結束" receiveFollowRequest: "已收到追隨請求" followRequestAccepted: "追隨請求已接受" + roleAssigned: "已授予角色" achievementEarned: "獲得成就" app: "應用程式通知" _actions: diff --git a/packages/backend/migration/1703209889304-bannedEmailDomains.js b/packages/backend/migration/1703209889304-bannedEmailDomains.js new file mode 100644 index 0000000000..5dc99c138f --- /dev/null +++ b/packages/backend/migration/1703209889304-bannedEmailDomains.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class bannedEmailDomains1703209889304 { + constructor() { + this.name = 'bannedEmailDomains1703209889304'; + } + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "bannedEmailDomains" character varying(1024) array NOT NULL DEFAULT '{}'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "bannedEmailDomains"`); + } +} diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index 05d120a8db..4fce64606f 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -9,6 +9,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { validate as validateEmail } from 'deep-email-validator'; import { SubOutputFormat } from 'deep-email-validator/dist/output/output.js'; import { MetaService } from '@/core/MetaService.js'; +import { UtilityService } from '@/core/UtilityService.js'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import type Logger from '@/logger.js'; @@ -30,6 +31,7 @@ export class EmailService { private metaService: MetaService, private loggerService: LoggerService, + private utilityService: UtilityService, private httpRequestService: HttpRequestService, ) { this.logger = this.loggerService.getLogger('email'); @@ -155,7 +157,7 @@ export class EmailService { @bindThis public async validateEmailForAccount(emailAddress: string): Promise<{ available: boolean; - reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp'; + reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned'; }> { const meta = await this.metaService.fetch(); @@ -164,7 +166,6 @@ export class EmailService { email: emailAddress, }); - const verifymailApi = meta.enableVerifymailApi && meta.verifymailAuthKey != null; let validated; if (meta.enableActiveEmailValidation) { @@ -184,12 +185,16 @@ export class EmailService { validated = { valid: true, reason: null }; } - const available = exist === 0 && validated.valid; + const emailDomain: string = emailAddress.split('@')[1]; + const isBanned = this.utilityService.isBlockedHost(meta.bannedEmailDomains, emailDomain); + + const available = exist === 0 && validated.valid && !isBanned; return { available, reason: available ? null : exist !== 0 ? 'used' : + isBanned ? 'banned' : validated.reason === 'regex' ? 'format' : validated.reason === 'disposable' ? 'disposable' : validated.reason === 'mx' ? 'mx' : diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 270730c723..0b06931213 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -462,7 +462,7 @@ export class NoteCreateService implements OnApplicationShutdown { } // Check blocking - if (this.isQuote(data)) { + if (data.renote && !this.isQuote(data)) { if (data.renote.userHost === null) { if (data.renote.userId !== user.id) { const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id); diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 6aa35b0b40..4bf856e619 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -510,6 +510,13 @@ export class MiMeta { }) public manifestJsonOverride: string; + @Column('varchar', { + length: 1024, + array: true, + default: '{}', + }) + public bannedEmailDomains: string[]; + @Column('varchar', { length: 1024, array: true, default: '{ "admin", "administrator", "root", "system", "maintainer", "host", "mod", "moderator", "owner", "superuser", "staff", "auth", "i", "me", "everyone", "all", "mention", "mentions", "example", "user", "users", "account", "accounts", "official", "help", "helps", "support", "supports", "info", "information", "informations", "announce", "announces", "announcement", "announcements", "notice", "notification", "notifications", "dev", "developer", "developers", "tech", "misskey" }', }) diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 17c81bb76d..80f0dc5747 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -149,6 +149,14 @@ export const meta = { type: 'string', }, }, + bannedEmailDomains: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, preservedUsernames: { type: 'array', optional: false, nullable: false, @@ -537,6 +545,7 @@ export default class extends Endpoint { // eslint- enableServerMachineStats: instance.enableServerMachineStats, enableAchievements: instance.enableAchievements, enableIdenticonGeneration: instance.enableIdenticonGeneration, + bannedEmailDomains: instance.bannedEmailDomains, policies: { ...DEFAULT_POLICIES, ...instance.policies }, manifestJsonOverride: instance.manifestJsonOverride, enableFanoutTimeline: instance.enableFanoutTimeline, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 3c5bc7e957..5d982b5093 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -126,6 +126,7 @@ export const paramDef = { enableAchievements: { type: 'boolean' }, enableIdenticonGeneration: { type: 'boolean' }, serverRules: { type: 'array', items: { type: 'string' } }, + bannedEmailDomains: { type: 'array', items: { type: 'string' } }, preservedUsernames: { type: 'array', items: { type: 'string' } }, bubbleInstances: { type: 'array', items: { type: 'string' } }, manifestJsonOverride: { type: 'string' }, @@ -535,6 +536,10 @@ export default class extends Endpoint { // eslint- set.notesPerOneAd = ps.notesPerOneAd; } + if (ps.bannedEmailDomains !== undefined) { + set.bannedEmailDomains = ps.bannedEmailDomains; + } + const before = await this.metaService.fetch(true); await this.metaService.update(set); diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index b46dc4bd93..3c5dd0ce29 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -38,6 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts._emailUnavailable.used }} {{ i18n.ts._emailUnavailable.format }} {{ i18n.ts._emailUnavailable.disposable }} + {{ i18n.ts._emailUnavailable.banned }} {{ i18n.ts._emailUnavailable.mx }} {{ i18n.ts._emailUnavailable.smtp }} {{ i18n.ts.unavailable }} @@ -116,7 +117,7 @@ const invitationCode = ref(''); const reason = ref(''); const email = ref(''); const usernameState = ref(null); -const emailState = ref(null); +const emailState = ref(null); const passwordStrength = ref<'' | 'low' | 'medium' | 'high'>(''); const passwordRetypeState = ref(null); const submitting = ref(false); @@ -215,6 +216,7 @@ function onChangeEmail(): void { result.reason === 'used' ? 'unavailable:used' : result.reason === 'format' ? 'unavailable:format' : result.reason === 'disposable' ? 'unavailable:disposable' : + result.reason === 'banned' ? 'unavailable:banned' : result.reason === 'mx' ? 'unavailable:mx' : result.reason === 'smtp' ? 'unavailable:smtp' : 'unavailable'; diff --git a/packages/frontend/src/pages/admin/security.vue b/packages/frontend/src/pages/admin/security.vue index 95f4d2b20c..524b9b9a79 100644 --- a/packages/frontend/src/pages/admin/security.vue +++ b/packages/frontend/src/pages/admin/security.vue @@ -31,15 +31,26 @@ SPDX-License-Identifier: AGPL-3.0-only - + - + + + + +
+ + + + {{ i18n.ts.save }} +
+
+ @@ -81,6 +92,7 @@ import FormSuspense from '@/components/form/suspense.vue'; import MkRange from '@/components/MkRange.vue'; import MkInput from '@/components/MkInput.vue'; import MkButton from '@/components/MkButton.vue'; +import MkTextarea from '@/components/MkTextarea.vue'; import * as os from '@/os.js'; import { fetchInstance } from '@/instance.js'; import { i18n } from '@/i18n.js'; @@ -94,6 +106,7 @@ const enableIpLogging = ref(false); const enableActiveEmailValidation = ref(false); const enableVerifymailApi = ref(false); const verifymailAuthKey = ref(null); +const bannedEmailDomains = ref(''); async function init() { const meta = await os.api('admin/meta'); @@ -105,6 +118,7 @@ async function init() { enableActiveEmailValidation.value = meta.enableActiveEmailValidation; enableVerifymailApi.value = meta.enableVerifymailApi; verifymailAuthKey.value = meta.verifymailAuthKey; + bannedEmailDomains.value = meta.bannedEmailDomains.join('\n'); } function save() { @@ -114,6 +128,7 @@ function save() { enableActiveEmailValidation: enableActiveEmailValidation.value, enableVerifymailApi: enableVerifymailApi.value, verifymailAuthKey: verifymailAuthKey.value, + bannedEmailDomains: bannedEmailDomains.value.split('\n'), }).then(() => { fetchInstance(); });