enhance: make active email validation configurable

This commit is contained in:
syuilo 2022-07-09 15:05:55 +09:00
parent da51152662
commit 638f0eba12
8 changed files with 61 additions and 8 deletions

View file

@ -9,6 +9,13 @@
You should also include the user name that made the change. You should also include the user name that made the change.
--> -->
## 12.x.x (unreleased)
### Improvements
- Make active email validation configurable
### Bugfixes
## 12.112.2 (2022/07/08) ## 12.112.2 (2022/07/08)
### Bugfixes ### Bugfixes

View file

@ -886,6 +886,7 @@ cannotUploadBecauseNoFreeSpace: "ドライブの空き容量が無いためア
beta: "ベータ" beta: "ベータ"
enableAutoSensitive: "自動NSFW判定" enableAutoSensitive: "自動NSFW判定"
enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。" enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。"
activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。" description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"

View file

@ -0,0 +1,11 @@
export class activeEmailValidation1657346559800 {
name = 'activeEmailValidation1657346559800'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "enableActiveEmailValidation" boolean NOT NULL DEFAULT true`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableActiveEmailValidation"`);
}
}

View file

@ -454,4 +454,9 @@ export class Meta {
default: false, default: false,
}) })
public enableIpLogging: boolean; public enableIpLogging: boolean;
@Column('boolean', {
default: true,
})
public enableActiveEmailValidation: boolean;
} }

View file

@ -324,6 +324,10 @@ export const meta = {
type: 'boolean', type: 'boolean',
optional: true, nullable: false, optional: true, nullable: false,
}, },
enableActiveEmailValidation: {
type: 'boolean',
optional: true, nullable: false,
},
}, },
}, },
} as const; } as const;
@ -421,5 +425,6 @@ export default define(meta, paramDef, async (ps, me) => {
deeplAuthKey: instance.deeplAuthKey, deeplAuthKey: instance.deeplAuthKey,
deeplIsPro: instance.deeplIsPro, deeplIsPro: instance.deeplIsPro,
enableIpLogging: instance.enableIpLogging, enableIpLogging: instance.enableIpLogging,
enableActiveEmailValidation: instance.enableActiveEmailValidation,
}; };
}); });

View file

@ -101,6 +101,7 @@ export const paramDef = {
objectStorageSetPublicRead: { type: 'boolean' }, objectStorageSetPublicRead: { type: 'boolean' },
objectStorageS3ForcePathStyle: { type: 'boolean' }, objectStorageS3ForcePathStyle: { type: 'boolean' },
enableIpLogging: { type: 'boolean' }, enableIpLogging: { type: 'boolean' },
enableActiveEmailValidation: { type: 'boolean' },
}, },
required: [], required: [],
} as const; } as const;
@ -421,6 +422,10 @@ export default define(meta, paramDef, async (ps, me) => {
set.enableIpLogging = ps.enableIpLogging; set.enableIpLogging = ps.enableIpLogging;
} }
if (ps.enableActiveEmailValidation !== undefined) {
set.enableActiveEmailValidation = ps.enableActiveEmailValidation;
}
await db.transaction(async transactionalEntityManager => { await db.transaction(async transactionalEntityManager => {
const metas = await transactionalEntityManager.find(Meta, { const metas = await transactionalEntityManager.find(Meta, {
order: { order: {

View file

@ -1,34 +1,37 @@
import { validate as validateEmail } from 'deep-email-validator'; import { validate as validateEmail } from 'deep-email-validator';
import { UserProfiles } from '@/models/index.js'; import { UserProfiles } from '@/models/index.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
export async function validateEmailForAccount(emailAddress: string): Promise<{ export async function validateEmailForAccount(emailAddress: string): Promise<{
available: boolean; available: boolean;
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp'; reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp';
}> { }> {
const meta = await fetchMeta();
const exist = await UserProfiles.countBy({ const exist = await UserProfiles.countBy({
emailVerified: true, emailVerified: true,
email: emailAddress, email: emailAddress,
}); });
const validated = await validateEmail({ const validated = meta.enableActiveEmailValidation ? await validateEmail({
email: emailAddress, email: emailAddress,
validateRegex: true, validateRegex: true,
validateMx: true, validateMx: true,
validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので
validateDisposable: true, // 捨てアドかどうかチェック validateDisposable: true, // 捨てアドかどうかチェック
validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので
}); }) : { valid: true };
const available = exist === 0 && validated.valid; const available = exist === 0 && validated.valid;
return { return {
available, available,
reason: available ? null : reason: available ? null :
exist !== 0 ? 'used' : exist !== 0 ? 'used' :
validated.reason === 'regex' ? 'format' : validated.reason === 'regex' ? 'format' :
validated.reason === 'disposable' ? 'disposable' : validated.reason === 'disposable' ? 'disposable' :
validated.reason === 'mx' ? 'mx' : validated.reason === 'mx' ? 'mx' :
validated.reason === 'smtp' ? 'smtp' : validated.reason === 'smtp' ? 'smtp' :
null, null,
}; };
} }

View file

@ -57,6 +57,19 @@
</div> </div>
</FormFolder> </FormFolder>
<FormFolder class="_formBlock">
<template #label>Active Email Validation</template>
<template v-if="enableActiveEmailValidation" #suffix>Enabled</template>
<template v-else #suffix>Disabled</template>
<div class="_formRoot">
<span class="_formBlock">{{ i18n.ts.activeEmailValidationDescription }}</span>
<FormSwitch v-model="enableActiveEmailValidation" class="_formBlock" @update:modelValue="save">
<template #label>Enable</template>
</FormSwitch>
</div>
</FormFolder>
<FormFolder class="_formBlock"> <FormFolder class="_formBlock">
<template #label>Log IP address</template> <template #label>Log IP address</template>
<template v-if="enableIpLogging" #suffix>Enabled</template> <template v-if="enableIpLogging" #suffix>Enabled</template>
@ -112,6 +125,7 @@ let sensitiveMediaDetectionSensitivity: number = $ref(0);
let setSensitiveFlagAutomatically: boolean = $ref(false); let setSensitiveFlagAutomatically: boolean = $ref(false);
let enableSensitiveMediaDetectionForVideos: boolean = $ref(false); let enableSensitiveMediaDetectionForVideos: boolean = $ref(false);
let enableIpLogging: boolean = $ref(false); let enableIpLogging: boolean = $ref(false);
let enableActiveEmailValidation: boolean = $ref(false);
async function init() { async function init() {
const meta = await os.api('admin/meta'); const meta = await os.api('admin/meta');
@ -128,6 +142,7 @@ async function init() {
setSensitiveFlagAutomatically = meta.setSensitiveFlagAutomatically; setSensitiveFlagAutomatically = meta.setSensitiveFlagAutomatically;
enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos; enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos;
enableIpLogging = meta.enableIpLogging; enableIpLogging = meta.enableIpLogging;
enableActiveEmailValidation = meta.enableActiveEmailValidation;
} }
function save() { function save() {
@ -144,6 +159,7 @@ function save() {
setSensitiveFlagAutomatically, setSensitiveFlagAutomatically,
enableSensitiveMediaDetectionForVideos, enableSensitiveMediaDetectionForVideos,
enableIpLogging, enableIpLogging,
enableActiveEmailValidation,
}).then(() => { }).then(() => {
fetchInstance(); fetchInstance();
}); });