上传文件至 /

This commit is contained in:
2025-10-17 21:29:39 +08:00
parent 08c860c684
commit 235fe98f1b
5 changed files with 2714 additions and 0 deletions

66
.gitignore vendored Normal file
View File

@@ -0,0 +1,66 @@
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Production builds
dist/
build/
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage/
# nyc test coverage
.nyc_output
# Dependency directories
jspm_packages/
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# Local cache
.cache/
# Temporary folders
tmp/
temp/
.github

View File

@@ -0,0 +1,507 @@
// ==UserScript==
// @name BIN文件上传提取Token工具
// @namespace http://tampermonkey.net/
// @version 0.5
// @description 上传BIN文件提取RoleToken并生成WSS链接
// @author 豆包编程助手
// @match *://*/*
// @grant GM_xmlhttpRequest
// @grant GM_setClipboard
// ==/UserScript==
(function() {
'use strict';
// 界面状态变量
let toolContainer = null;
let isToolVisible = false;
// 创建工具界面
function createToolUI() {
// 检查是否已存在界面
if (document.getElementById('bin-token-extractor')) {
toolContainer = document.getElementById('bin-token-extractor');
return toolContainer;
}
// 创建容器固定宽度380px
const container = document.createElement('div');
container.id = 'bin-token-extractor';
container.style.cssText = `
position: fixed;
top: 50%;
right: 20px;
transform: translateY(-50%);
background: linear-gradient(180deg, #ffffff 0%, #f9fbfd 100%);
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
width: 380px;
max-height: 80vh;
overflow-y: auto;
padding: 25px;
z-index: 99999;
display: none; /* 默认隐藏 */
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
`;
// 优化后的HTML结构
container.innerHTML = `
<div style="text-align: center; margin-bottom: 15px;">
<h2 style="margin: 0 0 10px 0; color: #2c3e50; font-size: 18px; font-weight: 600;">BIN文件Token提取工具</h2>
<p style="margin: 0; color: #7f8c8d; font-size: 13px;">上传文件提取RoleToken并生成WSS链接</p>
</div>
<div id="uploadArea" style="border: 2px dashed #d1d9e6; border-radius: 12px; padding: 30px 15px; margin-bottom: 20px; cursor: pointer; transition: all 0.3s; background-color: #f8fafc; position: relative;">
<div style="font-size: 48px; color: #3b82f6; margin-bottom: 12px;">📂</div>
<p style="font-size: 16px; color: #334155; margin-bottom: 5px; font-weight: 500;">点击或拖放BIN文件</p>
<p style="font-size: 12px; color: #94a3b8; margin: 0;">仅支持 .bin 格式文件</p>
<input type="file" id="fileInput" style="position: absolute; width: 100%; height: 100%; top: 0; left: 0; opacity: 0; cursor: pointer;" accept=".bin">
</div>
<div id="fileInfo" style="margin-top: 10px; padding: 10px; background-color: #eff6ff; border-radius: 8px; font-size: 13px; color: #3b82f6; display: none; border-left: 3px solid #3b82f6;"></div>
<div id="progressContainer" style="margin: 15px 0; display: none;">
<div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
<span style="font-size: 12px; color: #64748b; font-weight: 500;">上传进度</span>
<span id="progressText" style="font-size: 12px; color: #64748b;">0%</span>
</div>
<div style="height: 6px; background-color: #e2e8f0; border-radius: 3px; overflow: hidden;">
<div id="progressBar" style="height: 100%; background: linear-gradient(90deg, #3b82f6 0%, #60a5fa 100%); width: 0%; transition: width 0.4s ease;"></div>
</div>
</div>
<div id="statusMessage" style="padding: 10px; border-radius: 8px; margin: 10px 0; text-align: center; font-weight: 500; display: none; font-size: 13px; transition: all 0.3s;"></div>
<button id="uploadBtn" style="background: linear-gradient(90deg, #3b82f6 0%, #60a5fa 100%); color: white; border: none; padding: 12px 15px; width: 100%; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3); margin-top: 5px; opacity: 0.7; transform: translateY(2px);" disabled>上传并提取Token</button>
<div id="resultContainer" style="margin-top: 20px; padding: 18px; background-color: #f8fafc; border-radius: 12px; text-align: left; display: none; border: 1px solid #e2e8f0; transform: translateY(10px); opacity: 0; transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);">
<h3 style="color: #1e40af; margin: 0 0 12px 0; font-size: 15px; display: flex; align-items: center;">
<span style="margin-right: 8px;">🔗</span>完整WebSocket链接
</h3>
<div id="wssLinkDisplay" style="word-break: break-all; font-family: monospace; font-size: 12px; color: #1e293b; line-height: 1.6; padding: 12px; background-color: white; border-radius: 8px; border: 1px solid #e2e8f0; margin-top: 5px; max-height: 120px; overflow-y: auto;"></div>
<button id="copyWssLinkBtn" style="background: #10b981; color: white; border: none; padding: 7px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; transition: all 0.3s; margin-top: 10px; box-shadow: 0 2px 6px rgba(16, 185, 129, 0.25);">
<span style="margin-right: 5px;">📋</span>复制WSS链接
</button>
</div>
`;
document.body.appendChild(container);
toolContainer = container;
return container;
}
// 切换工具显示/隐藏状态
function toggleTool() {
if (!toolContainer) {
createToolUI();
}
isToolVisible = !isToolVisible;
if (isToolVisible) {
// 显示工具并添加淡入动画
toolContainer.style.display = 'block';
setTimeout(() => {
toolContainer.style.opacity = '1';
toolContainer.style.transform = 'translateY(-50%) scale(1)';
}, 10);
// 初始化工具功能
initToolFunctions();
} else {
// 添加淡出动画后隐藏
toolContainer.style.opacity = '0';
toolContainer.style.transform = 'translateY(-50%) scale(0.95)';
setTimeout(() => {
toolContainer.style.display = 'none';
}, 300);
}
}
// 初始化工具功能
function initToolFunctions() {
if (!toolContainer) return;
// 获取DOM元素
const uploadArea = toolContainer.querySelector('#uploadArea');
const fileInput = toolContainer.querySelector('#fileInput');
const fileInfo = toolContainer.querySelector('#fileInfo');
const uploadBtn = toolContainer.querySelector('#uploadBtn');
const progressContainer = toolContainer.querySelector('#progressContainer');
const progressBar = toolContainer.querySelector('#progressBar');
const progressText = toolContainer.querySelector('#progressText');
const statusMessage = toolContainer.querySelector('#statusMessage');
const resultContainer = toolContainer.querySelector('#resultContainer');
const wssLinkDisplay = toolContainer.querySelector('#wssLinkDisplay');
const copyWssLinkBtn = toolContainer.querySelector('#copyWssLinkBtn');
let selectedFile = null;
let extractedToken = null;
// 点击上传区域触发文件选择
uploadArea.addEventListener('click', function(e) {
if (e.target !== fileInput) {
fileInput.click();
}
});
// 拖放功能
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
uploadArea.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
uploadArea.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
uploadArea.addEventListener(eventName, unhighlight, false);
});
function highlight() {
uploadArea.style.borderColor = '#3b82f6';
uploadArea.style.backgroundColor = 'rgba(59, 130, 246, 0.05)';
uploadArea.style.transform = 'scale(1.02)';
}
function unhighlight() {
uploadArea.style.borderColor = '#d1d9e6';
uploadArea.style.backgroundColor = '#f8fafc';
uploadArea.style.transform = 'scale(1)';
}
// 文件拖放处理
uploadArea.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
if (files.length) {
handleFiles(files);
}
}
// 文件选择处理
fileInput.addEventListener('change', function() {
if (this.files.length) {
handleFiles(this.files);
}
});
function handleFiles(files) {
const file = files[0];
// 检查文件类型
if (!file.name.toLowerCase().endsWith('.bin')) {
showStatus('请选择.bin格式的文件', 'error');
return;
}
selectedFile = file;
updateFileInfo(file);
uploadBtn.disabled = false;
uploadBtn.style.opacity = '1';
uploadBtn.style.transform = 'translateY(0)';
}
function updateFileInfo(file) {
fileInfo.textContent = `已选择: ${file.name} (${formatFileSize(file.size)})`;
fileInfo.style.display = 'block';
// 添加淡入动画
fileInfo.style.opacity = '0';
setTimeout(() => {
fileInfo.style.opacity = '1';
}, 10);
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 上传按钮点击事件
uploadBtn.addEventListener('click', function() {
if (!selectedFile) {
showStatus('请先选择文件', 'error');
return;
}
// 禁用上传按钮,防止重复点击
uploadBtn.disabled = true;
uploadBtn.style.opacity = '0.7';
uploadBtn.style.transform = 'translateY(2px)';
// 隐藏之前的结果
resultContainer.style.display = 'none';
// 显示进度条
progressContainer.style.display = 'block';
progressBar.style.width = '0%';
progressText.textContent = '0%';
// 直接上传文件
uploadFile(selectedFile);
});
function uploadFile(file) {
showStatus('正在上传文件...', '');
// 读取文件内容
const reader = new FileReader();
reader.onload = function(e) {
const arrayBuffer = e.target.result;
// 配置请求
GM_xmlhttpRequest({
method: 'POST',
url: 'https://xxz-xyzw.hortorgames.com/login/authuser?_seq=1',
data: arrayBuffer,
headers: {
'Content-Type': 'application/octet-stream'
},
responseType: 'arraybuffer',
onprogress: function(e) {
if (e.lengthComputable) {
const percentComplete = (e.loaded / e.total) * 100;
progressBar.style.width = percentComplete + '%';
progressText.textContent = Math.round(percentComplete) + '%';
}
},
onload: function(response) {
if (response.status >= 200 && response.status < 300) {
try {
// 处理二进制响应
const arrayBuffer = response.response;
if (arrayBuffer) {
// 提取RoleToken
extractRoleToken(arrayBuffer);
showStatus('Token提取成功', 'success');
} else {
showStatus('上传成功,但响应为空', 'error');
}
} catch (e) {
showStatus('处理响应时出错: ' + e.message, 'error');
}
} else {
showStatus('上传失败: ' + response.statusText, 'error');
}
// 重新启用上传按钮
uploadBtn.disabled = false;
uploadBtn.style.opacity = '1';
uploadBtn.style.transform = 'translateY(0)';
},
onerror: function() {
showStatus('上传过程中发生错误', 'error');
uploadBtn.disabled = false;
uploadBtn.style.opacity = '1';
uploadBtn.style.transform = 'translateY(0)';
}
});
};
reader.onerror = function() {
showStatus('读取文件失败', 'error');
uploadBtn.disabled = false;
uploadBtn.style.opacity = '1';
uploadBtn.style.transform = 'translateY(0)';
};
reader.readAsArrayBuffer(file);
}
function extractRoleToken(arrayBuffer) {
try {
// 将ArrayBuffer转换为Uint8Array以便处理
const bytes = new Uint8Array(arrayBuffer);
// 转换为ASCII字符串以便搜索
let asciiString = '';
for (let i = 0; i < bytes.length; i++) {
// 只转换可打印的ASCII字符32-126
if (bytes[i] >= 32 && bytes[i] <= 126) {
asciiString += String.fromCharCode(bytes[i]);
} else {
asciiString += '.'; // 用点号表示不可打印字符
}
}
// 搜索Token的位置 - 查找 "Token" 字符串
const tokenIndex = asciiString.indexOf('Token');
if (tokenIndex !== -1) {
// 找到Token标记提取Token值
let tokenStart = tokenIndex + 5; // "Token"长度为5
// 跳过可能的非Base64字符直到找到Base64字符
while (tokenStart < asciiString.length) {
const char = asciiString[tokenStart];
if (isBase64Char(char)) {
break;
}
tokenStart++;
}
// 提取Base64 Token
let tokenEnd = tokenStart;
while (tokenEnd < asciiString.length && isBase64Char(asciiString[tokenEnd])) {
tokenEnd++;
}
const tokenValue = asciiString.substring(tokenStart, tokenEnd);
if (tokenValue.length > 0) {
extractedToken = tokenValue;
resultContainer.style.display = 'block';
// 触发动画
setTimeout(() => {
resultContainer.style.transform = 'translateY(0)';
resultContainer.style.opacity = '1';
}, 10);
// 生成并显示完整的WSS链接
generateAndDisplayWssLink(extractedToken);
// 平滑滚动到结果区域
resultContainer.scrollIntoView({ behavior: 'smooth' });
} else {
showStatus('找到Token标记但未找到Token值', 'error');
}
} else {
showStatus('在响应中未找到Token标记', 'error');
}
} catch (error) {
showStatus('提取Token时发生错误: ' + error.message, 'error');
}
}
function isBase64Char(char) {
// Base64字符集: A-Z, a-z, 0-9, +, /, =
return /[A-Za-z0-9+/=]/.test(char);
}
function showStatus(message, type) {
statusMessage.textContent = message;
statusMessage.className = '';
statusMessage.style.backgroundColor = '';
statusMessage.style.color = '';
statusMessage.style.boxShadow = 'none';
if (type === 'success') {
statusMessage.style.backgroundColor = 'rgba(16, 185, 129, 0.1)';
statusMessage.style.color = '#059669';
statusMessage.style.borderLeft = '3px solid #10b981';
} else if (type === 'error') {
statusMessage.style.backgroundColor = 'rgba(239, 68, 68, 0.1)';
statusMessage.style.color = '#dc2626';
statusMessage.style.borderLeft = '3px solid #ef4444';
} else {
statusMessage.style.backgroundColor = 'rgba(59, 130, 246, 0.1)';
statusMessage.style.color = '#2563eb';
statusMessage.style.borderLeft = '3px solid #3b82f6';
}
statusMessage.style.display = 'block';
statusMessage.style.opacity = '0';
statusMessage.style.transform = 'translateY(10px)';
// 触发淡入动画
setTimeout(() => {
statusMessage.style.opacity = '1';
statusMessage.style.transform = 'translateY(0)';
}, 10);
// 3秒后自动隐藏非错误状态
if (type !== 'error') {
setTimeout(() => {
statusMessage.style.opacity = '0';
statusMessage.style.transform = 'translateY(10px)';
setTimeout(() => {
statusMessage.style.display = 'none';
}, 300);
}, 3000);
}
}
// 复制完整WSS链接按钮事件
copyWssLinkBtn.addEventListener('click', function() {
const wssLink = wssLinkDisplay.textContent;
if (!wssLink) return;
GM_setClipboard(wssLink);
// 按钮点击反馈
this.style.backgroundColor = '#059669';
setTimeout(() => {
this.style.backgroundColor = '#10b981';
}, 200);
showStatus('WSS链接已复制', 'success');
});
// 生成并显示完整的WSS链接
function generateAndDisplayWssLink(token) {
// 生成随机的会话ID和连接ID
const currentTime = Date.now();
const sessId = currentTime * 100 + Math.floor(Math.random() * 100);
const connId = currentTime + Math.floor(Math.random() * 10);
// 构建WebSocket参数
const wssParams = `{"roleToken":"${token}","sessId":${sessId},"connId":${connId},"isRestore":0}`;
// 显示完整的WSS链接参数
wssLinkDisplay.textContent = wssParams;
}
}
// 创建切换按钮(兼具显示和关闭功能)
function createToggleButton() {
// 创建按钮
const toggleBtn = document.createElement('button');
toggleBtn.innerHTML = `<span style="margin-right: 6px;">🔑</span>BIN Token提取`;
toggleBtn.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
background: linear-gradient(90deg, #3b82f6 0%, #60a5fa 100%);
color: white;
border: none;
padding: 10px 18px;
border-radius: 50px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3);
white-space: nowrap;
z-index: 99998;
transition: all 0.3s;
`;
// 添加悬停效果
toggleBtn.addEventListener('mouseenter', () => {
toggleBtn.style.transform = 'translateY(-2px)';
toggleBtn.style.boxShadow = '0 6px 20px rgba(59, 130, 246, 0.4)';
});
toggleBtn.addEventListener('mouseleave', () => {
toggleBtn.style.transform = 'translateY(0)';
toggleBtn.style.boxShadow = '0 4px 15px rgba(59, 130, 246, 0.3)';
});
// 添加点击事件 - 切换显示/隐藏
toggleBtn.addEventListener('click', toggleTool);
document.body.appendChild(toggleBtn);
}
// 页面加载完成后创建切换按钮
window.addEventListener('load', createToggleButton);
})();

42
LICENSE Normal file
View File

@@ -0,0 +1,42 @@
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
Copyright (c) 2024 XYZW Team
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
You are free to:
- Share — copy and redistribute the material in any medium or format
- Adapt — remix, transform, and build upon the material
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- NonCommercial — You may not use the material for commercial purposes.
- ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
- No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
Notices:
You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation.
No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material.
For the full legal text of this license, please visit:
https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
---
ADDITIONAL TERMS FOR THIS SOFTWARE:
This software is specifically designed for educational and personal use only.
Commercial use, including but not limited to:
- Selling this software or derivative works
- Using this software in commercial gaming operations
- Integrating this software into commercial products or services
- Using this software to generate revenue in any form
is strictly prohibited without explicit written permission from the copyright holders.
The software is provided "AS IS", without warranty of any kind, express or implied,
including but not limited to the warranties of merchantability, fitness for a
particular purpose and noninfringement.

2057
auto.js Normal file

File diff suppressed because it is too large Load Diff

42
index.html Normal file
View File

@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>XYZW 游戏管理系统</title>
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<script src="/tampermonkey-emulator.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
#app {
min-height: 100vh;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
color: white;
font-size: 18px;
}
</style>
</head>
<body>
<div id="app">
<div class="loading">正在加载应用...</div>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>