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
|
@bindThis
|
||||||
public async validateEmailForAccount(emailAddress: string): Promise<{
|
public async validateEmailForAccount(emailAddress: string): Promise<{
|
||||||
available: boolean;
|
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();
|
const meta = await this.metaService.fetch();
|
||||||
|
|
||||||
|
@ -173,6 +173,8 @@ export class EmailService {
|
||||||
if (meta.enableActiveEmailValidation) {
|
if (meta.enableActiveEmailValidation) {
|
||||||
if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) {
|
if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) {
|
||||||
validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey);
|
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 {
|
} else {
|
||||||
validated = await validateEmail({
|
validated = await validateEmail({
|
||||||
email: emailAddress,
|
email: emailAddress,
|
||||||
|
@ -201,6 +203,8 @@ export class EmailService {
|
||||||
validated.reason === 'disposable' ? 'disposable' :
|
validated.reason === 'disposable' ? 'disposable' :
|
||||||
validated.reason === 'mx' ? 'mx' :
|
validated.reason === 'mx' ? 'mx' :
|
||||||
validated.reason === 'smtp' ? 'smtp' :
|
validated.reason === 'smtp' ? 'smtp' :
|
||||||
|
validated.reason === 'network' ? 'network' :
|
||||||
|
validated.reason === 'blacklist' ? 'blacklist' :
|
||||||
null,
|
null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -265,4 +269,67 @@ export class EmailService {
|
||||||
reason: null,
|
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;
|
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', {
|
@Column('boolean', {
|
||||||
default: true,
|
default: true,
|
||||||
})
|
})
|
||||||
|
|
|
@ -284,6 +284,18 @@ export const meta = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
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: {
|
enableChartsForRemoteUser: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
@ -520,6 +532,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
||||||
enableVerifymailApi: instance.enableVerifymailApi,
|
enableVerifymailApi: instance.enableVerifymailApi,
|
||||||
verifymailAuthKey: instance.verifymailAuthKey,
|
verifymailAuthKey: instance.verifymailAuthKey,
|
||||||
|
enableTruemailApi: instance.enableTruemailApi,
|
||||||
|
truemailInstance: instance.truemailInstance,
|
||||||
|
truemailAuthKey: instance.truemailAuthKey,
|
||||||
enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
|
enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
|
||||||
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
|
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
|
||||||
enableServerMachineStats: instance.enableServerMachineStats,
|
enableServerMachineStats: instance.enableServerMachineStats,
|
||||||
|
|
|
@ -116,6 +116,9 @@ export const paramDef = {
|
||||||
enableActiveEmailValidation: { type: 'boolean' },
|
enableActiveEmailValidation: { type: 'boolean' },
|
||||||
enableVerifymailApi: { type: 'boolean' },
|
enableVerifymailApi: { type: 'boolean' },
|
||||||
verifymailAuthKey: { type: 'string', nullable: true },
|
verifymailAuthKey: { type: 'string', nullable: true },
|
||||||
|
enableTruemailApi: { type: 'boolean' },
|
||||||
|
truemailInstance: { type: 'string', nullable: true },
|
||||||
|
truemailAuthKey: { type: 'string', nullable: true },
|
||||||
enableChartsForRemoteUser: { type: 'boolean' },
|
enableChartsForRemoteUser: { type: 'boolean' },
|
||||||
enableChartsForFederatedInstances: { type: 'boolean' },
|
enableChartsForFederatedInstances: { type: 'boolean' },
|
||||||
enableServerMachineStats: { type: 'boolean' },
|
enableServerMachineStats: { type: 'boolean' },
|
||||||
|
@ -469,6 +472,26 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.verifymailAuthKey = ps.verifymailAuthKey;
|
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) {
|
if (ps.enableChartsForRemoteUser !== undefined) {
|
||||||
set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser;
|
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 #prefix><i class="ti ti-key"></i></template>
|
||||||
<template #label>Verifymail.io API Auth Key</template>
|
<template #label>Verifymail.io API Auth Key</template>
|
||||||
</MkInput>
|
</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>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
@ -153,6 +164,9 @@ const enableIpLogging = ref<boolean>(false);
|
||||||
const enableActiveEmailValidation = ref<boolean>(false);
|
const enableActiveEmailValidation = ref<boolean>(false);
|
||||||
const enableVerifymailApi = ref<boolean>(false);
|
const enableVerifymailApi = ref<boolean>(false);
|
||||||
const verifymailAuthKey = ref<string | null>(null);
|
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>('');
|
const bannedEmailDomains = ref<string>('');
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
|
@ -194,6 +208,9 @@ function save() {
|
||||||
enableActiveEmailValidation: enableActiveEmailValidation.value,
|
enableActiveEmailValidation: enableActiveEmailValidation.value,
|
||||||
enableVerifymailApi: enableVerifymailApi.value,
|
enableVerifymailApi: enableVerifymailApi.value,
|
||||||
verifymailAuthKey: verifymailAuthKey.value,
|
verifymailAuthKey: verifymailAuthKey.value,
|
||||||
|
enableTruemailApi: enableTruemailApi.value,
|
||||||
|
truemailInstance: truemailInstance.value,
|
||||||
|
truemailAuthKey: truemailAuthKey.value,
|
||||||
bannedEmailDomains: bannedEmailDomains.value.split('\n'),
|
bannedEmailDomains: bannedEmailDomains.value.split('\n'),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance();
|
||||||
|
|
Loading…
Reference in a new issue