summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--locales/index.d.ts1
-rw-r--r--locales/ja-JP.yml1
-rw-r--r--packages/backend/migration/1703209889304-bannedEmailDomains.js18
-rw-r--r--packages/backend/src/core/EmailService.ts10
-rw-r--r--packages/backend/src/models/Meta.ts7
-rw-r--r--packages/backend/src/server/api/endpoints/admin/meta.ts9
-rw-r--r--packages/backend/src/server/api/endpoints/admin/update-meta.ts5
-rw-r--r--packages/frontend/src/components/MkSignupDialog.form.vue4
-rw-r--r--packages/frontend/src/pages/admin/security.vue15
10 files changed, 68 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c21684e77..71a90620e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -94,6 +94,7 @@
- Fix: MFMでルビの中のテキストがnyaizeされない問題を修正
### Server
+- Feat: 使い捨てメールのドメインを手動で設定できるように
- Enhance: MFM `$[ruby ]` が他ソフトウェアと連合されるように
- Enhance: Meilisearchを有効にした検索で、ユーザーのミュートやブロックを考慮するように
- Enhance: カスタム絵文字のインポート時の動作を改善
diff --git a/locales/index.d.ts b/locales/index.d.ts
index fd96fd7625..b3589082e1 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -1745,6 +1745,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 2c29bd20da..b59fb6e749 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1652,6 +1652,7 @@ _emailUnavailable:
disposable: "恒久的に使用可能なアドレスではありません"
mx: "正しいメールサーバーではありません"
smtp: "メールサーバーが応答しません"
+ banned: "このメールアドレスでは登録できません"
_ffVisibility:
public: "公開"
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 d4508d5313..6107b9601c 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();
@@ -184,12 +186,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/models/Meta.ts b/packages/backend/src/models/Meta.ts
index 83e8962f5d..84ca762492 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -496,6 +496,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" }',
})
public preservedUsernames: string[];
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index 07912154bd..6f8494d1d0 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -145,6 +145,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,
@@ -513,6 +521,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
enableServerMachineStats: instance.enableServerMachineStats,
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 293a95a9a4..5f9de0523e 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -122,6 +122,7 @@ export const paramDef = {
enableServerMachineStats: { type: 'boolean' },
enableIdenticonGeneration: { type: 'boolean' },
serverRules: { type: 'array', items: { type: 'string' } },
+ bannedEmailDomains: { type: 'array', items: { type: 'string' } },
preservedUsernames: { type: 'array', items: { type: 'string' } },
manifestJsonOverride: { type: 'string' },
enableFanoutTimeline: { type: 'boolean' },
@@ -526,6 +527,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // 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 dd05a44e04..f171e449c8 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
<span v-else-if="emailState === 'unavailable:used'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts._emailUnavailable.used }}</span>
<span v-else-if="emailState === 'unavailable:format'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts._emailUnavailable.format }}</span>
<span v-else-if="emailState === 'unavailable:disposable'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts._emailUnavailable.disposable }}</span>
+ <span v-else-if="emailState === 'unavailable:banned'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts._emailUnavailable.banned }}</span>
<span v-else-if="emailState === 'unavailable:mx'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts._emailUnavailable.mx }}</span>
<span v-else-if="emailState === 'unavailable:smtp'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts._emailUnavailable.smtp }}</span>
<span v-else-if="emailState === 'unavailable'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.unavailable }}</span>
@@ -110,7 +111,7 @@ const retypedPassword = ref<string>('');
const invitationCode = ref<string>('');
const email = ref('');
const usernameState = ref<null | 'wait' | 'ok' | 'unavailable' | 'error' | 'invalid-format' | 'min-range' | 'max-range'>(null);
-const emailState = ref<null | 'wait' | 'ok' | 'unavailable:used' | 'unavailable:format' | 'unavailable:disposable' | 'unavailable:mx' | 'unavailable:smtp' | 'unavailable' | 'error'>(null);
+const emailState = ref<null | 'wait' | 'ok' | 'unavailable:used' | 'unavailable:format' | 'unavailable:disposable' | 'unavailable:banned' | 'unavailable:mx' | 'unavailable:smtp' | 'unavailable' | 'error'>(null);
const passwordStrength = ref<'' | 'low' | 'medium' | 'high'>('');
const passwordRetypeState = ref<null | 'match' | 'not-match'>(null);
const submitting = ref<boolean>(false);
@@ -209,6 +210,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 9835591fa8..bda29cee58 100644
--- a/packages/frontend/src/pages/admin/security.vue
+++ b/packages/frontend/src/pages/admin/security.vue
@@ -84,6 +84,17 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFolder>
<MkFolder>
+ <template #label>Banned Email Domains</template>
+
+ <div class="_gaps_m">
+ <MkTextarea v-model="bannedEmailDomains">
+ <template #label>Banned Email Domains List</template>
+ </MkTextarea>
+ <MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
+ </div>
+ </MkFolder>
+
+ <MkFolder>
<template #label>Log IP address</template>
<template v-if="enableIpLogging" #suffix>Enabled</template>
<template v-else #suffix>Disabled</template>
@@ -124,6 +135,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';
@@ -141,6 +153,7 @@ const enableIpLogging = ref<boolean>(false);
const enableActiveEmailValidation = ref<boolean>(false);
const enableVerifymailApi = ref<boolean>(false);
const verifymailAuthKey = ref<string | null>(null);
+const bannedEmailDomains = ref<string>('');
async function init() {
const meta = await os.api('admin/meta');
@@ -161,6 +174,7 @@ async function init() {
enableActiveEmailValidation.value = meta.enableActiveEmailValidation;
enableVerifymailApi.value = meta.enableVerifymailApi;
verifymailAuthKey.value = meta.verifymailAuthKey;
+ bannedEmailDomains.value = meta.bannedEmailDomains.join('\n');
}
function save() {
@@ -180,6 +194,7 @@ function save() {
enableActiveEmailValidation: enableActiveEmailValidation.value,
enableVerifymailApi: enableVerifymailApi.value,
verifymailAuthKey: verifymailAuthKey.value,
+ bannedEmailDomains: bannedEmailDomains.value.split('\n'),
}).then(() => {
fetchInstance();
});