新增规则触发人机验证和加载失败提示

This commit is contained in:
eoao
2025-07-29 20:00:00 +08:00
parent d03b7ca21d
commit 3a40cfc63b
25 changed files with 632 additions and 273 deletions

View File

@@ -6,21 +6,26 @@ import emailService from './email-service';
import orm from '../entity/orm';
import account from '../entity/account';
import { and, asc, eq, gt, inArray, count, sql } from 'drizzle-orm';
import { isDel } from '../const/entity-const';
import { isDel, settingConst } from '../const/entity-const';
import settingService from './setting-service';
import turnstileService from './turnstile-service';
import roleService from './role-service';
import { t } from '../i18n/i18n';
import verifyRecordService from './verify-record-service';
const accountService = {
async add(c, params, userId) {
if (!await settingService.isAddEmail(c)) {
const {addEmailVerify , addEmail, manyEmail, addVerifyCount} = await settingService.query(c);
let { email, token } = params;
if (!(addEmail === settingConst.addEmail.OPEN && manyEmail === settingConst.manyEmail.OPEN)) {
throw new BizError(t('addAccountDisabled'));
}
let { email, token } = params;
if (!email) {
throw new BizError(t('emptyEmail'));
@@ -35,7 +40,7 @@ const accountService = {
}
const accountRow = await this.selectByEmailIncludeDelNoCase(c, email);
let accountRow = await this.selectByEmailIncludeDelNoCase(c, email);
if (accountRow && accountRow.isDel === isDel.DELETE) {
throw new BizError(t('isDelAccount'));
@@ -61,11 +66,30 @@ const accountService = {
}
if (await settingService.isAddEmailVerify(c)) {
let addVerifyOpen = false
if (addEmailVerify === settingConst.addEmailVerify.OPEN) {
addVerifyOpen = true
await turnstileService.verify(c, token);
}
return orm(c).insert(account).values({ email: email, userId: userId, name: emailUtils.getName(email) }).returning().get();
if (addEmailVerify === settingConst.addEmailVerify.COUNT) {
addVerifyOpen = await verifyRecordService.isOpenAddVerify(c, addVerifyCount);
if (addVerifyOpen) {
await turnstileService.verify(c,token)
}
}
accountRow = await orm(c).insert(account).values({ email: email, userId: userId, name: emailUtils.getName(email) }).returning().get();
if (addEmailVerify === settingConst.addEmailVerify.COUNT && !addVerifyOpen) {
const row = await verifyRecordService.increaseAddCount(c);
addVerifyOpen = row.count >= addVerifyCount
}
accountRow.addVerifyOpen = addVerifyOpen
return accountRow;
},
selectByEmailIncludeDelNoCase(c, email) {

View File

@@ -18,6 +18,7 @@ import regKeyService from './reg-key-service';
import dayjs from 'dayjs';
import { toUtc } from '../utils/date-uitil';
import { t } from '../i18n/i18n.js';
import verifyRecordService from './verify-record-service';
const loginService = {
@@ -25,11 +26,8 @@ const loginService = {
const { email, password, token, code } = params;
const {regKey, register, registerVerify} = await settingService.query(c)
const {regKey, register, registerVerify, regVerifyCount} = await settingService.query(c)
if (registerVerify === settingConst.registerVerify.OPEN) {
await turnstileService.verify(c,token)
}
if (register === settingConst.register.CLOSE) {
throw new BizError(t('regDisabled'));
@@ -80,7 +78,6 @@ const loginService = {
throw new BizError(t('isRegAccount'));
}
const { salt, hash } = await saltHashUtils.hashPassword(password);
let defType = null
@@ -104,6 +101,22 @@ const loginService = {
}
let regVerifyOpen = false
if (registerVerify === settingConst.registerVerify.OPEN) {
regVerifyOpen = true
await turnstileService.verify(c,token)
}
if (registerVerify === settingConst.registerVerify.COUNT) {
regVerifyOpen = await verifyRecordService.isOpenRegVerify(c, regVerifyCount);
if (regVerifyOpen) {
await turnstileService.verify(c,token)
}
}
const { salt, hash } = await saltHashUtils.hashPassword(password);
const userId = await userService.insert(c, { email, regKeyId,password: hash, salt, type: type || defType });
await userService.updateUserInfo(c, userId, true);
@@ -114,6 +127,13 @@ const loginService = {
await regKeyService.reduceCount(c, code, 1);
}
if (registerVerify === settingConst.registerVerify.COUNT && !regVerifyOpen) {
const row = await verifyRecordService.increaseRegCount(c);
return {regVerifyOpen: row.count >= regVerifyCount}
}
return {regVerifyOpen}
},
async handleOpenRegKey(c, regKey, code) {

View File

@@ -1,7 +1,7 @@
import KvConst from '../const/kv-const';
import setting from '../entity/setting';
import orm from '../entity/orm';
import { settingConst } from '../const/entity-const';
import { settingConst, verifyRecordType } from '../const/entity-const';
import fileUtils from '../utils/file-utils';
import r2Service from './r2-service';
import emailService from './email-service';
@@ -10,6 +10,7 @@ import userService from './user-service';
import constant from '../const/constant';
import BizError from '../error/biz-error';
import { t } from '../i18n/i18n'
import verifyRecordService from './verify-record-service';
const settingService = {
@@ -31,11 +32,32 @@ const settingService = {
},
async get(c) {
const settingRow = await this.query(c);
const [settingRow, recordList] = await Promise.all([
await this.query(c),
verifyRecordService.selectListByIP(c)
]);
settingRow.secretKey = settingRow.secretKey ? `${settingRow.secretKey.slice(0, 12)}******` : null;
Object.keys(settingRow.resendTokens).forEach(key => {
settingRow.resendTokens[key] = `${settingRow.resendTokens[key].slice(0, 12)}******`;
});
let regVerifyOpen = false
let addVerifyOpen = false
recordList.forEach(row => {
if (row.type === verifyRecordType.REG) {
regVerifyOpen = row.count >= settingRow.regVerifyCount
}
if (row.type === verifyRecordType.ADD) {
addVerifyOpen = row.count >= settingRow.addVerifyCount
}
})
settingRow.regVerifyOpen = regVerifyOpen
settingRow.addVerifyOpen = addVerifyOpen
return settingRow;
},
@@ -50,28 +72,13 @@ const settingService = {
await this.refresh(c);
},
async isAddEmail(c) {
const { addEmail, manyEmail } = await this.query(c);
return addEmail === settingConst.addEmail.OPEN && manyEmail === settingConst.manyEmail.OPEN;
},
async isRegisterVerify(c) {
const { registerVerify } = await this.query(c);
return registerVerify === settingConst.registerVerify.OPEN;
},
async isAddEmailVerify(c) {
const { addEmailVerify } = await this.query(c);
return addEmailVerify === settingConst.addEmailVerify.OPEN;
},
async setBackground(c, params) {
const settingRow = await this.query(c);
let { background } = params
if (!background.startsWith('http')) {
if (background && !background.startsWith('http')) {
if (!c.env.r2) {
throw new BizError(t('noOsUpBack'));
@@ -113,7 +120,9 @@ const settingService = {
},
async websiteConfig(c) {
const settingRow = await this.get(c);
const settingRow = await this.get(c)
return {
register: settingRow.register,
title: settingRow.title,
@@ -128,7 +137,9 @@ const settingService = {
background: settingRow.background,
loginOpacity: settingRow.loginOpacity,
domainList:settingRow.domainList,
regKey: settingRow.regKey
regKey: settingRow.regKey,
regVerifyOpen: settingRow.regVerifyOpen,
addVerifyOpen: settingRow.addVerifyOpen
};
}
};

View File

@@ -7,7 +7,7 @@ const turnstileService = {
async verify(c, token) {
if (!token) {
throw new BizError(t('emptyBotToken'));
throw new BizError(t('emptyBotToken'),400);
}
const settingRow = await settingService.query(c)

View File

@@ -0,0 +1,90 @@
import orm from '../entity/orm';
import verifyRecord from '../entity/verify-record';
import { eq, sql, and } from 'drizzle-orm';
import dayjs from 'dayjs';
import ipUtils from '../utils/ip-utils';
import { verifyRecordType } from '../const/entity-const';
const verifyRecordService = {
async selectListByIP(c) {
const ip = ipUtils.getIp(c)
return orm(c).select().from(verifyRecord).where(eq(verifyRecord.ip, ip)).all();
},
async clearRecord(c) {
await orm(c).delete(verifyRecord).run();
},
async isOpenRegVerify(c, regVerifyCount) {
const ip = ipUtils.getIp(c)
const row = await orm(c).select().from(verifyRecord).where(and(eq(verifyRecord.ip, ip),eq(verifyRecord.type,verifyRecordType.REG))).get();
if (row) {
if (row.count >= regVerifyCount){
return true
}
}
return false
},
async isOpenAddVerify(c, addVerifyCount) {
const ip = ipUtils.getIp(c)
const row = await orm(c).select().from(verifyRecord).where(and(eq(verifyRecord.ip, ip),eq(verifyRecord.type,verifyRecordType.ADD))).get();
if (row) {
if (row.count >= addVerifyCount){
return true
}
}
return false
},
async increaseRegCount(c) {
const ip = ipUtils.getIp(c)
const row = await orm(c).select().from(verifyRecord).where(and(eq(verifyRecord.ip, ip),eq(verifyRecord.type,verifyRecordType.REG))).get();
const now = dayjs().format('YYYY-MM-DD HH:mm:ss');
if (row) {
return orm(c).update(verifyRecord).set({
count: sql`${verifyRecord.count}
+ 1`, updateTime: now
}).where(and(eq(verifyRecord.ip, ip),eq(verifyRecord.type,verifyRecordType.REG))).returning().get();
} else {
return orm(c).insert(verifyRecord).values({ip, type: verifyRecordType.REG}).returning().run();
}
},
async increaseAddCount(c) {
const ip = ipUtils.getIp(c)
const row = await orm(c).select().from(verifyRecord).where(and(eq(verifyRecord.ip, ip),eq(verifyRecord.type,verifyRecordType.ADD))).get();
const now = dayjs().format('YYYY-MM-DD HH:mm:ss');
if (row) {
return orm(c).update(verifyRecord).set({
count: sql`${verifyRecord.count}
+ 1`, updateTime: now
}).where(and(eq(verifyRecord.ip, ip),eq(verifyRecord.type,verifyRecordType.ADD))).returning().get();
} else {
return orm(c).insert(verifyRecord).values({ip, type: verifyRecordType.ADD}).returning().get();
}
}
};
export default verifyRecordService;