メールアドレスの認証にverifymail.ioを使えるようにする。
This commit is contained in:
parent
83ea0395f6
commit
0a73973a7c
5 changed files with 140 additions and 8 deletions
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class SupportVerifyMailApi1700303245007 {
|
||||||
|
name = 'SupportVerifyMailApi1700303245007'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "verifymailAuthKey" character varying(1024)`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "enableVerifymailApi" boolean NOT NULL DEFAULT false`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableVerifymailApi"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "verifymailAuthKey"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,9 @@ import type Logger from '@/logger.js';
|
||||||
import type { UserProfilesRepository } from '@/models/_.js';
|
import type { UserProfilesRepository } from '@/models/_.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import {URLSearchParams} from "node:url";
|
||||||
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
|
import {SubOutputFormat} from "deep-email-validator/dist/output/output.js";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EmailService {
|
export class EmailService {
|
||||||
|
@ -27,6 +30,7 @@ export class EmailService {
|
||||||
|
|
||||||
private metaService: MetaService,
|
private metaService: MetaService,
|
||||||
private loggerService: LoggerService,
|
private loggerService: LoggerService,
|
||||||
|
private httpRequestService: HttpRequestService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.loggerService.getLogger('email');
|
this.logger = this.loggerService.getLogger('email');
|
||||||
}
|
}
|
||||||
|
@ -160,14 +164,25 @@ export class EmailService {
|
||||||
email: emailAddress,
|
email: emailAddress,
|
||||||
});
|
});
|
||||||
|
|
||||||
const validated = meta.enableActiveEmailValidation ? await validateEmail({
|
const verifymailApi = meta.enableVerifymailApi && meta.verifymailAuthKey != null;
|
||||||
email: emailAddress,
|
let validated;
|
||||||
validateRegex: true,
|
|
||||||
validateMx: true,
|
if (meta.enableActiveEmailValidation) {
|
||||||
validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので
|
if (verifymailApi) {
|
||||||
validateDisposable: true, // 捨てアドかどうかチェック
|
validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey);
|
||||||
validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので
|
} else {
|
||||||
}) : { valid: true, reason: null };
|
validated = meta.enableActiveEmailValidation ? await validateEmail({
|
||||||
|
email: emailAddress,
|
||||||
|
validateRegex: true,
|
||||||
|
validateMx: true,
|
||||||
|
validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので
|
||||||
|
validateDisposable: true, // 捨てアドかどうかチェック
|
||||||
|
validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので
|
||||||
|
}) : { valid: true, reason: null };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
validated = { valid: true, reason: null };
|
||||||
|
}
|
||||||
|
|
||||||
const available = exist === 0 && validated.valid;
|
const available = exist === 0 && validated.valid;
|
||||||
|
|
||||||
|
@ -182,4 +197,65 @@ export class EmailService {
|
||||||
null,
|
null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async verifyMail(emailAddress: string, verifymailAuthKey: string): Promise<{
|
||||||
|
valid: boolean;
|
||||||
|
reason: 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | null;
|
||||||
|
}> {
|
||||||
|
const endpoint = 'https://verifymail.io/api/' + emailAddress + '?key=' + verifymailAuthKey;
|
||||||
|
const res = await this.httpRequestService.send(endpoint, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
Accept: 'application/json, */*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const json = (await res.json()) as {
|
||||||
|
block: boolean;
|
||||||
|
catch_all: boolean;
|
||||||
|
deliverable_email: boolean;
|
||||||
|
disposable: boolean;
|
||||||
|
domain: string;
|
||||||
|
email_address: string;
|
||||||
|
email_provider: string;
|
||||||
|
mx: boolean;
|
||||||
|
mx_fallback: boolean;
|
||||||
|
mx_host: string[];
|
||||||
|
mx_ip: string[];
|
||||||
|
mx_priority: { [key: string]: number };
|
||||||
|
privacy: boolean;
|
||||||
|
related_domains: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (json.email_address === undefined) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: 'format',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (json.deliverable_email !== undefined && !json.deliverable_email) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: 'smtp',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (json.disposable) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: 'disposable',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (json.mx !== undefined && !json.mx) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
reason: 'mx',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
reason: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -446,6 +446,17 @@ export class MiMeta {
|
||||||
})
|
})
|
||||||
public enableActiveEmailValidation: boolean;
|
public enableActiveEmailValidation: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public enableVerifymailApi: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 1024,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
public verifymailAuthKey: string | null;
|
||||||
|
|
||||||
@Column('boolean', {
|
@Column('boolean', {
|
||||||
default: true,
|
default: true,
|
||||||
})
|
})
|
||||||
|
|
|
@ -113,6 +113,8 @@ export const paramDef = {
|
||||||
objectStorageS3ForcePathStyle: { type: 'boolean' },
|
objectStorageS3ForcePathStyle: { type: 'boolean' },
|
||||||
enableIpLogging: { type: 'boolean' },
|
enableIpLogging: { type: 'boolean' },
|
||||||
enableActiveEmailValidation: { type: 'boolean' },
|
enableActiveEmailValidation: { type: 'boolean' },
|
||||||
|
enableVerifymailApi: { type: 'boolean' },
|
||||||
|
verifymailAuthKey: { type: 'string', nullable: true },
|
||||||
enableChartsForRemoteUser: { type: 'boolean' },
|
enableChartsForRemoteUser: { type: 'boolean' },
|
||||||
enableChartsForFederatedInstances: { type: 'boolean' },
|
enableChartsForFederatedInstances: { type: 'boolean' },
|
||||||
enableServerMachineStats: { type: 'boolean' },
|
enableServerMachineStats: { type: 'boolean' },
|
||||||
|
@ -454,6 +456,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.enableActiveEmailValidation = ps.enableActiveEmailValidation;
|
set.enableActiveEmailValidation = ps.enableActiveEmailValidation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.enableVerifymailApi !== undefined) {
|
||||||
|
set.enableVerifymailApi = ps.enableVerifymailApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.verifymailAuthKey !== undefined) {
|
||||||
|
if (ps.verifymailAuthKey === '') {
|
||||||
|
set.verifymailAuthKey = null;
|
||||||
|
} else {
|
||||||
|
set.verifymailAuthKey = ps.verifymailAuthKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.enableChartsForRemoteUser !== undefined) {
|
if (ps.enableChartsForRemoteUser !== undefined) {
|
||||||
set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser;
|
set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSwitch v-model="enableActiveEmailValidation" @update:modelValue="save">
|
<MkSwitch v-model="enableActiveEmailValidation" @update:modelValue="save">
|
||||||
<template #label>Enable</template>
|
<template #label>Enable</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
|
<MkSwitch v-model="enableVerifymailApi" @update:modelValue="save">
|
||||||
|
<template #label>Use Verifymail API</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkInput v-model="verifymailAuthKey" @update:modelValue="save">
|
||||||
|
<template #prefix><i class="ti ti-key"></i></template>
|
||||||
|
<template #label>Verifymail API Auth Key</template>
|
||||||
|
</MkInput>
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
@ -132,6 +139,8 @@ 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);
|
let enableActiveEmailValidation: boolean = $ref(false);
|
||||||
|
let enableVerifymailApi: boolean = $ref(false);
|
||||||
|
let verifymailAuthKey: string | null = $ref(null);
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
const meta = await os.api('admin/meta');
|
const meta = await os.api('admin/meta');
|
||||||
|
@ -150,6 +159,8 @@ async function init() {
|
||||||
enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos;
|
enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos;
|
||||||
enableIpLogging = meta.enableIpLogging;
|
enableIpLogging = meta.enableIpLogging;
|
||||||
enableActiveEmailValidation = meta.enableActiveEmailValidation;
|
enableActiveEmailValidation = meta.enableActiveEmailValidation;
|
||||||
|
enableVerifymailApi = meta.enableVerifymailApi;
|
||||||
|
verifymailAuthKey = meta.verifymailAuthKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
|
@ -167,6 +178,8 @@ function save() {
|
||||||
enableSensitiveMediaDetectionForVideos,
|
enableSensitiveMediaDetectionForVideos,
|
||||||
enableIpLogging,
|
enableIpLogging,
|
||||||
enableActiveEmailValidation,
|
enableActiveEmailValidation,
|
||||||
|
enableVerifymailApi,
|
||||||
|
verifymailAuthKey,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue