mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-02-24 14:15:24 +00:00
feat(v0.2.1): 添加认证参数支持和客户端下载命令生成
主要更新: - 新增 auth 参数加密传递支持 (QK/UC Cookie认证) - 实现下载命令自动生成 (curl/aria2c/迅雷) - aria2c 命令支持 8 线程 8 片段下载 - 修复 cookie 字段映射问题 - 优化前端 clientLinks 页面 - 添加认证参数文档和测试用例 - 更新 .gitignore 忽略编译目录
This commit is contained in:
444
webroot/auth-encrypt.html
Normal file
444
webroot/auth-encrypt.html
Normal file
@@ -0,0 +1,444 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>认证参数加密工具</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
max-width: 900px;
|
||||
width: 100%;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #555;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
select, input, textarea {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
select:focus, input:focus, textarea:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 14px 24px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #f5f5f5;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
|
||||
.result-section {
|
||||
margin-top: 30px;
|
||||
padding: 20px;
|
||||
background: #f9f9f9;
|
||||
border-radius: 12px;
|
||||
border: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.result-title {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 12px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.result-content {
|
||||
background: white;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
word-break: break-all;
|
||||
border: 1px solid #e0e0e0;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
margin-top: 10px;
|
||||
padding: 8px 16px;
|
||||
background: #4caf50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
background: #45a049;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: #e3f2fd;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 25px;
|
||||
border-left: 4px solid #2196f3;
|
||||
}
|
||||
|
||||
.info-box p {
|
||||
color: #1976d2;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.dynamic-fields {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dynamic-fields.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.example-box {
|
||||
background: #fff3e0;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
color: #e65100;
|
||||
border-left: 3px solid #ff9800;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔐 认证参数加密工具</h1>
|
||||
<p class="subtitle">在线加密网盘认证参数,用于调用解析接口</p>
|
||||
|
||||
<div class="info-box">
|
||||
<p><strong>加密算法:</strong> AES/ECB/PKCS5Padding</p>
|
||||
<p><strong>默认密钥:</strong> nfd_auth_key2026 (16位)</p>
|
||||
<p><strong>编码流程:</strong> JSON对象 → AES加密 → Base64编码 → URL编码</p>
|
||||
</div>
|
||||
|
||||
<form id="encryptForm">
|
||||
<div class="form-group">
|
||||
<label for="authType">认证类型 *</label>
|
||||
<select id="authType" required>
|
||||
<option value="">-- 请选择认证类型 --</option>
|
||||
<option value="accesstoken">AccessToken 认证</option>
|
||||
<option value="cookie">Cookie 认证</option>
|
||||
<option value="authorization">Authorization 头认证</option>
|
||||
<option value="password">用户名密码认证</option>
|
||||
<option value="custom">自定义认证</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="tokenField" class="form-group dynamic-fields">
|
||||
<label for="token">Token/Cookie 值 *</label>
|
||||
<textarea id="token" placeholder="输入 Token 或 Cookie 字符串"></textarea>
|
||||
<div class="example-box">
|
||||
示例: session_id=abc123; user_token=xyz789
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="usernameField" class="form-group dynamic-fields">
|
||||
<label for="username">用户名 *</label>
|
||||
<input type="text" id="username" placeholder="输入用户名">
|
||||
</div>
|
||||
|
||||
<div id="passwordField" class="form-group dynamic-fields">
|
||||
<label for="password">密码 *</label>
|
||||
<input type="password" id="password" placeholder="输入密码">
|
||||
</div>
|
||||
|
||||
<div id="extFields" class="dynamic-fields">
|
||||
<div class="form-group">
|
||||
<label for="ext1">扩展字段 1 (可选)</label>
|
||||
<input type="text" id="ext1" placeholder="格式: key:value">
|
||||
<div class="example-box">
|
||||
示例: refresh_token:your_refresh_token
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="ext2">扩展字段 2 (可选)</label>
|
||||
<input type="text" id="ext2" placeholder="格式: key:value">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="ext3">扩展字段 3 (可选)</label>
|
||||
<input type="text" id="ext3" placeholder="格式: key:value">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="encryptKey">加密密钥 (可选,默认: nfd_auth_key2026)</label>
|
||||
<input type="text" id="encryptKey" placeholder="留空使用默认密钥" value="nfd_auth_key2026">
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="submit" class="btn-primary">🔒 加密生成</button>
|
||||
<button type="button" class="btn-secondary" onclick="resetForm()">🔄 重置</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="resultSection" class="result-section" style="display: none;">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<div class="result-title">📋 原始 JSON 对象</div>
|
||||
<div class="result-content" id="jsonResult"></div>
|
||||
<button class="copy-btn" onclick="copyToClipboard('jsonResult')">复制 JSON</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<div class="result-title">🔐 加密后的参数</div>
|
||||
<div class="result-content" id="encryptedResult"></div>
|
||||
<button class="copy-btn" onclick="copyToClipboard('encryptedResult')">复制加密参数</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="result-title">🔗 完整接口调用示例</div>
|
||||
<div class="result-content" id="apiExample"></div>
|
||||
<button class="copy-btn" onclick="copyToClipboard('apiExample')">复制接口示例</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>
|
||||
<script>
|
||||
// 根据认证类型显示/隐藏相应字段
|
||||
document.getElementById('authType').addEventListener('change', function() {
|
||||
const authType = this.value;
|
||||
|
||||
// 隐藏所有动态字段
|
||||
document.querySelectorAll('.dynamic-fields').forEach(el => {
|
||||
el.classList.remove('show');
|
||||
el.querySelectorAll('input, textarea').forEach(input => {
|
||||
input.required = false;
|
||||
});
|
||||
});
|
||||
|
||||
// 根据选择显示相应字段
|
||||
if (authType === 'accesstoken' || authType === 'cookie' || authType === 'authorization') {
|
||||
document.getElementById('tokenField').classList.add('show');
|
||||
document.getElementById('token').required = true;
|
||||
} else if (authType === 'password') {
|
||||
document.getElementById('usernameField').classList.add('show');
|
||||
document.getElementById('passwordField').classList.add('show');
|
||||
document.getElementById('username').required = true;
|
||||
document.getElementById('password').required = true;
|
||||
} else if (authType === 'custom') {
|
||||
document.getElementById('tokenField').classList.add('show');
|
||||
document.getElementById('extFields').classList.add('show');
|
||||
document.getElementById('token').required = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 表单提交处理
|
||||
document.getElementById('encryptForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const authType = document.getElementById('authType').value;
|
||||
if (!authType) {
|
||||
alert('请选择认证类型');
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建 JSON 对象
|
||||
const authParam = {
|
||||
authType: authType
|
||||
};
|
||||
|
||||
if (authType === 'accesstoken' || authType === 'cookie' || authType === 'authorization' || authType === 'custom') {
|
||||
authParam.token = document.getElementById('token').value.trim();
|
||||
}
|
||||
|
||||
if (authType === 'password') {
|
||||
authParam.username = document.getElementById('username').value.trim();
|
||||
authParam.password = document.getElementById('password').value.trim();
|
||||
}
|
||||
|
||||
if (authType === 'custom') {
|
||||
['ext1', 'ext2', 'ext3'].forEach(field => {
|
||||
const value = document.getElementById(field).value.trim();
|
||||
if (value) {
|
||||
authParam[field] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示 JSON
|
||||
const jsonString = JSON.stringify(authParam, null, 2);
|
||||
document.getElementById('jsonResult').textContent = jsonString;
|
||||
|
||||
// AES 加密
|
||||
try {
|
||||
const encryptKey = document.getElementById('encryptKey').value.trim() || 'nfd_auth_key2026';
|
||||
const encrypted = encryptAuthParam(JSON.stringify(authParam), encryptKey);
|
||||
|
||||
document.getElementById('encryptedResult').textContent = encrypted;
|
||||
|
||||
// 生成接口调用示例
|
||||
const apiUrl = `/parser?url=https://pan.baidu.com/s/example&auth=${encrypted}`;
|
||||
document.getElementById('apiExample').textContent = apiUrl;
|
||||
|
||||
// 显示结果区域
|
||||
document.getElementById('resultSection').style.display = 'block';
|
||||
|
||||
// 滚动到结果区域
|
||||
document.getElementById('resultSection').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
} catch (error) {
|
||||
alert('加密失败: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
// AES 加密函数
|
||||
function encryptAuthParam(jsonString, key) {
|
||||
// 确保密钥是16位
|
||||
if (key.length !== 16) {
|
||||
throw new Error('密钥必须是16位字符');
|
||||
}
|
||||
|
||||
// AES 加密 (ECB 模式, PKCS5Padding)
|
||||
const encrypted = CryptoJS.AES.encrypt(
|
||||
jsonString,
|
||||
CryptoJS.enc.Utf8.parse(key),
|
||||
{
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
}
|
||||
);
|
||||
|
||||
// Base64 编码
|
||||
const base64 = encrypted.toString();
|
||||
|
||||
// URL 编码
|
||||
return encodeURIComponent(base64);
|
||||
}
|
||||
|
||||
// 复制到剪贴板
|
||||
function copyToClipboard(elementId) {
|
||||
const element = document.getElementById(elementId);
|
||||
const text = element.textContent;
|
||||
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
const btn = event.target;
|
||||
const originalText = btn.textContent;
|
||||
btn.textContent = '✓ 已复制';
|
||||
btn.style.background = '#4caf50';
|
||||
|
||||
setTimeout(() => {
|
||||
btn.textContent = originalText;
|
||||
btn.style.background = '';
|
||||
}, 2000);
|
||||
}).catch(err => {
|
||||
alert('复制失败,请手动复制');
|
||||
});
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
function resetForm() {
|
||||
document.getElementById('encryptForm').reset();
|
||||
document.querySelectorAll('.dynamic-fields').forEach(el => {
|
||||
el.classList.remove('show');
|
||||
});
|
||||
document.getElementById('resultSection').style.display = 'none';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user