mirror of
https://gitee.com/samwaf/SamWaf.git
synced 2025-12-06 06:58:54 +08:00
1
exedata/capjs/capversion
Normal file
1
exedata/capjs/capversion
Normal file
@@ -0,0 +1 @@
|
||||
0.0.6
|
||||
@@ -1,335 +1,357 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<title id="page-title">进行验证</title>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<title id="page-title">进行验证</title>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: #3C3C3C;
|
||||
background: #EBF3FB;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: #3C3C3C;
|
||||
background: #EBF3FB;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.lang-switch {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #3C3C3C;
|
||||
}
|
||||
|
||||
.lang-switch:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
color: #5eaa2f;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
margin-top: 20px;
|
||||
font-family: system, -apple-system, "BlinkMacSystemFont",
|
||||
".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI",
|
||||
"Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #ed4630;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
margin-top: 20px;
|
||||
font-family: system, -apple-system, "BlinkMacSystemFont",
|
||||
".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI",
|
||||
"Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif;
|
||||
}
|
||||
|
||||
/* Toast样式 */
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 12px 24px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.toast.success {
|
||||
background: #f0f9eb;
|
||||
border: 1px solid #dcf9cc;
|
||||
color: #5eaa2f;
|
||||
box-shadow: 1px 1px 10px #e0e0e0;
|
||||
}
|
||||
|
||||
.toast.error {
|
||||
background: #fef0f0;
|
||||
border: 1px solid #fcd6d6;
|
||||
color: #ed4630;
|
||||
box-shadow: 1px 1px 10px #e0e0e0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button id="lang-switch" class="lang-switch">English</button>
|
||||
|
||||
<div class="container">
|
||||
<!-- 添加提示信息区域 -->
|
||||
<div class="info-message" id="info-message">
|
||||
<h2 id="info-title">安全验证</h2>
|
||||
<p id="info-text">为了确保您的访问安全,请完成以下验证</p>
|
||||
</div>
|
||||
|
||||
<cap-widget
|
||||
id="cap"
|
||||
data-cap-api-endpoint="/samwaf_captcha/"
|
||||
data-cap-i18n-verifying-label="验证中..."
|
||||
data-cap-i18n-initial-state="我是人类"
|
||||
data-cap-i18n-solved-label="我是人类"
|
||||
data-cap-i18n-error-label="错误"
|
||||
></cap-widget>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 语言资源
|
||||
const i18n = {
|
||||
'zh': {
|
||||
title: '进行验证',
|
||||
verifySuccess: '验证成功,页面即将刷新...',
|
||||
verifyFail: '验证失败',
|
||||
validationError: '验证异常',
|
||||
switchLang: 'English',
|
||||
// 添加提示信息的中文翻译
|
||||
infoTitle: '安全验证',
|
||||
infoText: '为了确保您的访问安全,请完成以下验证',
|
||||
// Cap.js widget 多语言
|
||||
capWidget: {
|
||||
verifyingLabel: '验证中...',
|
||||
initialState: '我是人类',
|
||||
solvedLabel: '我是人类',
|
||||
errorLabel: '错误'
|
||||
}
|
||||
},
|
||||
'en': {
|
||||
title: 'Verification',
|
||||
verifySuccess: 'Verification successful, page will refresh...',
|
||||
verifyFail: 'Verification failed',
|
||||
validationError: 'Validation error',
|
||||
switchLang: '中文',
|
||||
// 添加提示信息的英文翻译
|
||||
infoTitle: 'Security Verification',
|
||||
infoText: 'To ensure the security of your access, please complete the following verification',
|
||||
// Cap.js widget 多语言
|
||||
capWidget: {
|
||||
verifyingLabel: 'Verifying...',
|
||||
initialState: "I'm a human",
|
||||
solvedLabel: "I'm a human",
|
||||
errorLabel: 'Error'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 语言管理
|
||||
const langManager = (function() {
|
||||
// Cookie 操作函数
|
||||
function setCookie(name, value, days) {
|
||||
let expires = "";
|
||||
if (days) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
const nameEQ = name + "=";
|
||||
const ca = document.cookie.split(';');
|
||||
for(let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检测浏览器语言
|
||||
function detectBrowserLang() {
|
||||
const browserLang = navigator.language || navigator.userLanguage;
|
||||
return browserLang.toLowerCase().startsWith('zh') ? 'zh' : 'en';
|
||||
}
|
||||
|
||||
let currentLang = getCookie('samwaf_lang') || detectBrowserLang();
|
||||
|
||||
function setLanguage(lang) {
|
||||
currentLang = lang;
|
||||
setCookie('samwaf_lang', lang, 30); // 保存30天
|
||||
applyLanguage();
|
||||
return currentLang;
|
||||
}
|
||||
|
||||
function getCurrentLang() {
|
||||
return currentLang;
|
||||
}
|
||||
|
||||
function getText(key) {
|
||||
return i18n[currentLang][key] || i18n['en'][key] || key;
|
||||
}
|
||||
|
||||
function getCapWidgetText(key) {
|
||||
return i18n[currentLang].capWidget[key] || i18n['en'].capWidget[key] || key;
|
||||
}
|
||||
|
||||
function applyLanguage() {
|
||||
// 更新页面标题
|
||||
document.getElementById('page-title').textContent = getText('title');
|
||||
// 更新语言切换按钮
|
||||
document.getElementById('lang-switch').textContent = getText('switchLang');
|
||||
|
||||
// 更新提示信息的多语言内容
|
||||
const infoTitle = document.getElementById('info-title');
|
||||
const infoText = document.getElementById('info-text');
|
||||
if (infoTitle) {
|
||||
infoTitle.textContent = getText('infoTitle');
|
||||
}
|
||||
if (infoText) {
|
||||
infoText.textContent = getText('infoText');
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 0;
|
||||
// 更新cap-widget的多语言属性
|
||||
const capWidget = document.getElementById('cap');
|
||||
if (capWidget) {
|
||||
capWidget.setAttribute('data-cap-i18n-verifying-label', getCapWidgetText('verifyingLabel'));
|
||||
capWidget.setAttribute('data-cap-i18n-initial-state', getCapWidgetText('initialState'));
|
||||
capWidget.setAttribute('data-cap-i18n-solved-label', getCapWidgetText('solvedLabel'));
|
||||
capWidget.setAttribute('data-cap-i18n-error-label', getCapWidgetText('errorLabel'));
|
||||
}
|
||||
}
|
||||
|
||||
.lang-switch {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #3C3C3C;
|
||||
}
|
||||
return {
|
||||
setLanguage,
|
||||
getCurrentLang,
|
||||
getText,
|
||||
getCapWidgetText,
|
||||
applyLanguage
|
||||
};
|
||||
})();
|
||||
|
||||
.lang-switch:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
// Toast提示函数
|
||||
function showToast(message, type = 'success') {
|
||||
// 移除已存在的toast
|
||||
const existingToast = document.querySelector('.toast');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
.success-message {
|
||||
color: #5eaa2f;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
margin-top: 20px;
|
||||
font-family: system, -apple-system, "BlinkMacSystemFont",
|
||||
".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI",
|
||||
"Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif;
|
||||
}
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
toast.textContent = message;
|
||||
document.body.appendChild(toast);
|
||||
|
||||
.error-message {
|
||||
color: #ed4630;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
margin-top: 20px;
|
||||
font-family: system, -apple-system, "BlinkMacSystemFont",
|
||||
".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI",
|
||||
"Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif;
|
||||
}
|
||||
// 显示toast
|
||||
setTimeout(() => {
|
||||
toast.classList.add('show');
|
||||
}, 100);
|
||||
|
||||
/* Toast样式 */
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 12px 24px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
// 隐藏toast
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.parentNode.removeChild(toast);
|
||||
}
|
||||
}, 300);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
}
|
||||
// 初始化语言
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
langManager.applyLanguage();
|
||||
});
|
||||
|
||||
.toast.success {
|
||||
background: #f0f9eb;
|
||||
border: 1px solid #dcf9cc;
|
||||
color: #5eaa2f;
|
||||
box-shadow: 1px 1px 10px #e0e0e0;
|
||||
}
|
||||
// 语言切换按钮事件
|
||||
document.getElementById('lang-switch').addEventListener('click', function() {
|
||||
const newLang = langManager.getCurrentLang() === 'zh' ? 'en' : 'zh';
|
||||
langManager.setLanguage(newLang);
|
||||
// 刷新页面以重新初始化验证码
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
.toast.error {
|
||||
background: #fef0f0;
|
||||
border: 1px solid #fcd6d6;
|
||||
color: #ed4630;
|
||||
box-shadow: 1px 1px 10px #e0e0e0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button id="lang-switch" class="lang-switch">English</button>
|
||||
|
||||
<div class="container">
|
||||
<cap-widget
|
||||
id="cap"
|
||||
data-cap-api-endpoint="/samwaf_captcha/"
|
||||
data-cap-i18n-verifying-label="验证中..."
|
||||
data-cap-i18n-initial-state="我是人类"
|
||||
data-cap-i18n-solved-label="我是人类"
|
||||
data-cap-i18n-error-label="错误"
|
||||
></cap-widget>
|
||||
</div>
|
||||
// 动态获取当前页面的协议、域名和端口
|
||||
const currentProtocol = window.location.protocol; // http: 或 https:
|
||||
const currentHost = window.location.host; // 包含域名和端口
|
||||
window.CAP_CUSTOM_WASM_URL = `${currentProtocol}//${currentHost}/samwaf_captcha/cap_wasm.min.js`;
|
||||
</script>
|
||||
<script src="/samwaf_captcha/widget.js"></script>
|
||||
|
||||
<script>
|
||||
// 语言资源
|
||||
const i18n = {
|
||||
'zh': {
|
||||
title: '进行验证',
|
||||
verifySuccess: '验证成功,页面即将刷新...',
|
||||
verifyFail: '验证失败',
|
||||
validationError: '验证异常',
|
||||
switchLang: 'English',
|
||||
// Cap.js widget 多语言
|
||||
capWidget: {
|
||||
verifyingLabel: '验证中...',
|
||||
initialState: '我是人类',
|
||||
solvedLabel: '我是人类',
|
||||
errorLabel: '错误'
|
||||
}
|
||||
<script>
|
||||
const widget = document.querySelector("#cap");
|
||||
|
||||
widget.addEventListener("solve", function (e) {
|
||||
const token = e.detail.token;
|
||||
// console.log("Captcha solved!");
|
||||
//console.log("Token:" + token); // Token is returned by the server
|
||||
|
||||
// Submit token to backend for validation
|
||||
validateToken(token);
|
||||
});
|
||||
|
||||
// Function to validate token with backend
|
||||
async function validateToken(token) {
|
||||
try {
|
||||
const response = await fetch('/samwaf_captcha/validate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
'en': {
|
||||
title: 'Verification',
|
||||
verifySuccess: 'Verification successful, page will refresh...',
|
||||
verifyFail: 'Verification failed',
|
||||
validationError: 'Validation error',
|
||||
switchLang: '中文',
|
||||
// Cap.js widget 多语言
|
||||
capWidget: {
|
||||
verifyingLabel: 'Verifying...',
|
||||
initialState: "I'm a human",
|
||||
solvedLabel: "I'm a human",
|
||||
errorLabel: 'Error'
|
||||
}
|
||||
}
|
||||
};
|
||||
body: JSON.stringify({ token: token })
|
||||
});
|
||||
|
||||
// 语言管理
|
||||
const langManager = (function() {
|
||||
// Cookie 操作函数
|
||||
function setCookie(name, value, days) {
|
||||
let expires = "";
|
||||
if (days) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
const nameEQ = name + "=";
|
||||
const ca = document.cookie.split(';');
|
||||
for(let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
// 检测浏览器语言
|
||||
function detectBrowserLang() {
|
||||
const browserLang = navigator.language || navigator.userLanguage;
|
||||
return browserLang.toLowerCase().startsWith('zh') ? 'zh' : 'en';
|
||||
}
|
||||
if (result.success) {
|
||||
// 隐藏验证码组件
|
||||
document.querySelector('#cap').style.display = 'none';
|
||||
// 隐藏语言切换按钮
|
||||
document.getElementById('lang-switch').style.display = 'none';
|
||||
|
||||
let currentLang = getCookie('samwaf_lang') || detectBrowserLang();
|
||||
// 显示成功消息
|
||||
const successEl = document.createElement("div");
|
||||
successEl.className = "success-message";
|
||||
successEl.textContent = langManager.getText('verifySuccess');
|
||||
document.querySelector(".container").appendChild(successEl);
|
||||
|
||||
function setLanguage(lang) {
|
||||
currentLang = lang;
|
||||
setCookie('samwaf_lang', lang, 30); // 保存30天
|
||||
applyLanguage();
|
||||
return currentLang;
|
||||
}
|
||||
// 显示成功toast
|
||||
showToast(langManager.getText('verifySuccess'), 'success');
|
||||
|
||||
function getCurrentLang() {
|
||||
return currentLang;
|
||||
}
|
||||
|
||||
function getText(key) {
|
||||
return i18n[currentLang][key] || i18n['en'][key] || key;
|
||||
}
|
||||
|
||||
function getCapWidgetText(key) {
|
||||
return i18n[currentLang].capWidget[key] || i18n['en'].capWidget[key] || key;
|
||||
}
|
||||
|
||||
function applyLanguage() {
|
||||
// 更新页面标题
|
||||
document.getElementById('page-title').textContent = getText('title');
|
||||
// 更新语言切换按钮
|
||||
document.getElementById('lang-switch').textContent = getText('switchLang');
|
||||
|
||||
// 更新cap-widget的多语言属性
|
||||
const capWidget = document.getElementById('cap');
|
||||
if (capWidget) {
|
||||
capWidget.setAttribute('data-cap-i18n-verifying-label', getCapWidgetText('verifyingLabel'));
|
||||
capWidget.setAttribute('data-cap-i18n-initial-state', getCapWidgetText('initialState'));
|
||||
capWidget.setAttribute('data-cap-i18n-solved-label', getCapWidgetText('solvedLabel'));
|
||||
capWidget.setAttribute('data-cap-i18n-error-label', getCapWidgetText('errorLabel'));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
setLanguage,
|
||||
getCurrentLang,
|
||||
getText,
|
||||
getCapWidgetText,
|
||||
applyLanguage
|
||||
};
|
||||
})();
|
||||
|
||||
// Toast提示函数
|
||||
function showToast(message, type = 'success') {
|
||||
// 移除已存在的toast
|
||||
const existingToast = document.querySelector('.toast');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
toast.textContent = message;
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// 显示toast
|
||||
// 2秒后刷新页面
|
||||
setTimeout(() => {
|
||||
toast.classList.add('show');
|
||||
}, 100);
|
||||
|
||||
// 隐藏toast
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.parentNode.removeChild(toast);
|
||||
}
|
||||
}, 300);
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
} else {
|
||||
// 显示失败toast
|
||||
showToast(langManager.getText('verifyFail'), 'error');
|
||||
}
|
||||
|
||||
// 初始化语言
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
langManager.applyLanguage();
|
||||
});
|
||||
|
||||
// 语言切换按钮事件
|
||||
document.getElementById('lang-switch').addEventListener('click', function() {
|
||||
const newLang = langManager.getCurrentLang() === 'zh' ? 'en' : 'zh';
|
||||
langManager.setLanguage(newLang);
|
||||
// 刷新页面以重新初始化验证码
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
// 动态获取当前页面的协议、域名和端口
|
||||
const currentProtocol = window.location.protocol; // http: 或 https:
|
||||
const currentHost = window.location.host; // 包含域名和端口
|
||||
window.CAP_CUSTOM_WASM_URL = `${currentProtocol}//${currentHost}/samwaf_captcha/cap_wasm.min.js`;
|
||||
</script>
|
||||
<script src="/samwaf_captcha/widget.js"></script>
|
||||
|
||||
<script>
|
||||
const widget = document.querySelector("#cap");
|
||||
|
||||
widget.addEventListener("solve", function (e) {
|
||||
const token = e.detail.token;
|
||||
// console.log("Captcha solved!");
|
||||
//console.log("Token:" + token); // Token is returned by the server
|
||||
|
||||
// Submit token to backend for validation
|
||||
validateToken(token);
|
||||
});
|
||||
|
||||
// Function to validate token with backend
|
||||
async function validateToken(token) {
|
||||
try {
|
||||
const response = await fetch('/samwaf_captcha/validate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ token: token })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
// 隐藏验证码组件
|
||||
document.querySelector('#cap').style.display = 'none';
|
||||
// 隐藏语言切换按钮
|
||||
document.getElementById('lang-switch').style.display = 'none';
|
||||
|
||||
// 显示成功消息
|
||||
const successEl = document.createElement("div");
|
||||
successEl.className = "success-message";
|
||||
successEl.textContent = langManager.getText('verifySuccess');
|
||||
document.querySelector(".container").appendChild(successEl);
|
||||
|
||||
// 显示成功toast
|
||||
showToast(langManager.getText('verifySuccess'), 'success');
|
||||
|
||||
// 2秒后刷新页面
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
} else {
|
||||
// 显示失败toast
|
||||
showToast(langManager.getText('verifyFail'), 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Validation error:', error);
|
||||
// 显示错误toast
|
||||
showToast(langManager.getText('validationError') + ': ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
} catch (error) {
|
||||
console.error('Validation error:', error);
|
||||
// 显示错误toast
|
||||
showToast(langManager.getText('validationError') + ': ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
@@ -1 +1 @@
|
||||
0.0.6
|
||||
1.0.1
|
||||
@@ -77,6 +77,14 @@ type CaptchaConfig struct {
|
||||
ChallengeSize int `json:"challengeSize,omitempty"` // Size of each challenge in bytes (default: 32)
|
||||
ChallengeDifficulty int `json:"challengeDifficulty,omitempty"` // Difficulty level (default: 4)
|
||||
ExpiresMs int `json:"expiresMs,omitempty"` // Expiration time in milliseconds (default: 600000)
|
||||
InfoTitle struct {
|
||||
En string `json:"en,omitempty"` // English title
|
||||
Zh string `json:"zh,omitempty"` // Chinese title
|
||||
} `json:"infoTitle,omitempty"` // Multi-language info title
|
||||
InfoText struct {
|
||||
En string `json:"en,omitempty"` // English text
|
||||
Zh string `json:"zh,omitempty"` // Chinese text
|
||||
} `json:"infoText,omitempty"` // Multi-language info text
|
||||
} `json:"cap_js_config"`
|
||||
}
|
||||
|
||||
@@ -97,6 +105,14 @@ func ParseCaptchaConfig(captchaJSON string) CaptchaConfig {
|
||||
config.CapJsConfig.ChallengeDifficulty = 4 // 默认难度级别4
|
||||
config.CapJsConfig.ExpiresMs = 600000 // 默认过期时间600秒(10分钟)
|
||||
|
||||
// 初始化InfoTitle默认值
|
||||
config.CapJsConfig.InfoTitle.Zh = "安全验证"
|
||||
config.CapJsConfig.InfoTitle.En = "Security Verification"
|
||||
|
||||
// 初始化InfoText默认值
|
||||
config.CapJsConfig.InfoText.Zh = "为了确保您的访问安全,请完成以下验证"
|
||||
config.CapJsConfig.InfoText.En = "To ensure the security of your access, please complete the following verification"
|
||||
|
||||
// 如果JSON不为空,则解析覆盖默认值
|
||||
if captchaJSON != "" {
|
||||
err := json.Unmarshal([]byte(captchaJSON), &config)
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/wenlng/go-captcha/v2/base/option"
|
||||
"github.com/wenlng/go-captcha/v2/click"
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -512,8 +513,49 @@ func (s *CaptchaService) ShowCaptchaHomePage(w http.ResponseWriter, r *http.Requ
|
||||
// 从指定目录加载index.html
|
||||
http.ServeFile(w, r, utils.GetCurrentDir()+"/data/captcha/index.html")
|
||||
} else if configStruct.EngineType == "capJs" {
|
||||
// 从指定目录加载index.html
|
||||
http.ServeFile(w, r, utils.GetCurrentDir()+"/data/capjs/index.html")
|
||||
// 读取HTML模板文件
|
||||
htmlPath := utils.GetCurrentDir() + "/data/capjs/index.html"
|
||||
htmlContent, err := ioutil.ReadFile(htmlPath)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to load page", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// 准备替换的数据
|
||||
htmlStr := string(htmlContent)
|
||||
|
||||
// 替换中文提示信息
|
||||
zhInfoTitle := configStruct.CapJsConfig.InfoTitle.Zh
|
||||
zhInfoText := configStruct.CapJsConfig.InfoText.Zh
|
||||
if zhInfoTitle == "" {
|
||||
zhInfoTitle = "安全验证"
|
||||
}
|
||||
if zhInfoText == "" {
|
||||
zhInfoText = "为了确保您的访问安全,请完成以下验证"
|
||||
}
|
||||
|
||||
// 替换英文提示信息
|
||||
enInfoTitle := configStruct.CapJsConfig.InfoTitle.En
|
||||
enInfoText := configStruct.CapJsConfig.InfoText.En
|
||||
if enInfoTitle == "" {
|
||||
enInfoTitle = "Security Verification"
|
||||
}
|
||||
if enInfoText == "" {
|
||||
enInfoText = "To ensure the security of your access, please complete the following verification"
|
||||
}
|
||||
|
||||
// 使用strings.Replace替换HTML中的静态文本
|
||||
htmlStr = strings.Replace(htmlStr, "infoTitle: '安全验证',", fmt.Sprintf("infoTitle: '%s',", zhInfoTitle), 1)
|
||||
htmlStr = strings.Replace(htmlStr, "infoText: '为了确保您的访问安全,请完成以下验证',", fmt.Sprintf("infoText: '%s',", zhInfoText), 1)
|
||||
htmlStr = strings.Replace(htmlStr, "infoTitle: 'Security Verification',", fmt.Sprintf("infoTitle: '%s',", enInfoTitle), 1)
|
||||
htmlStr = strings.Replace(htmlStr, "infoText: 'To ensure the security of your access, please complete the following verification',", fmt.Sprintf("infoText: '%s',", enInfoText), 1)
|
||||
|
||||
// 同时替换HTML中的默认显示文本
|
||||
htmlStr = strings.Replace(htmlStr, "<h2 id=\"info-title\">安全验证</h2>", fmt.Sprintf("<h2 id=\"info-title\">%s</h2>", zhInfoTitle), 1)
|
||||
htmlStr = strings.Replace(htmlStr, "<p id=\"info-text\">为了确保您的访问安全,请完成以下验证</p>", fmt.Sprintf("<p id=\"info-text\">%s</p>", zhInfoText), 1)
|
||||
|
||||
// 输出修改后的HTML
|
||||
w.Write([]byte(htmlStr))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user