first commit

This commit is contained in:
2026-02-17 13:06:23 +08:00
commit 7cbd3d061d
349 changed files with 126558 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

+152
View File
@@ -0,0 +1,152 @@
# 微信验证页面浏览器访问解决方案
## 问题描述
微信的安全验证页面(如 `https://weixin110.qq.com/security/acct/newreadtemplate?t=extdevsignin/slaveverify&ticket=xxx`)通常只能在微信内置浏览器中打开,在普通浏览器中会报错。
## 解决方案
本方案通过以下技术手段解决了浏览器访问限制:
### 1. User-Agent模拟
- 使用微信浏览器的User-Agent头部
- 模拟iPhone微信浏览器环境
- 绕过微信服务器的浏览器检测
### 2. 代理接口
创建了代理接口 `/api/v1/login/ProxyWechatVerify`,该接口:
- 接收ticket参数
- 设置正确的微信浏览器User-Agent
- 代理请求微信验证页面
- 返回可在浏览器中正常显示的页面
### 3. 验证页面封装
提供了 `/api/v1/login/GetWechatVerifyPage` 接口,返回包含多种验证方式的HTML页面:
- **方法一**:直接在iframe中显示验证页面(推荐)
- **方法二**:新窗口打开验证页面
- **方法三**:复制链接手动打开
## 在Swagger中的集成
### 自动检测功能
- 当调用获取二维码接口后,系统自动开始监控登录状态
- 检测到需要验证时,自动显示浮动验证按钮
- 点击按钮即可打开验证弹窗
### 使用流程
1. 在Swagger中调用获取二维码接口
2. 用户扫描二维码
3. 如果需要安全验证,右下角会出现"🔐 安全验证"按钮
4. 点击按钮打开验证弹窗
5. 在弹窗中完成滑块验证
6. 验证成功后自动关闭弹窗,继续登录流程
## API接口说明
### 1. 代理微信验证页面
```
GET /api/v1/login/ProxyWechatVerify?ticket={ticket}
```
**参数:**
- `ticket`: 微信验证票据(从检测扫码状态接口获取)
**返回:**
- 微信验证页面的HTML内容(已处理CORS和路径问题)
### 2. 获取微信验证页面
```
GET /api/v1/login/GetWechatVerifyPage?ticket={ticket}
```
**参数:**
- `ticket`: 微信验证票据
**返回:**
- 包含多种验证方式的自定义HTML页面
### 3. 检测扫码状态(已增强)
```
GET /api/v1/login/CheckLoginStatus?key={key}
```
**返回数据包含:**
```json
{
"code": 200,
"data": {
"state": 0, // 0: 等待扫码, 1: 已扫码, 2: 登录成功
"loginState": "waiting",
"data62": "...",
"ticket": "3_890d910a803559e0a6681089cbf70205" // 验证票据
},
"text": "等待扫码"
}
```
## 技术特点
### 1. 微信浏览器模拟
```javascript
req.Header.Set("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.42(0x18002a2f) NetType/WIFI Language/zh_CN")
```
### 2. 自动路径修复
- 将相对路径转换为绝对路径
- 处理CORS跨域问题
- 确保资源正确加载
### 3. 实时状态监控
- 自动轮询检测登录状态
- 智能识别验证需求
- 用户友好的交互体验
## 使用建议
1. **推荐方法一**:直接在iframe中验证,体验最佳
2. **备用方案**:如果iframe加载失败,使用新窗口方式
3. **手动方式**:复制链接到新标签页打开(最后选择)
## 安全说明
- 所有验证过程在用户浏览器中完成
- 不存储任何用户凭据信息
- 仅作为微信验证页面的技术代理
- 验证票据具有时效性,过期需重新获取
## 故障排除
### 常见问题
1. **验证页面无法加载**
- 检查ticket是否有效
- 尝试使用不同的验证方法
- 确保网络连接正常
2. **验证后无响应**
- 检查是否完成了验证操作
- 等待几秒钟让系统检测状态变化
- 可手动调用状态检查接口
3. **弹窗被浏览器拦截**
- 允许浏览器弹窗
- 使用iframe方式验证
### 日志调试
```javascript
// 在浏览器控制台中查看
console.log(window.WechatVerifyIntegration);
// 手动触发状态检查
window.WechatVerifyIntegration.checkLoginStatusOnce();
```
## 更新记录
- **v1.0** - 初始版本,支持基本的微信验证页面代理
- **v1.1** - 添加Swagger集成,自动检测和弹窗功能
- **v1.2** - 优化用户体验,增加多种验证方式
---
> 本解决方案仅供学习交流使用,请遵守相关法律法规和平台规则。
+1
View File
@@ -0,0 +1 @@
生成二维码!
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+763
View File
@@ -0,0 +1,763 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
/* Reset */
html,
body {
box-sizing: border-box;
margin: 0;
padding: 0;
overflow-y: scroll;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f8f9fa;
}
/* Swagger UI Container */
#swagger-ui {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 10px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
}
/* Floating Window */
.floating-window {
position: fixed;
bottom: 20px;
right: 20px;
padding: 15px 25px;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 10px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
z-index: 2;
animation: glow 2s infinite alternate;
}
.close-btn {
position: absolute;
top: 5px;
right: 5px;
font-size: 18px;
color: #e74c3c;
cursor: pointer;
}
/* Form and Input Styling */
#xxcaibi {
background-color: #f5f5f5;
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
margin: 20px auto;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
width: 90%;
}
.xxcaibi-group {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.xxcaibi-label {
color: #555;
font-size: 14px;
width: 120px;
}
.xxcaibi-input,
.xxcaibi-switch {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
}
.xxcaibi-input:focus {
border-color: #4CAF50;
outline: none;
}
.xxcaibi-switch {
width: 40px;
height: 20px;
appearance: none;
background-color: #ccc;
/* 默认状态下的开关背景颜色 */
outline: none;
border-radius: 20px;
position: relative;
cursor: pointer;
transition: background-color 0.3s ease;
}
.xxcaibi-switch:checked {
background-color: #4CAF50;
}
.xxcaibi-switch::before {
content: "";
position: absolute;
width: 18px;
height: 18px;
border-radius: 50%;
background-color: white;
top: 1px;
left: 1px;
transition: transform 0.3s ease;
}
.xxcaibi-switch:checked::before {
transform: translateX(20px);
}
/* Radio Button Group */
.radio-group {
display: flex;
justify-content: space-between;
width: 80%;
}
.radio-group label {
display: flex;
align-items: center;
}
.radio-group input[type="radio"] {
margin-right: 10px;
transform: scale(1.5);
}
.radio-group input[type="radio"]:focus {
outline: none;
}
/* Glow Animation */
@keyframes glow {
from {
box-shadow: 0 0 10px rgba(0, 255, 255, 0.4);
}
to {
box-shadow: 0 0 20px rgba(0, 255, 255, 0.7);
}
}
/* Link Card */
.card {
position: absolute;
top: 0;
left: 0;
width: 100px;
z-index: 2;
transition: transform 0.5s ease, filter 0.5s ease;
}
.card:hover {
transform: scale(1.2);
filter: drop-shadow(0 0 10px rgba(0, 255, 255, 0.7));
}
/* Card Movement Animation */
@keyframes cardMove {
0% {
transform: translate(0, 0);
}
50% {
transform: translate(50vw, 50vh);
}
100% {
transform: translate(0, 0);
}
}
.base-url {
display: none;
}
/* Telegram Link Container */
.tg-link {
display: flex;
margin-top: 20px;
}
/* Telegram Button */
.tg-button {
display: flex;
align-items: center;
padding: 10px 20px;
background-color: #5cadff !important;
color: white !important;
font-size: 16px;
text-decoration: none;
border-radius: 30px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: background-color 0.3s ease, transform 0.3s ease;
}
/* Telegram Button Hover Effect */
.tg-button:hover {
background-color: #007ab8 !important;
transform: translateY(-2px);
}
/* Telegram Icon */
.tg-icon {
width: 24px;
height: 24px;
margin-right: 10px;
}
.container {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 20px;
width: 100%;
}
.container input[type="text"] {
flex: 1;
width: 300px;
/* 初始宽度 */
max-width: 500px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
margin-right: 10px;
font-size: 16px;
}
.container button {
padding: 10px 15px;
border: none;
border-radius: 4px;
background-color: #007bff;
color: white;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
margin-left: 12px;
}
.container button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.container button:hover:not(:disabled) {
background-color: #0056b3;
}
#messages {
margin-top: 12px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 10px;
max-height: 300px;
overflow-y: auto;
background-color: #f9f9f9;
}
</style>
</head>
<body>
<div id="xxcaibi" class="wrapper" style="display: none;">
<div class="xxcaibi-group">
<label for="admin-key" class="xxcaibi-label">ADMIN_KEY</label>
<input type="text" id="admin-key" class="xxcaibi-input" placeholder="管理员接口 ADMIN_KEY">
</div>
<div class="xxcaibi-group">
<label for="token-key" class="xxcaibi-label">TOKEN_KEY</label>
<input type="text" id="token-key" class="xxcaibi-input" placeholder="普通API TOKEN_KEY">
</div>
<div class="xxcaibi-group">
<label class="xxcaibi-label">Swagger 展开方式</label>
<div class="radio-group">
<label>
<input type="radio" name="expand-options" value="none" checked>不展开
</label>
<label>
<input type="radio" name="expand-options" value="list">只展开API
</label>
<label>
<input type="radio" name="expand-options" value="full">展开所有
</label>
</div>
</div>
<div class="xxcaibi-group">
<label for="copy-base-url" class="xxcaibi-label">是否复制根路径</label>
<input style="flex: none !important" type="checkbox" id="copy-base-url" class="xxcaibi-switch" checked>
<span style="margin-left: 20px;" id="BASE_URL"></span>
</div>
<h4 style="text-align: center;line-height: 1;margin-bottom: 10px">WS 客户端 (同步消息)</h4>
<div class="container">
<input id="urlInput" type="text" placeholder="输入 WebSocket URL" />
<button id="connectButton">连接</button>
<button id="disconnectButton" disabled>取消连接</button>
<button id="clearMessagesButton">清理消息</button>
</div>
<div id="messages"></div>
</div>
<script>
let socket;
document.getElementById('urlInput').value = window.location.origin.replace(/^http/, 'ws') + '/ws/GetSyncMsg?key='
// 更新按钮文本
function updateButton(button, text, isLoading) {
button.innerHTML = isLoading ? text + '...' : text;
button.disabled = isLoading;
}
// 连接按钮点击事件
document.getElementById('connectButton').onclick = function () {
const url = document.getElementById('urlInput').value;
// 如果已经有连接,先关闭
if (socket && socket.readyState === WebSocket.OPEN) {
socket.close();
}
// 更新按钮状态为连接中
updateButton(this, '连接中', true);
// 创建 WebSocket 连接
socket = new WebSocket(url);
// 连接成功时
socket.onopen = function () {
console.log('已连接到服务器');
document.getElementById('messages').innerHTML += '<p>已连接到服务器</p>';
updateButton(document.getElementById('connectButton'), '连接', false); // 重置连接按钮
document.getElementById('disconnectButton').disabled = false; // 启用取消连接按钮
document.getElementById('connectButton').disabled = true;
};
// 接收消息
socket.onmessage = function (event) {
console.log('收到来自服务器的消息:', event.data);
document.getElementById('messages').innerHTML += '<p>服务器: ' + event.data + '</p>';
};
// 连接关闭时
socket.onclose = function () {
console.log('与服务器的连接已关闭');
document.getElementById('messages').innerHTML += '<p>与服务器的连接已关闭</p>';
updateButton(document.getElementById('connectButton'), '连接', false); // 启用连接按钮
document.getElementById('disconnectButton').innerHTML = "取消连接",
document.getElementById('disconnectButton').disabled = true; // 启用连接按钮
document.getElementById('connectButton').disabled = false; // 启用连接按钮
};
// 处理错误
socket.onerror = function (error) {
console.error('WebSocket 错误:', error);
document.getElementById('messages').innerHTML += '<p>WebSocket 错误: ' + error.message + '</p>';
updateButton(document.getElementById('connectButton'), '连接', false); // 重置连接按钮
};
};
// 取消连接按钮点击事件
document.getElementById('disconnectButton').onclick = function () {
updateButton(this, '取消中', true); // 更新为取消中状态
if (socket) {
setTimeout(function () {
socket.close();
}, 30)
}
};
// 清理消息按钮点击事件
document.getElementById('clearMessagesButton').onclick = function () {
document.getElementById('messages').innerHTML = ''; // 清空消息区域
};
</script>
<div id="swagger-ui"></div>
<!-- Floating window -->
<div class="floating-window" style="display: none !important">
</div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"></script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"></script>
<script src="./jquery-3.7.1.slim.min.js"></script>
<!-- 微信验证集成脚本 -->
<script src="./wechat-verify-integration.js"></script>
<script>
function closeDiv(element) {
element.parentElement.style.display = 'none';
}
function isAdminApi(pathKey) {
if (pathKey.startsWith("/admin/")) {
return true
}
return window.xxcaibi.adminUrls[pathKey]
}
const CustomPlugin = function (system) {
return {
statePlugins: {
spec: {
actions: {
updateQueryParam: (paramName, paramValue, isAdminKey = false) => (state) => {
const spec = state.specSelectors.specJson().toJS();
const paths = spec.paths;
Object.keys(paths).forEach(pathKey => {
if (!isAdminKey && isAdminApi(pathKey)) {
// 非 ADMIN_KEY 并且是 ADMIN 接口
return;
}
if (isAdminKey && !isAdminApi(pathKey)) {
// 是 ADMIN_KEY 并且 不是 ADMIN 接口
return;
}
Object.keys(paths[pathKey]).forEach(method => {
const params = paths[pathKey][method].parameters;
params.forEach(param => {
if (param.name === paramName && param.in === 'query') {
param.default = paramValue;
}
});
});
});
state.specActions.updateSpec(JSON.stringify(spec));
},
updateConfigs: (spec) => (state) => {
state.specActions.updateSpec(JSON.stringify(spec));
},
},
wrapActions: {
updateSpec: (oriAction, system) => (...args) => {
return oriAction(...args)
},
},
},
},
};
};
// 检查 Swagger-UI 内的 img.opblock-loading-animation 请求体节点是否加载完成
function checkSwaggerLoadingComplete(targetFunc) {
const targetNode = document.getElementById('swagger-ui');
const config = { childList: true, subtree: true };
const callback = function (mutationsList, observer) {
const loadingElements = targetNode.querySelectorAll('img.opblock-loading-animation');
if (loadingElements.length === 0) {
console.log('Swagger UI loaded successfully');
observer.disconnect(); // 停止观察
targetFunc && targetFunc();
}
};
const observer = new MutationObserver(callback);
setTimeout(function () {
$("#swagger-ui").append("&nbsp;")
}, 100)
observer.observe(targetNode, config); // DOM 节点无变化则不会触发监听
}
// 粘贴到系统剪切板1
function copy(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
// navigator.clipboard 只能在 HTTPS 环境使用; 旧版浏览器兼容性不好
navigator.clipboard.writeText(text).then(function () {
}).catch(function (error) {
console.error('Failed to copy text: ', error);
fallbackCopy(text);
});
} else {
fallbackCopy(text);
}
}
// 粘贴到系统剪切板2
function fallbackCopy(text) {
// 使用 textarea 标签 可以复制 pre 代码标签里的换行
let textArea = document.createElement("textarea");
textArea.value = text;
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
} catch (err) {
console.error('Fallback copy failed: ', err);
}
document.body.removeChild(textArea);
}
// 复制 API 的路径即描述
function addCopy1(selector) {
let pathElements;
// opblock-summary-path opblock-summary-description
if (selector) {
pathElements = $(selector).parent().find(".opblock-summary-description");
} else {
pathElements = $(".opblock-summary-description");
addCopy2();
}
if (pathElements.length === 0) {
return;
}
console.log("API数量:", pathElements.length);
$(".opblock-summary-post").click(function () {
let status = $(this).children().first().attr("aria-expanded");
if (status === "true") {
return;
}
let curId = $(this).parent().attr("id");
// console.log(curId, status);
setTimeout(function () {
addCopy2(`#${curId}`);
}, 100);
});
pathElements.each(function (index, pathElement) {
pathElement = $(pathElement);
let isCopy = pathElement.attr("copy");
if (isCopy === "true") { // 已经添加过 copy 按钮
return;
}
pathElement.after(
$("<button>复制</button>").css("cursor", "pointer").css("color", "#FFF").css("background", "#2b85e4").css("border-color", "#2b85e4").css("padding", "4px 8px").css("border-radius", "4px").css("margin-right", "10px").click(function () {
// 获取接口文本
let api = this.parentNode.children[1].dataset.path;
let desc = this.parentNode.children[2].textContent;
let text = api + " " + desc;
if (window.xxcaibi.copy) {
text = window.xxcaibi.BASE_URL + text;
}
// console.log(api, desc)
// 调用函数,复制到剪切板
text = text.replace(/([^:])\/+/g, '$1/')
copy(text);
// 提示复制成功
$(this).text("复制成功!");
// 定时改变显示文字
setTimeout(() => {
$(this).text("复制");
}, 500);
return false;
})
);
pathElement.attr("copy", "true");
});
}
// 复制 POST 请求的 JSON 请求体
function addCopy2(selector) {
if (!selector) {
selector = "#swagger-ui"
}
let lis = $(selector + ' li[role="presentation"]');
if (lis.length < 2) {
return;
}
lis.each(function (index, element) {
if (index % 2 === 0) {
return;
}
element = $(element);
let isCopy = element.attr("copy");
if (isCopy === "true") { // 已经添加过 copy 按钮
return;
}
element.after(
$("<button>复制</button>").css("cursor", "pointer").css("color", "#FFF").css("background", "#515a6e").css("border-color", "#17233d").css("padding", "4px 10px").css("border-radius", "4px").css("margin-right", "10px").click(function () {
// 获取接口文本
let preTag = $(selector + " .highlight-code pre")[0];
if (!preTag) {
alert("无法复制");
return;
}
let text = preTag.textContent;
// 调用函数,复制到剪切板
copy(text);
// 提示复制成功
$(this).text("复制成功!");
// 定时改变显示文字
setTimeout(() => {
$(this).text("复制");
}, 500);
})
);
element.attr("copy", "true");
});
}
window.onload = function () {
// Initialize Swagger UI
const ui = SwaggerUIBundle({
url: "swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl,
CustomPlugin,
],
docExpansion: "none", // none(不展开) list(展开operations) full(全部展开)
onComplete: function () {
// Swagger-UI 渲染完成后回调; updateSpec 成功也会调用
// 但是如果数据太多会导致部分 HTML 元素在此时还未加载完成
console.log("Swagger UI onComplete...")
console.log("Swagger UI Version:", window.versions.swaggerUi.version)
parseBaseUrl();
addXXCaiBi();
checkSwaggerLoadingComplete(function () {
addCopy1();
addCopy2();
// Operations API 接口的点击事件
$(".opblock-tag").click(function () {
checkSwaggerLoadingComplete(function () {
addCopy1();
addCopy2();
});
});
});
},
// parameterMacro: function (operation, parameter) {
// // 展开 API 对应的 operations 时触发, 可以在此修改 指定参数的默认值
// console.log(operation, parameter);
// return "";
// },
});
window.ui = ui;
window.xxcaibi = {
"BASE_URL": "",
"copy": true,
"ADMIN_KEY": "",
"TOKEN_KEY": "",
"adminUrls": {
"/login/GenAuthKey": true,
"/login/GenAuthKey2": true,
},
}
// 监听状态变化
$('#copy-base-url').change(function () {
window.xxcaibi.copy = $(this).is(':checked');
// console.log(window.xxcaibi);
});
$('#admin-key').change(function () {
window.xxcaibi.ADMIN_KEY = $(this).val().trim();
// console.log(window.xxcaibi);
ui.specActions.updateQueryParam("key", window.xxcaibi.ADMIN_KEY, true);
});
$('#token-key').change(function () {
window.xxcaibi.TOKEN_KEY = $(this).val().trim();
// console.log(window.xxcaibi);
if (window.xxcaibi.TOKEN_KEY) {
document.getElementById('urlInput').value = window.location.origin.replace(/^http/, 'ws') + '/ws/GetSyncMsg?key=' + window.xxcaibi.TOKEN_KEY
}
ui.specActions.updateQueryParam("key", window.xxcaibi.TOKEN_KEY);
});
$('.radio-group input[type="radio"]').change(function () {
let value = $(this).val();
let configs = ui.getConfigs();
configs.docExpansion = value
// // 更新整个 UI 数据; 会刷新 UI 导致 onComplete 回调
// const spec = ui.specSelectors.specJson().toJS();
// ui.specActions.updateConfigs(spec);
// 只更新配置; 不会刷新 UI 导致 onComplete 回调
ui.configsActions.toggle();
checkSwaggerLoadingComplete(function () {
addCopy1();
addCopy2();
// Operations API 接口的点击事件
$(".opblock-tag").click(function () {
checkSwaggerLoadingComplete(function () {
addCopy1();
addCopy2();
});
});
}); // DOM 节点无变化不会触发监听
});
let parseBaseUrl = function () {
let config = window.ui.specSelectors.specJson().toJS(); // 获取 spec 对象
let basePath = config.basePath || ''; // 获取 basePath
basePath = "" ? basePath === "/" : basePath;
// 获取当前网址的协议、域名和端口
let protocol = window.location.protocol;
let hostname = window.location.hostname;
let port = window.location.port;
// 组合协议、域名和端口
const baseUrl = protocol + "//" + hostname + (port ? ":" + port : "") + basePath;
// 显示结果
console.log("BASE_URL:", baseUrl);
window.xxcaibi.BASE_URL = baseUrl;
}
let addXXCaiBi = function () {
$("#xxcaibi").insertAfter('.information-container:first').css('display', 'block');
// 判断 tg-link 不存在
if (!document.getElementsByClassName("tg-link").length) {
$(".info__contact").append(
'<div class="tg-link">' +
'<a href="https://t.me/wx_ipad" target="_blank" class="tg-button">' +
'<img src="https://upload.wikimedia.org/wikipedia/commons/8/82/Telegram_logo.svg" alt="Telegram Logo" class="tg-icon">' +
'加入 Telegram 群' +
'</a>' +
'</div>'
);
}
$("#BASE_URL").html("BASE_URL: " + window.xxcaibi.BASE_URL);
}
};
</script>
</body>
</html>
File diff suppressed because one or more lines are too long
+75
View File
@@ -0,0 +1,75 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
window.addEventListener('DOMContentLoaded', function () {
run();
});
</script>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+5989
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+20
View File
@@ -0,0 +1,20 @@
<html>
<head>
<style type="text/css">
.box{width:300px; text-align:center; font-szie:18px;}
.box img {width:100%;}
body{text-align:center}
#aa{display:block;
position:relative;
margin:auto;
}
</style>
<meta charset="utf-8">
<title>错误</title>
</head>
<body>
<div class="box" id="aa">
{{.showlog}}
</div>
</body>
</html>
+22
View File
@@ -0,0 +1,22 @@
<html>
<head>
<style type="text/css">
.box{width:300px; text-align:center; font-szie:18px;}
.box img {width:100%;}
body{text-align:center}
#aa{display:block;
position:relative;
margin:auto;
}
</style>
<meta charset="utf-8">
<title>登陆二维码</title>
</head>
<body>
<div class="box" id="aa">
<img src="/static/qrcode/{{.img}}.png" align="center">
请使用手机微信扫码登陆
{{.resp}}
</div>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
<html>
<head>
<meta charset="utf-8">
<title>系统信息</title>
</head>
<body>
<h4>{{.message}}</h4>
</body>
</html>