feat: add email regex validation for user registration (#835)

This commit is contained in:
Dream Hunter
2026-02-16 12:40:20 +08:00
committed by GitHub
parent 56351ed963
commit bde08b9d55
6 changed files with 47 additions and 1 deletions
+16
View File
@@ -21,6 +21,8 @@ const { t } = useI18n({
manualInputPrompt: 'Type and press Enter to add', manualInputPrompt: 'Type and press Enter to add',
mailAllowList: 'Mail Address Allow List', mailAllowList: 'Mail Address Allow List',
maxAddressCount: 'Maximum number of email addresses that can be binded', maxAddressCount: 'Maximum number of email addresses that can be binded',
emailCheckRegex: 'Email Check Regex (e.g. ^[^.]+@.+$ to disallow dots before @)',
enableEmailCheckRegex: 'Enable Email Check Regex',
}, },
zh: { zh: {
save: '保存', save: '保存',
@@ -33,6 +35,8 @@ const { t } = useI18n({
manualInputPrompt: '输入后按回车键添加', manualInputPrompt: '输入后按回车键添加',
mailAllowList: '邮件地址白名单', mailAllowList: '邮件地址白名单',
maxAddressCount: '可绑定最大邮箱地址数量', maxAddressCount: '可绑定最大邮箱地址数量',
emailCheckRegex: '邮箱正则校验 (例如 ^[^.]+@.+$ 禁止@前面有.)',
enableEmailCheckRegex: '启用邮箱正则校验',
} }
} }
}); });
@@ -53,6 +57,8 @@ const userSettings = ref({
enableMailAllowList: false, enableMailAllowList: false,
mailAllowList: commonMail, mailAllowList: commonMail,
maxAddressCount: 5, maxAddressCount: 5,
enableEmailCheckRegex: false,
emailCheckRegex: "",
}); });
const fetchData = async () => { const fetchData = async () => {
@@ -125,6 +131,16 @@ onMounted(async () => {
:placeholder="t('maxAddressCount')" /> :placeholder="t('maxAddressCount')" />
</n-input-group> </n-input-group>
</n-form-item-row> </n-form-item-row>
<n-form-item-row :label="t('enableEmailCheckRegex')">
<n-input-group>
<n-checkbox v-model:checked="userSettings.enableEmailCheckRegex" style="width: 20%;">
{{ t('enable') }}
</n-checkbox>
<n-input v-model:value="userSettings.emailCheckRegex"
v-if="userSettings.enableEmailCheckRegex"
style="width: 80%;" :placeholder="t('emailCheckRegex')" />
</n-input-group>
</n-form-item-row>
</n-form> </n-form>
</n-card> </n-card>
</div> </div>
+1
View File
@@ -26,6 +26,7 @@ const messages: LocaleMessages = {
FailedToRegisterMsg: "Failed to register", FailedToRegisterMsg: "Failed to register",
UserRegistrationDisabledMsg: "User registration is disabled, please contact the administrator", UserRegistrationDisabledMsg: "User registration is disabled, please contact the administrator",
UserMailDomainMustInMsg: "User mail domain must be in this list", UserMailDomainMustInMsg: "User mail domain must be in this list",
UserEmailNotMatchRegexMsg: "Email address format does not match the required pattern",
InvalidVerifyCodeMsg: "Invalid verify code", InvalidVerifyCodeMsg: "Invalid verify code",
InvalidEmailOrPasswordMsg: "Invalid email or password", InvalidEmailOrPasswordMsg: "Invalid email or password",
VerifyMailSenderNotSetMsg: "Verify mail sender address is not set, please contact the administrator", VerifyMailSenderNotSetMsg: "Verify mail sender address is not set, please contact the administrator",
+1
View File
@@ -24,6 +24,7 @@ export type LocaleMessages = {
FailedToRegisterMsg: string FailedToRegisterMsg: string
UserRegistrationDisabledMsg: string UserRegistrationDisabledMsg: string
UserMailDomainMustInMsg: string UserMailDomainMustInMsg: string
UserEmailNotMatchRegexMsg: string
InvalidVerifyCodeMsg: string InvalidVerifyCodeMsg: string
InvalidEmailOrPasswordMsg: string InvalidEmailOrPasswordMsg: string
VerifyMailSenderNotSetMsg: string VerifyMailSenderNotSetMsg: string
+1
View File
@@ -26,6 +26,7 @@ const messages: LocaleMessages = {
FailedToRegisterMsg: "注册失败", FailedToRegisterMsg: "注册失败",
UserRegistrationDisabledMsg: "用户注册已禁用, 请联系管理员", UserRegistrationDisabledMsg: "用户注册已禁用, 请联系管理员",
UserMailDomainMustInMsg: "用户邮箱域必须在此列表中", UserMailDomainMustInMsg: "用户邮箱域必须在此列表中",
UserEmailNotMatchRegexMsg: "邮箱地址格式不符合要求",
InvalidVerifyCodeMsg: "无效的验证码", InvalidVerifyCodeMsg: "无效的验证码",
InvalidEmailOrPasswordMsg: "无效的邮箱或密码", InvalidEmailOrPasswordMsg: "无效的邮箱或密码",
VerifyMailSenderNotSetMsg: "验证邮件发送邮箱未设置, 请联系管理员", VerifyMailSenderNotSetMsg: "验证邮件发送邮箱未设置, 请联系管理员",
+6 -1
View File
@@ -99,11 +99,14 @@ export class UserSettings {
enableMailAllowList: boolean | undefined; enableMailAllowList: boolean | undefined;
mailAllowList: string[] | undefined; mailAllowList: string[] | undefined;
maxAddressCount: number; maxAddressCount: number;
enableEmailCheckRegex: boolean | undefined;
emailCheckRegex: string | undefined;
constructor(data: UserSettings | undefined | null) { constructor(data: UserSettings | undefined | null) {
const { const {
enable, enableMailVerify, verifyMailSender, enable, enableMailVerify, verifyMailSender,
enableMailAllowList, mailAllowList, maxAddressCount enableMailAllowList, mailAllowList, maxAddressCount,
enableEmailCheckRegex, emailCheckRegex
} = data || {}; } = data || {};
this.enable = enable; this.enable = enable;
this.enableMailVerify = enableMailVerify; this.enableMailVerify = enableMailVerify;
@@ -111,6 +114,8 @@ export class UserSettings {
this.enableMailAllowList = enableMailAllowList; this.enableMailAllowList = enableMailAllowList;
this.mailAllowList = mailAllowList; this.mailAllowList = mailAllowList;
this.maxAddressCount = maxAddressCount || 5; this.maxAddressCount = maxAddressCount || 5;
this.enableEmailCheckRegex = enableEmailCheckRegex;
this.emailCheckRegex = emailCheckRegex;
} }
} }
+22
View File
@@ -27,6 +27,17 @@ export default {
) { ) {
return c.text(`${msgs.UserMailDomainMustInMsg} ${JSON.stringify(settings.mailAllowList, null, 2)}`, 400) return c.text(`${msgs.UserMailDomainMustInMsg} ${JSON.stringify(settings.mailAllowList, null, 2)}`, 400)
} }
// check email regex
if (settings.enableEmailCheckRegex && settings.emailCheckRegex) {
try {
const regex = new RegExp(settings.emailCheckRegex);
if (!regex.test(email)) {
return c.text(`${msgs.UserEmailNotMatchRegexMsg}: /${settings.emailCheckRegex}/`, 400)
}
} catch (e) {
console.error("Failed to check user email regex", e);
}
}
if (!settings.verifyMailSender) { if (!settings.verifyMailSender) {
return c.text(msgs.VerifyMailSenderNotSetMsg, 400) return c.text(msgs.VerifyMailSenderNotSetMsg, 400)
} }
@@ -82,6 +93,17 @@ export default {
) { ) {
return c.text(`${msgs.UserMailDomainMustInMsg} ${JSON.stringify(settings.mailAllowList, null, 2)}`, 400) return c.text(`${msgs.UserMailDomainMustInMsg} ${JSON.stringify(settings.mailAllowList, null, 2)}`, 400)
} }
// check email regex
if (settings.enableEmailCheckRegex && settings.emailCheckRegex) {
try {
const regex = new RegExp(settings.emailCheckRegex);
if (!regex.test(email)) {
return c.text(`${msgs.UserEmailNotMatchRegexMsg}: /${settings.emailCheckRegex}/`, 400)
}
} catch (e) {
console.error("Failed to check user email regex", e);
}
}
// check code // check code
if (settings.enableMailVerify) { if (settings.enableMailVerify) {
const verifyCode = await c.env.KV.get(`temp-mail:${email}`) const verifyCode = await c.env.KV.get(`temp-mail:${email}`)