新增规则触发人机验证和加载失败提示
This commit is contained in:
@@ -255,7 +255,11 @@ const en = {
|
|||||||
backgroundUrlDesc: 'Image URL',
|
backgroundUrlDesc: 'Image URL',
|
||||||
localUpload: ' Local upload',
|
localUpload: ' Local upload',
|
||||||
imageLink: 'Image URL',
|
imageLink: 'Image URL',
|
||||||
backgroundWarning: 'Image file size affects website load speed.'
|
imageLinkErrorMsg: 'Invalid image URL',
|
||||||
|
backgroundWarning: 'Image file size affects website load speed.',
|
||||||
|
rulesVerify: 'Rules',
|
||||||
|
rulesVerifyTitle: 'Trigger After {count} Daily Uses per IP',
|
||||||
|
botVerifyMsg: 'Please verify that you are human',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default en
|
export default en
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import zh from './zh.js'
|
|||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
legacy: false,
|
legacy: false,
|
||||||
messages: {
|
messages: {
|
||||||
en,
|
zh,
|
||||||
zh
|
en
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -255,6 +255,10 @@ const zh = {
|
|||||||
backgroundUrlDesc: '在线图片链接',
|
backgroundUrlDesc: '在线图片链接',
|
||||||
localUpload: '本地上传',
|
localUpload: '本地上传',
|
||||||
imageLink: '图片链接',
|
imageLink: '图片链接',
|
||||||
|
imageLinkErrorMsg: '图片链接不正确',
|
||||||
backgroundWarning: '图片文件大小会影响网站加载速度',
|
backgroundWarning: '图片文件大小会影响网站加载速度',
|
||||||
|
rulesVerify: '规则',
|
||||||
|
rulesVerifyTitle: 'IP 每天使用 {count} 次后触发',
|
||||||
|
botVerifyMsg: '请完成人机验证',
|
||||||
}
|
}
|
||||||
export default zh
|
export default zh
|
||||||
@@ -6,6 +6,7 @@ import {permsToRouter} from "@/perm/perm.js";
|
|||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import {websiteConfig} from "@/request/setting.js";
|
import {websiteConfig} from "@/request/setting.js";
|
||||||
import {cvtR2Url} from "@/utils/convert.js";
|
import {cvtR2Url} from "@/utils/convert.js";
|
||||||
|
import i18n from "@/i18n/index.js";
|
||||||
|
|
||||||
export async function init() {
|
export async function init() {
|
||||||
document.title = '\u200B'
|
document.title = '\u200B'
|
||||||
@@ -15,11 +16,12 @@ export async function init() {
|
|||||||
const accountStore = useAccountStore();
|
const accountStore = useAccountStore();
|
||||||
|
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
|
|
||||||
if (!settingStore.lang) {
|
if (!settingStore.lang) {
|
||||||
settingStore.lang = navigator.language.split('-')[0]
|
settingStore.lang = navigator.language.split('-')[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i18n.global.locale.value = settingStore.lang
|
||||||
|
|
||||||
let setting = null;
|
let setting = null;
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|||||||
@@ -103,7 +103,10 @@
|
|||||||
:class="verifyShow ? 'turnstile-show' : 'turnstile-hide'"
|
:class="verifyShow ? 'turnstile-show' : 'turnstile-hide'"
|
||||||
:data-sitekey="settingStore.settings.siteKey"
|
:data-sitekey="settingStore.settings.siteKey"
|
||||||
data-callback="onTurnstileSuccess"
|
data-callback="onTurnstileSuccess"
|
||||||
></div>
|
data-error-callback="onTurnstileError"
|
||||||
|
>
|
||||||
|
<span style="font-size: 12px;color: #F56C6C" v-if="botJsError">人机验证模块加载失败,请刷新浏览器</span>
|
||||||
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog v-model="setNameShow" :title="$t('changeUserName')" >
|
<el-dialog v-model="setNameShow" :title="$t('changeUserName')" >
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -145,6 +148,7 @@ const accountName = ref(null)
|
|||||||
const addRef = ref({})
|
const addRef = ref({})
|
||||||
let account = null
|
let account = null
|
||||||
let turnstileId = null
|
let turnstileId = null
|
||||||
|
const botJsError = ref(false)
|
||||||
let verifyToken = ''
|
let verifyToken = ''
|
||||||
const addForm = reactive({
|
const addForm = reactive({
|
||||||
email: '',
|
email: '',
|
||||||
@@ -170,11 +174,19 @@ const openSelect = () => {
|
|||||||
mySelect.value.toggleMenu()
|
mySelect.value.toggleMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.onTurnstileError = (e) => {
|
||||||
|
console.log('人机验加载失败')
|
||||||
|
nextTick(() => {
|
||||||
|
if (!turnstileId) {
|
||||||
|
turnstileId = window.turnstile.render('.register-turnstile')
|
||||||
|
} else {
|
||||||
|
window.turnstile.reset(turnstileId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
window.onTurnstileSuccess = (token) => {
|
window.onTurnstileSuccess = (token) => {
|
||||||
verifyToken = token;
|
verifyToken = token;
|
||||||
setTimeout(() => {
|
|
||||||
verifyShow.value = false
|
|
||||||
},1500)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function setName() {
|
function setName() {
|
||||||
@@ -338,14 +350,27 @@ function submit() {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!verifyToken && settingStore.settings.addEmailVerify === 0) {
|
if (!verifyToken && (settingStore.settings.addEmailVerify === 0 || (settingStore.settings.addEmailVerify === 2 && settingStore.settings.addVerifyOpen))) {
|
||||||
verifyShow.value = true
|
if (!verifyShow.value) {
|
||||||
if (!turnstileId) {
|
verifyShow.value = true
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
turnstileId = window.turnstile.render('.add-email-turnstile')
|
if (!turnstileId) {
|
||||||
|
try {
|
||||||
|
turnstileId = window.turnstile.render('.add-email-turnstile')
|
||||||
|
} catch (e) {
|
||||||
|
botJsError.value = true
|
||||||
|
console.log('人机验证js加载失败')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.turnstile.reset('.add-email-turnstile')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (!botJsError.value) {
|
||||||
|
ElMessage({
|
||||||
|
message: t('botVerifyMsg'),
|
||||||
|
type: "error",
|
||||||
|
plain: true
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
window.turnstile.reset(turnstileId)
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -357,16 +382,24 @@ function submit() {
|
|||||||
addForm.email = ''
|
addForm.email = ''
|
||||||
accounts.push(account)
|
accounts.push(account)
|
||||||
verifyToken = ''
|
verifyToken = ''
|
||||||
|
settingStore.settings.addVerifyOpen = account.addVerifyOpen
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: t('addSuccessMsg'),
|
message: t('addSuccessMsg'),
|
||||||
type: "success",
|
type: "success",
|
||||||
plain: true
|
plain: true
|
||||||
})
|
})
|
||||||
|
verifyShow.value = false
|
||||||
userStore.refreshUserInfo()
|
userStore.refreshUserInfo()
|
||||||
}).catch(res => {
|
}).catch(res => {
|
||||||
if (res.code === 400) {
|
if (res.code === 400) {
|
||||||
verifyToken = ''
|
verifyToken = ''
|
||||||
window.turnstile.reset(turnstileId)
|
if (turnstileId) {
|
||||||
|
window.turnstile.reset(turnstileId)
|
||||||
|
} else {
|
||||||
|
nextTick(() => {
|
||||||
|
turnstileId = window.turnstile.render('.add-email-turnstile')
|
||||||
|
})
|
||||||
|
}
|
||||||
verifyShow.value = true
|
verifyShow.value = true
|
||||||
}
|
}
|
||||||
addLoading.value = false
|
addLoading.value = false
|
||||||
|
|||||||
@@ -13,11 +13,12 @@
|
|||||||
<span class="form-title">{{settingStore.settings.title}}</span>
|
<span class="form-title">{{settingStore.settings.title}}</span>
|
||||||
<span class="form-desc" v-if="show === 'login'">{{$t('loginTitle')}}</span>
|
<span class="form-desc" v-if="show === 'login'">{{$t('loginTitle')}}</span>
|
||||||
<span class="form-desc" v-else>{{$t('regTitle')}}</span>
|
<span class="form-desc" v-else>{{$t('regTitle')}}</span>
|
||||||
<div v-if="show === 'login'">
|
<div v-show="show === 'login'">
|
||||||
<el-input class="email-input" v-model="form.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
<el-input class="email-input" v-model="form.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||||
<template #append>
|
<template #append>
|
||||||
<div @click.stop="openSelect">
|
<div @click.stop="openSelect">
|
||||||
<el-select
|
<el-select
|
||||||
|
v-if="show === 'login'"
|
||||||
ref="mySelect"
|
ref="mySelect"
|
||||||
v-model="suffix"
|
v-model="suffix"
|
||||||
:placeholder="$t('select')"
|
:placeholder="$t('select')"
|
||||||
@@ -43,11 +44,12 @@
|
|||||||
>{{$t('loginBtn')}}
|
>{{$t('loginBtn')}}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-show="show !== 'login'">
|
||||||
<el-input class="email-input" v-model="registerForm.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
<el-input class="email-input" v-model="registerForm.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||||
<template #append>
|
<template #append>
|
||||||
<div @click.stop="openSelect">
|
<div @click.stop="openSelect">
|
||||||
<el-select
|
<el-select
|
||||||
|
v-if="show !== 'login'"
|
||||||
ref="mySelect"
|
ref="mySelect"
|
||||||
v-model="suffix"
|
v-model="suffix"
|
||||||
:placeholder="$t('select')"
|
:placeholder="$t('select')"
|
||||||
@@ -75,7 +77,12 @@
|
|||||||
class="register-turnstile"
|
class="register-turnstile"
|
||||||
:data-sitekey="settingStore.settings.siteKey"
|
:data-sitekey="settingStore.settings.siteKey"
|
||||||
data-callback="onTurnstileSuccess"
|
data-callback="onTurnstileSuccess"
|
||||||
></div>
|
data-error-callback="onTurnstileError"
|
||||||
|
data-after-interactive-callback="loadAfter"
|
||||||
|
data-before-interactive-callback="loadBefore"
|
||||||
|
>
|
||||||
|
<span style="font-size: 12px;color: #F56C6C" v-if="botJsError">人机验证模块加载失败,请刷新浏览器</span>
|
||||||
|
</div>
|
||||||
<el-button class="btn" type="primary" @click="submitRegister" :loading="registerLoading"
|
<el-button class="btn" type="primary" @click="submitRegister" :loading="registerLoading"
|
||||||
>{{$t('regBtn')}}
|
>{{$t('regBtn')}}
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -129,15 +136,30 @@ suffix.value = domainList[0]
|
|||||||
const verifyShow = ref(false)
|
const verifyShow = ref(false)
|
||||||
let verifyToken = ''
|
let verifyToken = ''
|
||||||
let turnstileId = null
|
let turnstileId = null
|
||||||
|
let botJsError = ref(false)
|
||||||
|
|
||||||
window.onTurnstileSuccess = (token) => {
|
window.onTurnstileSuccess = (token) => {
|
||||||
verifyToken = token;
|
verifyToken = token;
|
||||||
setTimeout(() => {
|
|
||||||
verifyShow.value = false
|
|
||||||
}, 2000)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.onTurnstileError = (e) => {
|
||||||
|
console.log('人机验加载失败')
|
||||||
|
nextTick(() => {
|
||||||
|
if (!turnstileId) {
|
||||||
|
turnstileId = window.turnstile.render('.register-turnstile')
|
||||||
|
} else {
|
||||||
|
window.turnstile.reset(turnstileId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
window.loadAfter = (e) => {
|
||||||
|
console.log('loadAfter')
|
||||||
|
}
|
||||||
|
|
||||||
|
window.loadBefore = (e) => {
|
||||||
|
console.log('loadBefore')
|
||||||
|
}
|
||||||
|
|
||||||
const loginOpacity = computed(() => {
|
const loginOpacity = computed(() => {
|
||||||
return `rgba(255, 255, 255, ${settingStore.settings.loginOpacity})`
|
return `rgba(255, 255, 255, ${settingStore.settings.loginOpacity})`
|
||||||
@@ -158,7 +180,6 @@ const openSelect = () => {
|
|||||||
mySelect.value.toggleMenu()
|
mySelect.value.toggleMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
|
|
||||||
if (!form.email) {
|
if (!form.email) {
|
||||||
@@ -267,15 +288,26 @@ function submitRegister() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verifyToken && settingStore.settings.registerVerify === 0) {
|
if (!verifyToken && (settingStore.settings.registerVerify === 0 || (settingStore.settings.registerVerify === 2 && settingStore.settings.regVerifyOpen))) {
|
||||||
verifyShow.value = true
|
if (!verifyShow.value) {
|
||||||
if (!turnstileId) {
|
verifyShow.value = true
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
turnstileId = window.turnstile.render('.register-turnstile')
|
if (!turnstileId) {
|
||||||
|
try {
|
||||||
|
turnstileId = window.turnstile.render('.register-turnstile')
|
||||||
|
} catch (e) {
|
||||||
|
botJsError.value = true
|
||||||
|
console.log('人机验证js加载失败')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.turnstile.reset('.register-turnstile')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else if (!botJsError.value) {
|
||||||
nextTick(() => {
|
ElMessage({
|
||||||
window.turnstile.reset(turnstileId);
|
message: t('botVerifyMsg'),
|
||||||
|
type: "error",
|
||||||
|
plain: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -290,27 +322,38 @@ function submitRegister() {
|
|||||||
code: registerForm.code
|
code: registerForm.code
|
||||||
}
|
}
|
||||||
|
|
||||||
register(form).then(() => {
|
register(form).then(({regVerifyOpen}) => {
|
||||||
show.value = 'login'
|
show.value = 'login'
|
||||||
registerForm.email = ''
|
registerForm.email = ''
|
||||||
registerForm.password = ''
|
registerForm.password = ''
|
||||||
registerForm.confirmPassword = ''
|
registerForm.confirmPassword = ''
|
||||||
registerForm.code = ''
|
registerForm.code = ''
|
||||||
registerLoading.value = false
|
registerLoading.value = false
|
||||||
turnstileId = null
|
|
||||||
verifyToken = ''
|
verifyToken = ''
|
||||||
|
settingStore.settings.regVerifyOpen = regVerifyOpen
|
||||||
|
verifyShow.value = false
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: t('regSuccessMsg'),
|
message: t('regSuccessMsg'),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
plain: true,
|
plain: true,
|
||||||
})
|
})
|
||||||
}).catch(res => {
|
}).catch(res => {
|
||||||
|
|
||||||
|
registerLoading.value = false
|
||||||
|
|
||||||
if (res.code === 400) {
|
if (res.code === 400) {
|
||||||
verifyToken = ''
|
verifyToken = ''
|
||||||
window.turnstile.reset(turnstileId)
|
settingStore.settings.regVerifyOpen = true
|
||||||
|
if (turnstileId) {
|
||||||
|
window.turnstile.reset(turnstileId)
|
||||||
|
} else {
|
||||||
|
nextTick(() => {
|
||||||
|
turnstileId = window.turnstile.render('.register-turnstile')
|
||||||
|
})
|
||||||
|
}
|
||||||
verifyShow.value = true
|
verifyShow.value = true
|
||||||
|
|
||||||
}
|
}
|
||||||
registerLoading.value = false
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -230,15 +230,39 @@
|
|||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<div><span>{{$t('signUpVerification')}}</span></div>
|
<div><span>{{$t('signUpVerification')}}</span></div>
|
||||||
<div>
|
<div>
|
||||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
<el-button class="opt-button" size="small" type="primary" @click="openRegVerifyCount">
|
||||||
v-model="setting.registerVerify"/>
|
<Icon icon="fluent:settings-48-regular" width="18" height="18"/>
|
||||||
|
</el-button>
|
||||||
|
<el-select
|
||||||
|
@change="change"
|
||||||
|
:style="`width: ${ locale === 'en' ? 100 : 80 }px;`"
|
||||||
|
v-model="setting.registerVerify"
|
||||||
|
placeholder="Select"
|
||||||
|
class="bot-verify-select"
|
||||||
|
>
|
||||||
|
<el-option key="1" :value="0" :label="$t('enable')" />
|
||||||
|
<el-option key="1" :value="1" :label="$t('disable')" />
|
||||||
|
<el-option key="1" :value="2" :label="$t('rulesVerify')" />
|
||||||
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<div><span>{{$t('addEmailVerification')}}</span></div>
|
<div><span>{{$t('addEmailVerification')}}</span></div>
|
||||||
<div>
|
<div>
|
||||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
<el-button class="opt-button" size="small" type="primary" @click="openAddVerifyCount">
|
||||||
v-model="setting.addEmailVerify"/>
|
<Icon icon="fluent:settings-48-regular" width="18" height="18"/>
|
||||||
|
</el-button>
|
||||||
|
<el-select
|
||||||
|
@change="change"
|
||||||
|
:style="`width: ${ locale === 'en' ? 100 : 80 }px;`"
|
||||||
|
v-model="setting.addEmailVerify"
|
||||||
|
placeholder="Select"
|
||||||
|
class="bot-verify-select"
|
||||||
|
>
|
||||||
|
<el-option key="1" :value="0" :label="$t('enable')" />
|
||||||
|
<el-option key="1" :value="1" :label="$t('disable')" />
|
||||||
|
<el-option key="1" :value="2" :label="$t('rulesVerify')" />
|
||||||
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
@@ -450,6 +474,19 @@
|
|||||||
<el-table-column :width="tokenColumnWidth" property="value" label="Token" fixed="right" :show-overflow-tooltip="true" />
|
<el-table-column :width="tokenColumnWidth" property="value" label="Token" fixed="right" :show-overflow-tooltip="true" />
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog v-model="showRegVerifyCount" :title="$t('rulesVerifyTitle',{count: regVerifyCount})" @closed="regVerifyCount = setting.regVerifyCount" >
|
||||||
|
<form>
|
||||||
|
<el-input-number type="text" v-model="regVerifyCount" :min="1" >
|
||||||
|
</el-input-number>
|
||||||
|
<el-button type="primary" :loading="settingLoading" @click="saveRegVerifyCount">{{$t('save')}}</el-button>
|
||||||
|
</form>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog v-model="showAddVerifyCount" :title="$t('rulesVerifyTitle',{count: addVerifyCount})" @closed="addVerifyCount = setting.addVerifyCount">
|
||||||
|
<form>
|
||||||
|
<el-input-number type="text" v-model="addVerifyCount" :min="1"/>
|
||||||
|
<el-button type="primary" :loading="settingLoading" @click="saveAddVerifyCount">{{$t('save')}}</el-button>
|
||||||
|
</form>
|
||||||
|
</el-dialog>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -497,7 +534,11 @@ const loginOpacity = ref(0)
|
|||||||
const backgroundUrl = ref('')
|
const backgroundUrl = ref('')
|
||||||
let backgroundFile = {}
|
let backgroundFile = {}
|
||||||
const showSetBackground = ref(false)
|
const showSetBackground = ref(false)
|
||||||
|
let regVerifyCount = ref(1)
|
||||||
|
let addVerifyCount = ref(1)
|
||||||
let backup = '{}'
|
let backup = '{}'
|
||||||
|
const showAddVerifyCount = ref(false)
|
||||||
|
const showRegVerifyCount = ref(false)
|
||||||
const resendTokenForm = reactive({
|
const resendTokenForm = reactive({
|
||||||
domain: '',
|
domain: '',
|
||||||
token: '',
|
token: '',
|
||||||
@@ -542,8 +583,20 @@ settingQuery().then(settingData => {
|
|||||||
backgroundUrl.value = setting.value.background?.startsWith('http') ? setting.value.background : ''
|
backgroundUrl.value = setting.value.background?.startsWith('http') ? setting.value.background : ''
|
||||||
editTitle.value = setting.value.title
|
editTitle.value = setting.value.title
|
||||||
r2DomainInput.value = setting.value.r2Domain
|
r2DomainInput.value = setting.value.r2Domain
|
||||||
|
addVerifyCount.value = setting.value.addVerifyCount
|
||||||
|
regVerifyCount.value = setting.value.regVerifyCount
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function openAddVerifyCount() {
|
||||||
|
if (settingLoading.value) return
|
||||||
|
showAddVerifyCount.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function openRegVerifyCount() {
|
||||||
|
if (settingLoading.value) return
|
||||||
|
showRegVerifyCount.value = true
|
||||||
|
}
|
||||||
|
|
||||||
const resendList = computed(() => {
|
const resendList = computed(() => {
|
||||||
|
|
||||||
let list = Object.keys(setting.value.resendTokens).map(key => {
|
let list = Object.keys(setting.value.resendTokens).map(key => {
|
||||||
@@ -566,6 +619,20 @@ const resendList = computed(() => {
|
|||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function saveAddVerifyCount() {
|
||||||
|
if(!addVerifyCount.value) {
|
||||||
|
addVerifyCount.value = 1
|
||||||
|
}
|
||||||
|
editSetting({addVerifyCount: addVerifyCount.value})
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveRegVerifyCount() {
|
||||||
|
if (!regVerifyCount.value) {
|
||||||
|
regVerifyCount.value = 1
|
||||||
|
}
|
||||||
|
editSetting({regVerifyCount: regVerifyCount.value})
|
||||||
|
}
|
||||||
|
|
||||||
const compareByLengthAndUpperCase = (a, b, key) => {
|
const compareByLengthAndUpperCase = (a, b, key) => {
|
||||||
const getUpperCaseCount = (str) => (str.match(/[A-Z]/g) || []).length;
|
const getUpperCaseCount = (str) => (str.match(/[A-Z]/g) || []).length;
|
||||||
if (a[key].length === b[key].length) {
|
if (a[key].length === b[key].length) {
|
||||||
@@ -742,9 +809,9 @@ async function saveBackground() {
|
|||||||
if (localUpShow.value) {
|
if (localUpShow.value) {
|
||||||
image = await fileToBase64(backgroundFile,true);
|
image = await fileToBase64(backgroundFile,true);
|
||||||
} else {
|
} else {
|
||||||
if (!backgroundUrl.value.startsWith('http')) {
|
if (backgroundUrl.value && !backgroundUrl.value.startsWith('http')) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '图片地址不正确',
|
message: t('imageLinkErrorMsg'),
|
||||||
type: "error",
|
type: "error",
|
||||||
plain: true
|
plain: true
|
||||||
})
|
})
|
||||||
@@ -872,8 +939,9 @@ function editSetting(settingForm, refreshStatus = true) {
|
|||||||
tgSettingShow.value = false
|
tgSettingShow.value = false
|
||||||
thirdEmailShow.value = false
|
thirdEmailShow.value = false
|
||||||
forwardRulesShow.value = false
|
forwardRulesShow.value = false
|
||||||
|
showAddVerifyCount.value = false
|
||||||
|
showRegVerifyCount.value = false
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.error(e)
|
|
||||||
loginOpacity.value = setting.value.loginOpacity
|
loginOpacity.value = setting.value.loginOpacity
|
||||||
setting.value = {...setting.value, ...JSON.parse(backup)}
|
setting.value = {...setting.value, ...JSON.parse(backup)}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -941,7 +1009,9 @@ function editSetting(settingForm, refreshStatus = true) {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bot-verify-select {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.settings-card {
|
.settings-card {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
193
mail-worker/dist/assets/index-BOcWPX50.js
vendored
193
mail-worker/dist/assets/index-BOcWPX50.js
vendored
File diff suppressed because one or more lines are too long
193
mail-worker/dist/assets/index-BwB6muO3.js
vendored
Normal file
193
mail-worker/dist/assets/index-BwB6muO3.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
mail-worker/dist/index.html
vendored
4
mail-worker/dist/index.html
vendored
@@ -6,8 +6,8 @@
|
|||||||
<title></title>
|
<title></title>
|
||||||
<link rel="icon" href="/assets/favicon-C5dAZutX.svg" type="image/svg+xml">
|
<link rel="icon" href="/assets/favicon-C5dAZutX.svg" type="image/svg+xml">
|
||||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
||||||
<script type="module" crossorigin src="/assets/index-BOcWPX50.js"></script>
|
<script type="module" crossorigin src="/assets/index-BwB6muO3.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CTj27R8v.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-BEDjT-8v.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="loading-first">
|
<div id="loading-first">
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
import app from '../hono/hono';
|
import app from '../hono/hono';
|
||||||
|
import result from '../model/result';
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import verifyRecordService from '../service/verify-record-service';
|
||||||
|
|
||||||
export const userConst = {
|
export const userConst = {
|
||||||
status: {
|
status: {
|
||||||
NORMAL: 0,
|
NORMAL: 0,
|
||||||
@@ -74,7 +76,7 @@ export const settingConst = {
|
|||||||
},
|
},
|
||||||
addEmail: {
|
addEmail: {
|
||||||
OPEN: 0,
|
OPEN: 0,
|
||||||
CLOSE: 1,
|
CLOSE: 1
|
||||||
},
|
},
|
||||||
manyEmail: {
|
manyEmail: {
|
||||||
OPEN: 0,
|
OPEN: 0,
|
||||||
@@ -83,10 +85,12 @@ export const settingConst = {
|
|||||||
registerVerify: {
|
registerVerify: {
|
||||||
OPEN: 0,
|
OPEN: 0,
|
||||||
CLOSE: 1,
|
CLOSE: 1,
|
||||||
|
COUNT: 2,
|
||||||
},
|
},
|
||||||
addEmailVerify: {
|
addEmailVerify: {
|
||||||
OPEN: 0,
|
OPEN: 0,
|
||||||
CLOSE: 1,
|
CLOSE: 1,
|
||||||
|
COUNT: 2,
|
||||||
},
|
},
|
||||||
forwardStatus: {
|
forwardStatus: {
|
||||||
OPEN: 0,
|
OPEN: 0,
|
||||||
@@ -102,6 +106,11 @@ export const settingConst = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const verifyRecordType = {
|
||||||
|
REG: 0,
|
||||||
|
ADD: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const isDel = {
|
export const isDel = {
|
||||||
DELETE: 1,
|
DELETE: 1,
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export const setting = sqliteTable('setting', {
|
|||||||
autoRefreshTime: integer('auto_refresh_time').default(0).notNull(),
|
autoRefreshTime: integer('auto_refresh_time').default(0).notNull(),
|
||||||
addEmailVerify: integer('add_email_verify').default(1).notNull(),
|
addEmailVerify: integer('add_email_verify').default(1).notNull(),
|
||||||
registerVerify: integer('register_verify').default(1).notNull(),
|
registerVerify: integer('register_verify').default(1).notNull(),
|
||||||
|
regVerifyCount: integer('reg_verify_count').default(1).notNull(),
|
||||||
|
addVerifyCount: integer('add_verify_count').default(1).notNull(),
|
||||||
send: integer('send').default(1).notNull(),
|
send: integer('send').default(1).notNull(),
|
||||||
r2Domain: text('r2_domain'),
|
r2Domain: text('r2_domain'),
|
||||||
secretKey: text('secret_key'),
|
secretKey: text('secret_key'),
|
||||||
|
|||||||
10
mail-worker/src/entity/verify-record.js
Normal file
10
mail-worker/src/entity/verify-record.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { sqliteTable, text, integer} from 'drizzle-orm/sqlite-core';
|
||||||
|
import { sql } from 'drizzle-orm';
|
||||||
|
export const email = sqliteTable('verify_record', {
|
||||||
|
vrId: integer('vr_id').primaryKey({ autoIncrement: true }),
|
||||||
|
ip: integer('ip').notNull().default(''),
|
||||||
|
count: integer('count').notNull().default(1),
|
||||||
|
type: integer('type').notNull().default(0),
|
||||||
|
updateTime: text('update_time').default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||||
|
});
|
||||||
|
export default email
|
||||||
@@ -48,7 +48,7 @@ const en = {
|
|||||||
noOsUpBack: 'Cannot upload background: R2 object storage not configured',
|
noOsUpBack: 'Cannot upload background: R2 object storage not configured',
|
||||||
noOsDomainUpBack: 'Cannot upload background: R2 domain not configured',
|
noOsDomainUpBack: 'Cannot upload background: R2 domain not configured',
|
||||||
starNotExistEmail: 'Starred email does not exist',
|
starNotExistEmail: 'Starred email does not exist',
|
||||||
emptyBotToken: 'Verification token cannot be empty',
|
emptyBotToken: 'Please verify that you are human',
|
||||||
botVerifyFail: 'Bot verification failed, please try again',
|
botVerifyFail: 'Bot verification failed, please try again',
|
||||||
authExpired: 'Authentication has expired. Please sign in again',
|
authExpired: 'Authentication has expired. Please sign in again',
|
||||||
unauthorized: 'Unauthorized',
|
unauthorized: 'Unauthorized',
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const zh = {
|
|||||||
noOsUpBack: 'r2对象存储未配置不能上传背景',
|
noOsUpBack: 'r2对象存储未配置不能上传背景',
|
||||||
noOsDomainUpBack: 'r2域名未配置不能上传背景',
|
noOsDomainUpBack: 'r2域名未配置不能上传背景',
|
||||||
starNotExistEmail: '星标的邮件不存在',
|
starNotExistEmail: '星标的邮件不存在',
|
||||||
emptyBotToken: '验证token不能为空',
|
emptyBotToken: '需要进行人机验证',
|
||||||
botVerifyFail: '人机验证失败,请重试',
|
botVerifyFail: '人机验证失败,请重试',
|
||||||
authExpired: '身份认证失效,请重新登录',
|
authExpired: '身份认证失效,请重新登录',
|
||||||
unauthorized: '权限不足',
|
unauthorized: '权限不足',
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import app from './hono/webs';
|
import app from './hono/webs';
|
||||||
import { email } from './email/email';
|
import { email } from './email/email';
|
||||||
import userService from './service/user-service';
|
import userService from './service/user-service';
|
||||||
|
import verifyRecord from './entity/verify-record';
|
||||||
|
import verifyRecordService from './service/verify-record-service';
|
||||||
export default {
|
export default {
|
||||||
async fetch(req, env, ctx) {
|
async fetch(req, env, ctx) {
|
||||||
const url = new URL(req.url)
|
const url = new URL(req.url)
|
||||||
@@ -16,6 +18,7 @@ export default {
|
|||||||
},
|
},
|
||||||
email: email,
|
email: email,
|
||||||
async scheduled(c, env, ctx) {
|
async scheduled(c, env, ctx) {
|
||||||
|
await verifyRecordService.clearRecord({env})
|
||||||
await userService.resetDaySendCount({ env })
|
await userService.resetDaySendCount({ env })
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,10 +18,34 @@ const init = {
|
|||||||
await this.v1_3_1DB(c);
|
await this.v1_3_1DB(c);
|
||||||
await this.v1_4DB(c);
|
await this.v1_4DB(c);
|
||||||
await this.v1_5DB(c);
|
await this.v1_5DB(c);
|
||||||
|
await this.v1_6DB(c);
|
||||||
await settingService.refresh(c);
|
await settingService.refresh(c);
|
||||||
return c.text(t('initSuccess'));
|
return c.text(t('initSuccess'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async v1_6DB(c) {
|
||||||
|
|
||||||
|
const ADD_COLUMN_SQL_LIST = [
|
||||||
|
`ALTER TABLE setting ADD COLUMN reg_verify_count INTEGER NOT NULL DEFAULT 1;`,
|
||||||
|
`ALTER TABLE setting ADD COLUMN add_verify_count INTEGER NOT NULL DEFAULT 1;`,
|
||||||
|
`CREATE TABLE IF NOT EXISTS verify_record (
|
||||||
|
vr_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ip TEXT NOT NULL DEFAULT '',
|
||||||
|
count INTEGER NOT NULL DEFAULT 1,
|
||||||
|
type INTEGER NOT NULL DEFAULT 0,
|
||||||
|
update_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)`
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let sql of ADD_COLUMN_SQL_LIST) {
|
||||||
|
try {
|
||||||
|
await c.env.db.prepare(sql).run();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`跳过字段添加,原因:${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async v1_5DB(c) {
|
async v1_5DB(c) {
|
||||||
await c.env.db.prepare(`UPDATE perm SET perm_key = 'sys-email:list' WHERE perm_key = 'all-email:list'`).run();
|
await c.env.db.prepare(`UPDATE perm SET perm_key = 'sys-email:list' WHERE perm_key = 'all-email:list'`).run();
|
||||||
await c.env.db.prepare(`UPDATE perm SET perm_key = 'sys-email:delete' WHERE perm_key = 'all-email:delete'`).run();
|
await c.env.db.prepare(`UPDATE perm SET perm_key = 'sys-email:delete' WHERE perm_key = 'all-email:delete'`).run();
|
||||||
|
|||||||
@@ -6,21 +6,26 @@ import emailService from './email-service';
|
|||||||
import orm from '../entity/orm';
|
import orm from '../entity/orm';
|
||||||
import account from '../entity/account';
|
import account from '../entity/account';
|
||||||
import { and, asc, eq, gt, inArray, count, sql } from 'drizzle-orm';
|
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 settingService from './setting-service';
|
||||||
import turnstileService from './turnstile-service';
|
import turnstileService from './turnstile-service';
|
||||||
import roleService from './role-service';
|
import roleService from './role-service';
|
||||||
import { t } from '../i18n/i18n';
|
import { t } from '../i18n/i18n';
|
||||||
|
import verifyRecordService from './verify-record-service';
|
||||||
|
|
||||||
const accountService = {
|
const accountService = {
|
||||||
|
|
||||||
async add(c, params, userId) {
|
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'));
|
throw new BizError(t('addAccountDisabled'));
|
||||||
}
|
}
|
||||||
|
|
||||||
let { email, token } = params;
|
|
||||||
|
|
||||||
if (!email) {
|
if (!email) {
|
||||||
throw new BizError(t('emptyEmail'));
|
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) {
|
if (accountRow && accountRow.isDel === isDel.DELETE) {
|
||||||
throw new BizError(t('isDelAccount'));
|
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);
|
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) {
|
selectByEmailIncludeDelNoCase(c, email) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import regKeyService from './reg-key-service';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { toUtc } from '../utils/date-uitil';
|
import { toUtc } from '../utils/date-uitil';
|
||||||
import { t } from '../i18n/i18n.js';
|
import { t } from '../i18n/i18n.js';
|
||||||
|
import verifyRecordService from './verify-record-service';
|
||||||
|
|
||||||
const loginService = {
|
const loginService = {
|
||||||
|
|
||||||
@@ -25,11 +26,8 @@ const loginService = {
|
|||||||
|
|
||||||
const { email, password, token, code } = params;
|
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) {
|
if (register === settingConst.register.CLOSE) {
|
||||||
throw new BizError(t('regDisabled'));
|
throw new BizError(t('regDisabled'));
|
||||||
@@ -80,7 +78,6 @@ const loginService = {
|
|||||||
throw new BizError(t('isRegAccount'));
|
throw new BizError(t('isRegAccount'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { salt, hash } = await saltHashUtils.hashPassword(password);
|
|
||||||
|
|
||||||
let defType = null
|
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 });
|
const userId = await userService.insert(c, { email, regKeyId,password: hash, salt, type: type || defType });
|
||||||
|
|
||||||
await userService.updateUserInfo(c, userId, true);
|
await userService.updateUserInfo(c, userId, true);
|
||||||
@@ -114,6 +127,13 @@ const loginService = {
|
|||||||
await regKeyService.reduceCount(c, code, 1);
|
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) {
|
async handleOpenRegKey(c, regKey, code) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import KvConst from '../const/kv-const';
|
import KvConst from '../const/kv-const';
|
||||||
import setting from '../entity/setting';
|
import setting from '../entity/setting';
|
||||||
import orm from '../entity/orm';
|
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 fileUtils from '../utils/file-utils';
|
||||||
import r2Service from './r2-service';
|
import r2Service from './r2-service';
|
||||||
import emailService from './email-service';
|
import emailService from './email-service';
|
||||||
@@ -10,6 +10,7 @@ import userService from './user-service';
|
|||||||
import constant from '../const/constant';
|
import constant from '../const/constant';
|
||||||
import BizError from '../error/biz-error';
|
import BizError from '../error/biz-error';
|
||||||
import { t } from '../i18n/i18n'
|
import { t } from '../i18n/i18n'
|
||||||
|
import verifyRecordService from './verify-record-service';
|
||||||
|
|
||||||
const settingService = {
|
const settingService = {
|
||||||
|
|
||||||
@@ -31,11 +32,32 @@ const settingService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async get(c) {
|
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;
|
settingRow.secretKey = settingRow.secretKey ? `${settingRow.secretKey.slice(0, 12)}******` : null;
|
||||||
Object.keys(settingRow.resendTokens).forEach(key => {
|
Object.keys(settingRow.resendTokens).forEach(key => {
|
||||||
settingRow.resendTokens[key] = `${settingRow.resendTokens[key].slice(0, 12)}******`;
|
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;
|
return settingRow;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -50,28 +72,13 @@ const settingService = {
|
|||||||
await this.refresh(c);
|
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) {
|
async setBackground(c, params) {
|
||||||
|
|
||||||
const settingRow = await this.query(c);
|
const settingRow = await this.query(c);
|
||||||
|
|
||||||
let { background } = params
|
let { background } = params
|
||||||
|
|
||||||
if (!background.startsWith('http')) {
|
if (background && !background.startsWith('http')) {
|
||||||
|
|
||||||
if (!c.env.r2) {
|
if (!c.env.r2) {
|
||||||
throw new BizError(t('noOsUpBack'));
|
throw new BizError(t('noOsUpBack'));
|
||||||
@@ -113,7 +120,9 @@ const settingService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async websiteConfig(c) {
|
async websiteConfig(c) {
|
||||||
const settingRow = await this.get(c);
|
|
||||||
|
const settingRow = await this.get(c)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
register: settingRow.register,
|
register: settingRow.register,
|
||||||
title: settingRow.title,
|
title: settingRow.title,
|
||||||
@@ -128,7 +137,9 @@ const settingService = {
|
|||||||
background: settingRow.background,
|
background: settingRow.background,
|
||||||
loginOpacity: settingRow.loginOpacity,
|
loginOpacity: settingRow.loginOpacity,
|
||||||
domainList:settingRow.domainList,
|
domainList:settingRow.domainList,
|
||||||
regKey: settingRow.regKey
|
regKey: settingRow.regKey,
|
||||||
|
regVerifyOpen: settingRow.regVerifyOpen,
|
||||||
|
addVerifyOpen: settingRow.addVerifyOpen
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const turnstileService = {
|
|||||||
async verify(c, token) {
|
async verify(c, token) {
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw new BizError(t('emptyBotToken'));
|
throw new BizError(t('emptyBotToken'),400);
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingRow = await settingService.query(c)
|
const settingRow = await settingService.query(c)
|
||||||
|
|||||||
90
mail-worker/src/service/verify-record-service.js
Normal file
90
mail-worker/src/service/verify-record-service.js
Normal 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;
|
||||||
9
mail-worker/src/utils/ip-utils.js
Normal file
9
mail-worker/src/utils/ip-utils.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const ipUtils = {
|
||||||
|
getIp(c) {
|
||||||
|
return c.req.header('CF-Connecting-IP') ||
|
||||||
|
c.req.header('X-Forwarded-For') ||
|
||||||
|
'Unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ipUtils
|
||||||
Reference in New Issue
Block a user