feat: Add support for TrueMail (#12850)
Co-authored-by: MarryDream <2190758465@qq.com>
This commit is contained in:
		
							parent
							
								
									8fb8d7c10c
								
							
						
					
					
						commit
						7948018e6a
					
				
					 6 changed files with 160 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: syuilo and other misskey contributors
 | 
			
		||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export class SupportTrueMailApi1703658526000 {
 | 
			
		||||
    name = 'SupportTrueMailApi1703658526000'
 | 
			
		||||
 | 
			
		||||
    async up(queryRunner) {
 | 
			
		||||
    	  await queryRunner.query(`ALTER TABLE "meta" ADD "truemailInstance" character varying(1024)`);
 | 
			
		||||
        await queryRunner.query(`ALTER TABLE "meta" ADD "truemailAuthKey" character varying(1024)`);
 | 
			
		||||
        await queryRunner.query(`ALTER TABLE "meta" ADD "enableTruemailApi" boolean NOT NULL DEFAULT false`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async down(queryRunner) {
 | 
			
		||||
        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableTruemailApi"`);
 | 
			
		||||
        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "truemailInstance"`);
 | 
			
		||||
        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "truemailAuthKey"`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -156,7 +156,7 @@ export class EmailService {
 | 
			
		|||
	@bindThis
 | 
			
		||||
	public async validateEmailForAccount(emailAddress: string): Promise<{
 | 
			
		||||
		available: boolean;
 | 
			
		||||
		reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned';
 | 
			
		||||
		reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist';
 | 
			
		||||
	}> {
 | 
			
		||||
		const meta = await this.metaService.fetch();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -173,6 +173,8 @@ export class EmailService {
 | 
			
		|||
		if (meta.enableActiveEmailValidation) {
 | 
			
		||||
			if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) {
 | 
			
		||||
				validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey);
 | 
			
		||||
			} else if (meta.enableTruemailApi && meta.truemailInstance && meta.truemailAuthKey != null) {
 | 
			
		||||
				validated = await this.trueMail(meta.truemailInstance, emailAddress, meta.truemailAuthKey);
 | 
			
		||||
			} else {
 | 
			
		||||
				validated = await validateEmail({
 | 
			
		||||
					email: emailAddress,
 | 
			
		||||
| 
						 | 
				
			
			@ -201,6 +203,8 @@ export class EmailService {
 | 
			
		|||
			validated.reason === 'disposable' ? 'disposable' :
 | 
			
		||||
			validated.reason === 'mx' ? 'mx' :
 | 
			
		||||
			validated.reason === 'smtp' ? 'smtp' :
 | 
			
		||||
			validated.reason === 'network' ? 'network' :
 | 
			
		||||
			validated.reason === 'blacklist' ? 'blacklist' :
 | 
			
		||||
			null,
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -265,4 +269,67 @@ export class EmailService {
 | 
			
		|||
			reason: null,
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private async trueMail<T>(truemailInstance: string, emailAddress: string, truemailAuthKey: string): Promise<{
 | 
			
		||||
		valid: boolean;
 | 
			
		||||
		reason: 'used' | 'format' | 'blacklist' | 'mx' | 'smtp' | 'network' | T | null;
 | 
			
		||||
	}> {
 | 
			
		||||
		const endpoint = truemailInstance + '?email=' + emailAddress;
 | 
			
		||||
		try {
 | 
			
		||||
			const res = await this.httpRequestService.send(endpoint, {
 | 
			
		||||
				method: 'POST',
 | 
			
		||||
				headers: {
 | 
			
		||||
					'Content-Type': 'application/json',
 | 
			
		||||
					Accept: 'application/json',
 | 
			
		||||
					Authorization: truemailAuthKey
 | 
			
		||||
				},
 | 
			
		||||
			});
 | 
			
		||||
			
 | 
			
		||||
			const json = (await res.json()) as {
 | 
			
		||||
				email: string;
 | 
			
		||||
				success: boolean;
 | 
			
		||||
				errors?: { 
 | 
			
		||||
					list_match?: string;
 | 
			
		||||
					regex?: string;
 | 
			
		||||
					mx?: string;
 | 
			
		||||
					smtp?: string;
 | 
			
		||||
				} | null;
 | 
			
		||||
			};
 | 
			
		||||
			
 | 
			
		||||
			if (json.email === undefined || (json.email !== undefined && json.errors?.regex)) {
 | 
			
		||||
				return {
 | 
			
		||||
						valid: false,
 | 
			
		||||
						reason: 'format',
 | 
			
		||||
				};
 | 
			
		||||
			}
 | 
			
		||||
			if (json.errors?.smtp) {
 | 
			
		||||
				return {
 | 
			
		||||
					valid: false,
 | 
			
		||||
					reason: 'smtp',
 | 
			
		||||
				};
 | 
			
		||||
			}
 | 
			
		||||
			if (json.errors?.mx) {
 | 
			
		||||
				return {
 | 
			
		||||
					valid: false,
 | 
			
		||||
					reason: 'mx',
 | 
			
		||||
				};
 | 
			
		||||
			}
 | 
			
		||||
			if (!json.success) {
 | 
			
		||||
				return {
 | 
			
		||||
					valid: false,
 | 
			
		||||
					reason: json.errors?.list_match as T || 'blacklist',
 | 
			
		||||
				};
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			return {
 | 
			
		||||
				valid: true,
 | 
			
		||||
				reason: null,
 | 
			
		||||
			};
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			return {
 | 
			
		||||
				valid: false,
 | 
			
		||||
				reason: 'network',
 | 
			
		||||
			};
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -457,6 +457,23 @@ export class MiMeta {
 | 
			
		|||
	})
 | 
			
		||||
	public verifymailAuthKey: string | null;
 | 
			
		||||
 | 
			
		||||
	@Column('boolean', {
 | 
			
		||||
		default: false,
 | 
			
		||||
	})
 | 
			
		||||
	public enableTruemailApi: boolean;
 | 
			
		||||
 | 
			
		||||
	@Column('varchar', {
 | 
			
		||||
		length: 1024,
 | 
			
		||||
		nullable: true,
 | 
			
		||||
	})
 | 
			
		||||
	public truemailInstance: string | null;
 | 
			
		||||
	
 | 
			
		||||
	@Column('varchar', {
 | 
			
		||||
		length: 1024,
 | 
			
		||||
		nullable: true,
 | 
			
		||||
	})
 | 
			
		||||
	public truemailAuthKey: string | null;
 | 
			
		||||
 | 
			
		||||
	@Column('boolean', {
 | 
			
		||||
		default: true,
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -284,6 +284,18 @@ export const meta = {
 | 
			
		|||
				type: 'string',
 | 
			
		||||
				optional: false, nullable: true,
 | 
			
		||||
			},
 | 
			
		||||
			enableTruemailApi: {
 | 
			
		||||
				type: 'boolean',
 | 
			
		||||
				optional: false, nullable: false,
 | 
			
		||||
			},
 | 
			
		||||
			truemailInstance: {
 | 
			
		||||
				type: 'string',
 | 
			
		||||
				optional: false, nullable: true,
 | 
			
		||||
			},
 | 
			
		||||
			truemailAuthKey: {
 | 
			
		||||
				type: 'string',
 | 
			
		||||
				optional: false, nullable: true,
 | 
			
		||||
			},
 | 
			
		||||
			enableChartsForRemoteUser: {
 | 
			
		||||
				type: 'boolean',
 | 
			
		||||
				optional: false, nullable: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -520,6 +532,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
				enableActiveEmailValidation: instance.enableActiveEmailValidation,
 | 
			
		||||
				enableVerifymailApi: instance.enableVerifymailApi,
 | 
			
		||||
				verifymailAuthKey: instance.verifymailAuthKey,
 | 
			
		||||
				enableTruemailApi: instance.enableTruemailApi,
 | 
			
		||||
				truemailInstance: instance.truemailInstance,
 | 
			
		||||
				truemailAuthKey: instance.truemailAuthKey,
 | 
			
		||||
				enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
 | 
			
		||||
				enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
 | 
			
		||||
				enableServerMachineStats: instance.enableServerMachineStats,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -116,6 +116,9 @@ export const paramDef = {
 | 
			
		|||
		enableActiveEmailValidation: { type: 'boolean' },
 | 
			
		||||
		enableVerifymailApi: { type: 'boolean' },
 | 
			
		||||
		verifymailAuthKey: { type: 'string', nullable: true },
 | 
			
		||||
		enableTruemailApi: { type: 'boolean' },
 | 
			
		||||
		truemailInstance: { type: 'string', nullable: true },
 | 
			
		||||
		truemailAuthKey: { type: 'string', nullable: true },
 | 
			
		||||
		enableChartsForRemoteUser: { type: 'boolean' },
 | 
			
		||||
		enableChartsForFederatedInstances: { type: 'boolean' },
 | 
			
		||||
		enableServerMachineStats: { type: 'boolean' },
 | 
			
		||||
| 
						 | 
				
			
			@ -469,6 +472,26 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
					set.verifymailAuthKey = ps.verifymailAuthKey;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (ps.enableTruemailApi !== undefined) {
 | 
			
		||||
				set.enableTruemailApi = ps.enableTruemailApi;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (ps.truemailInstance !== undefined) {
 | 
			
		||||
				if (ps.truemailInstance === '') {
 | 
			
		||||
					set.truemailInstance = null;
 | 
			
		||||
				} else {
 | 
			
		||||
					set.truemailInstance = ps.truemailInstance;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (ps.truemailAuthKey !== undefined) {
 | 
			
		||||
				if (ps.truemailAuthKey === '') {
 | 
			
		||||
					set.truemailAuthKey = null;
 | 
			
		||||
				} else {
 | 
			
		||||
					set.truemailAuthKey = ps.truemailAuthKey;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (ps.enableChartsForRemoteUser !== undefined) {
 | 
			
		||||
				set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,6 +80,17 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		|||
							<template #prefix><i class="ti ti-key"></i></template>
 | 
			
		||||
							<template #label>Verifymail.io API Auth Key</template>
 | 
			
		||||
						</MkInput>
 | 
			
		||||
						<MkSwitch v-model="enableTruemailApi" @update:modelValue="save">
 | 
			
		||||
							<template #label>Use TrueMail API</template>
 | 
			
		||||
						</MkSwitch>
 | 
			
		||||
						<MkInput v-model="truemailInstance" @update:modelValue="save">
 | 
			
		||||
							<template #prefix><i class="ti ti-key"></i></template>
 | 
			
		||||
							<template #label>TrueMail API Instance</template>
 | 
			
		||||
						</MkInput>
 | 
			
		||||
						<MkInput v-model="truemailAuthKey" @update:modelValue="save">
 | 
			
		||||
							<template #prefix><i class="ti ti-key"></i></template>
 | 
			
		||||
							<template #label>TrueMail API Auth Key</template>
 | 
			
		||||
						</MkInput>
 | 
			
		||||
					</div>
 | 
			
		||||
				</MkFolder>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +164,9 @@ const enableIpLogging = ref<boolean>(false);
 | 
			
		|||
const enableActiveEmailValidation = ref<boolean>(false);
 | 
			
		||||
const enableVerifymailApi = ref<boolean>(false);
 | 
			
		||||
const verifymailAuthKey = ref<string | null>(null);
 | 
			
		||||
const enableTruemailApi = ref<boolean>(false);
 | 
			
		||||
const truemailInstance = ref<string | null>(null);
 | 
			
		||||
const truemailAuthKey = ref<string | null>(null);
 | 
			
		||||
const bannedEmailDomains = ref<string>('');
 | 
			
		||||
 | 
			
		||||
async function init() {
 | 
			
		||||
| 
						 | 
				
			
			@ -194,6 +208,9 @@ function save() {
 | 
			
		|||
		enableActiveEmailValidation: enableActiveEmailValidation.value,
 | 
			
		||||
		enableVerifymailApi: enableVerifymailApi.value,
 | 
			
		||||
		verifymailAuthKey: verifymailAuthKey.value,
 | 
			
		||||
		enableTruemailApi: enableTruemailApi.value,
 | 
			
		||||
		truemailInstance: truemailInstance.value,
 | 
			
		||||
		truemailAuthKey: truemailAuthKey.value,
 | 
			
		||||
		bannedEmailDomains: bannedEmailDomains.value.split('\n'),
 | 
			
		||||
	}).then(() => {
 | 
			
		||||
		fetchInstance();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue