diff --git a/public/index.html b/public/index.html index b6eebb6..c565ee9 100644 --- a/public/index.html +++ b/public/index.html @@ -10,6 +10,7 @@ +
@@ -102,17 +103,15 @@

🔐 OpenList Token 获取工具

- -
× -

阿里云盘扫码登录v2

+

扫码登录

@@ -147,10 +146,12 @@

隐私政策和使用条款

+ + @@ -169,13 +170,9 @@

隐私政策和使用条款

const shared_uid_views = document.getElementById('sharepoint-uid-view'); const url_hash = window.location.hash.substring(1); // 去掉地址栏上的#号 const current_host = window.location.protocol + "//" + window.location.host; - if (window.location.host === "api.oplist.org.cn") + if(window.location.host==="api.oplist.org.cn") document.getElementById('eo-show').hidden = false; getToken(); - // 阿里云盘扫码v2相关变量 - let alicloud2SessionId = null; - let alicloud2CheckInterval = null; - let alicloud2StartTime = null; let clientFingerprint = null; // 点击模态框外部关闭 window.onclick = function (event) { diff --git a/public/static/alitv.js b/public/static/alitv.js new file mode 100644 index 0000000..63ec90c --- /dev/null +++ b/public/static/alitv.js @@ -0,0 +1,172 @@ +// 阿里云盘TV版扫码登录 +class AliTVQRLogin { + constructor() { + // 创建QR登录管理器实例 + this.qrManager = new QRLoginManager({ + onSuccess: this.handleLoginSuccess.bind(this), + maxCheckTime: 30000 // 30秒过期时间 + }); + this.sidValue = null; // 存储二维码的sid + this.checkAttempts = 0; // 检查尝试次数 + this.maxCheckAttempts = 12; // 最大检查次数(30秒内,每2.5秒检查一次) + } + + // 启动阿里云盘TV版扫码登录 + async startLogin() { + try { + // 显示模态框 + this.qrManager.showModal('阿里云盘TV版扫码登录'); + + // 构建请求参数 + const client_uid = document.getElementById("client-uid-input").value; + const client_key = document.getElementById("client-key-input").value; + const server_use = document.getElementById("server-use-input").checked; + + // 获取二维码 + const requestUrl = `/alitv/qrcode?client_uid=${encodeURIComponent(client_uid)}&client_key=${encodeURIComponent(client_key)}&server_use=${server_use}`; + const response = await fetch(requestUrl); + const result = await response.json(); + + if (result.text && result.sid) { + this.qrManager.sessionId = this.qrManager.generateSessionId(); + this.qrManager.provider = 'alitv'; + this.sidValue = result.sid; + this.checkAttempts = 0; + + // 显示二维码 + this.qrManager.showQRCode(result.text); + this.qrManager.setStatus('请使用阿里云盘App扫描二维码登录TV版', 'waiting'); + + // 开始检查状态 + this.qrManager.startStatusCheck(this.checkStatus.bind(this)); + } else { + this.qrManager.setStatus(result.text || '生成二维码失败', 'error'); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + } + } catch (error) { + console.error('获取TV版二维码失败:', error); + this.qrManager.setStatus('网络错误,请重试', 'error'); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + } + } + + // 检查登录状态 + async checkStatus(elapsed) { + if (!this.sidValue) return; + + // 检查尝试次数是否达到上限 + if (this.checkAttempts >= this.maxCheckAttempts) { + this.qrManager.setStatus('二维码已过期,请点击刷新重新生成', 'error'); + this.qrManager.stopStatusCheck(); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + return; + } + + this.checkAttempts++; + + try { + const waitTime = Math.floor(elapsed / 1000); + this.qrManager.setStatus(`等待扫描... (${waitTime}s) 请使用阿里云盘App扫码登录TV版`, 'waiting'); + + // 构建请求参数 + const client_uid = document.getElementById("client-uid-input").value; + const client_key = document.getElementById("client-key-input").value; + const server_use = document.getElementById("server-use-input").checked; + + // 检查二维码状态 + const requestUrl = `/alitv/check?sid=${encodeURIComponent(this.sidValue)}&client_uid=${encodeURIComponent(client_uid)}&client_key=${encodeURIComponent(client_key)}&server_use=${server_use}`; + const response = await fetch(requestUrl); + + // 如果状态码是202,表示还在等待扫码 + if (response.status === 202) { + return; // 继续等待 + } + + // 如果状态码是200,尝试解析结果 + if (response.ok) { + const result = await response.json(); + + if (result.auth_code) { + // 获取到了授权码,表示登录成功 + this.qrManager.setStatus('登录成功!正在获取Token...', 'success'); + this.qrManager.stopStatusCheck(); + + // 获取token + await this.getToken(result.auth_code); + } + } + } catch (error) { + // 错误处理,但轮询期间的一些网络错误可能是正常的,不需要中断轮询 + console.error('检查TV版登录状态失败:', error); + // 不显示错误,继续轮询 + } + } + + // 获取Token + async getToken(authCode) { + try { + // 构建请求参数 + const client_uid = document.getElementById("client-uid-input").value; + const client_key = document.getElementById("client-key-input").value; + const server_use = document.getElementById("server-use-input").checked; + + const requestUrl = `/alitv/token?auth_code=${encodeURIComponent(authCode)}&client_uid=${encodeURIComponent(client_uid)}&client_key=${encodeURIComponent(client_key)}&server_use=${server_use}`; + const response = await fetch(requestUrl); + + if (response.ok) { + const tokenData = await response.json(); + + // 关闭模态框 + this.qrManager.closeModal(); + + // 显示成功消息 + await Swal.fire({ + position: 'top', + icon: 'success', + title: '登录成功', + text: '已成功获取阿里云盘TV版Token', + showConfirmButton: true + }); + + // 填充token字段 + if (tokenData.access_token) { + document.getElementById("access-token").value = tokenData.access_token; + } + if (tokenData.refresh_token) { + document.getElementById("refresh-token").value = tokenData.refresh_token; + } + + // 执行成功回调 + this.qrManager.onSuccess(tokenData); + } else { + this.qrManager.setStatus('获取Token失败: ' + (await response.text()), 'error'); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + } + } catch (error) { + console.error('获取TV版Token失败:', error); + this.qrManager.setStatus('获取Token失败,请重试', 'error'); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + } + } + + // 刷新二维码 + async refreshQRCode() { + document.getElementById(this.qrManager.refreshBtnId).style.display = 'none'; + this.sidValue = null; + this.checkAttempts = 0; + await this.startLogin(); + } + + // 登录成功处理函数 + handleLoginSuccess(result) { + console.log('阿里云盘TV版登录成功'); + } +} + +// 创建全局实例 +window.alitvQRLogin = new AliTVQRLogin(); + +// 开始TV版登录 +function startAliTVLogin() { + window.alitvQRLogin.startLogin(); +} \ No newline at end of file diff --git a/public/static/aliv2.js b/public/static/aliv2.js index c16de67..c6531b9 100644 --- a/public/static/aliv2.js +++ b/public/static/aliv2.js @@ -1,249 +1,195 @@ -// 生成客户端指纹 -function generateClientFingerprint() { - if (clientFingerprint) return clientFingerprint; - - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); - ctx.textBaseline = 'top'; - ctx.font = '14px Arial'; - ctx.fillText('Client fingerprint', 2, 2); - - const fingerprint = [ - navigator.userAgent, - navigator.language, - screen.width + 'x' + screen.height, - new Date().getTimezoneOffset(), - canvas.toDataURL(), - navigator.hardwareConcurrency || 'unknown', - navigator.deviceMemory || 'unknown' - ].join('|'); - - // 生成简单的哈希 - let hash = 0; - for (let i = 0; i < fingerprint.length; i++) { - const char = fingerprint.charCodeAt(i); - hash = ((hash << 5) - hash) + char; - hash = hash & hash; // 转换为32位整数 +// 阿里云盘扫码登录v2 +class AlicloudQRLogin { + constructor() { + // 创建QR登录管理器实例 + this.qrManager = new QRLoginManager({ + onSuccess: this.handleLoginSuccess.bind(this), + maxCheckTime: 30000 // 30秒过期时间 + }); } - clientFingerprint = Math.abs(hash).toString(36); - // console.log('客户端指纹生成:', clientFingerprint); - return clientFingerprint; -} + // 启动阿里云盘扫码v2登录 + async startLogin() { + try { + // 显示模态框 + this.qrManager.showModal('阿里云盘扫码登录v2'); -// 发送带有客户端指纹的请求 -async function fetchWithFingerprint(url, options = {}) { - const fingerprint = generateClientFingerprint(); - const headers = { - 'X-Client-Fingerprint': fingerprint, - ...options.headers - }; - - return fetch(url, { - ...options, - headers - }); -} + // 生成二维码 + const response = await this.qrManager.fetchWithFingerprint('/alicloud2/generate_qr'); + const result = await response.json(); -// 启动阿里云盘扫码v2登录 -async function startAlicloud2Login() { - try { - // 显示模态框 - document.getElementById('qr-modal').style.display = 'block'; - setQRStatus('正在生成二维码...', 'waiting'); - - // 生成二维码 - 使用带指纹的请求 - const response = await fetchWithFingerprint('/alicloud2/generate_qr'); - const result = await response.json(); - - if (result.success) { - alicloud2SessionId = result.session_id; - alicloud2StartTime = Date.now(); - showQRCode(result.qr_code_url); - setQRStatus('请使用阿里云盘App扫描二维码', 'waiting'); - - // 显示过期时间信息 - if (result.expires_in) { - const expireMinutes = Math.floor(result.expires_in / 60); - // console.log(`会话将在 ${expireMinutes} 分钟后过期`); - } + if (result.success) { + this.qrManager.sessionId = result.session_id; + this.qrManager.provider = 'alicloud'; + this.qrManager.showQRCode(result.qr_code_url); + this.qrManager.setStatus('请使用阿里云盘App扫描二维码', 'waiting'); - startStatusCheck(); - } else { - setQRStatus(result.error || '生成二维码失败', 'error'); - document.getElementById('refresh-qr-btn').style.display = 'inline-block'; + // 开始检查状态 + this.qrManager.startStatusCheck(this.checkStatus.bind(this)); + } else { + this.qrManager.setStatus(result.error || '生成二维码失败', 'error'); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + } + } catch (error) { + console.error('生成二维码失败:', error); + this.qrManager.setStatus('网络错误,请重试', 'error'); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; } - } catch (error) { - setQRStatus('网络错误,请重试', 'error'); - document.getElementById('refresh-qr-btn').style.display = 'inline-block'; - console.error('生成二维码失败:', error); } -} -// 显示二维码 -function showQRCode(qrUrl) { - const qrApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(qrUrl)}`; - document.getElementById('qr-code-display').innerHTML = `二维码`; - document.getElementById('qr-code-container').style.display = 'block'; -} - -// 设置状态 -function setQRStatus(message, type) { - const statusEl = document.getElementById('qr-status'); - statusEl.textContent = message; - statusEl.className = `qr-status ${type}`; - statusEl.style.display = 'block'; -} + // 检查登录状态 + async checkStatus(elapsed) { + if (!this.qrManager.sessionId) return; -// 开始状态检查 -function startStatusCheck() { - stopStatusCheck(); - alicloud2CheckInterval = setInterval(checkAlicloud2Status, 2000); -} - -// 停止状态检查 -function stopStatusCheck() { - if (alicloud2CheckInterval) { - clearInterval(alicloud2CheckInterval); - alicloud2CheckInterval = null; + try { + const response = await this.qrManager.fetchWithFingerprint( + `/alicloud2/check_login?session_id=${this.qrManager.sessionId}` + ); + const result = await response.json(); + + if (result.success) { + switch (result.status) { + case 'WAITING': + const waitTime = Math.floor(elapsed / 1000); + this.qrManager.setStatus(`等待扫描... (${waitTime}s) 请使用阿里云盘App扫码`, 'waiting'); + break; + case 'SCANED': + this.qrManager.setStatus('已扫描,请在手机上确认登录', 'scaned'); + break; + case 'CONFIRMED': + this.qrManager.setStatus('登录成功!正在获取用户信息...', 'success'); + this.qrManager.stopStatusCheck(); + setTimeout(async () => { + await this.getUserInfo(); + }, 1000); + break; + case 'EXPIRED': + this.qrManager.setStatus('二维码已过期,请点击刷新重新生成', 'error'); + this.qrManager.stopStatusCheck(); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + break; + } + } else { + if (response.status === 403) { + this.qrManager.setStatus('会话验证失败,请重新生成二维码', 'error'); + this.qrManager.stopStatusCheck(); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + } else { + this.qrManager.setStatus('检查状态失败: ' + (result.error || '未知错误'), 'error'); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + } + } + } catch (error) { + console.error('检查登录状态失败:', error); + this.qrManager.setStatus('网络连接失败,请检查网络后重试', 'error'); + document.getElementById(this.qrManager.refreshBtnId).style.display = 'inline-block'; + } } -} -// 检查登录状态 -async function checkAlicloud2Status() { - if (!alicloud2SessionId) return; - - // 检查是否超过3分钟(二维码可能过期) - const elapsed = Date.now() - alicloud2StartTime; - if (elapsed > 180000) { // 3分钟 - setQRStatus('二维码可能已过期,建议点击刷新重新生成', 'error'); - document.getElementById('refresh-qr-btn').style.display = 'inline-block'; - stopStatusCheck(); - return; - } + // 获取用户信息 + async getUserInfo() { + if (!this.qrManager.sessionId) return; - try { - // 使用带指纹的请求 - const response = await fetchWithFingerprint(`/alicloud2/check_login?session_id=${alicloud2SessionId}`); - const result = await response.json(); - - if (result.success) { - switch (result.status) { - case 'WAITING': - const waitTime = Math.floor(elapsed / 1000); - setQRStatus(`等待扫描... (${waitTime}s) 请使用阿里云盘App扫码`, 'waiting'); - break; - case 'SCANED': - setQRStatus('已扫描,请在手机上确认登录', 'scaned'); - break; - case 'CONFIRMED': - setQRStatus('登录成功!正在获取用户信息...', 'success'); - stopStatusCheck(); - // 稍等一下确保token已保存 - setTimeout(async () => { - await getAlicloud2UserInfo(); - }, 1000); - break; - case 'EXPIRED': - setQRStatus('二维码已过期,请点击刷新重新生成', 'error'); - stopStatusCheck(); - document.getElementById('refresh-qr-btn').style.display = 'inline-block'; - break; - } - } else { - // 处理会话验证失败的情况 - if (response.status === 403) { - setQRStatus('会话验证失败,请重新生成二维码', 'error'); - document.getElementById('refresh-qr-btn').style.display = 'inline-block'; - stopStatusCheck(); + try { + const response = await this.qrManager.fetchWithFingerprint( + `/alicloud2/get_user_info?session_id=${this.qrManager.sessionId}` + ); + const result = await response.json(); + + if (result.success && result.user_info) { + // 关闭模态框 + this.qrManager.closeModal(); + + // 显示成功消息 + await Swal.fire({ + position: 'top', + icon: 'success', + title: '登录成功', + html: `
用户: ${result.user_info.nick_name || result.user_info.user_id}
`, + showConfirmButton: true + }); + + // 填充token字段 + if (result.access_token) { + document.getElementById("access-token").value = result.access_token; + } + if (result.refresh_token) { + document.getElementById("refresh-token").value = result.refresh_token; + } + + // 执行成功回调 + this.qrManager.onSuccess(result); + + // 清理会话 + await this.qrManager.fetchWithFingerprint(`/alicloud2/logout?session_id=${this.qrManager.sessionId}`); + this.qrManager.sessionId = null; } else { - setQRStatus('检查状态失败: ' + (result.error || '未知错误'), 'error'); - document.getElementById('refresh-qr-btn').style.display = 'inline-block'; + if (response.status === 403) { + this.qrManager.setStatus('会话验证失败,请重新登录', 'error'); + } else { + this.qrManager.setStatus('获取用户信息失败: ' + (result.error || '未知错误'), 'error'); + } } + } catch (error) { + this.qrManager.setStatus('获取用户信息失败', 'error'); + console.error('获取用户信息失败:', error); } - } catch (error) { - console.error('检查登录状态失败:', error); - setQRStatus('网络连接失败,请检查网络后重试', 'error'); - document.getElementById('refresh-qr-btn').style.display = 'inline-block'; } -} -// 获取用户信息 -async function getAlicloud2UserInfo() { - if (!alicloud2SessionId) return; - - try { - // 使用带指纹的请求 - const response = await fetchWithFingerprint(`/alicloud2/get_user_info?session_id=${alicloud2SessionId}`); - const result = await response.json(); - - if (result.success && result.user_info) { - // 关闭模态框 - closeQRModal(); - - // 显示成功消息 - await Swal.fire({ - position: 'top', - icon: 'success', - title: '登录成功', - html: `
用户: ${result.user_info.nick_name || result.user_info.user_id}
`, - showConfirmButton: true - }); - - // 填充token字段(使用真实的tokens) - if (result.access_token) { - document.getElementById("access-token").value = result.access_token; - } - if (result.refresh_token) { - document.getElementById("refresh-token").value = result.refresh_token; - } + // 刷新二维码 + async refreshQRCode() { + document.getElementById(this.qrManager.refreshBtnId).style.display = 'none'; - // 清理会话 - await fetchWithFingerprint(`/alicloud2/logout?session_id=${alicloud2SessionId}`); - alicloud2SessionId = null; - } else { - // 处理会话验证失败的情况 - if (response.status === 403) { - setQRStatus('会话验证失败,请重新登录', 'error'); - } else { - setQRStatus('获取用户信息失败: ' + (result.error || '未知错误'), 'error'); + // 清理旧会话 + if (this.qrManager.sessionId) { + try { + await this.qrManager.fetchWithFingerprint(`/alicloud2/logout?session_id=${this.qrManager.sessionId}`); + } catch (e) { + console.error('清理旧会话失败:', e); } + this.qrManager.sessionId = null; } - } catch (error) { - setQRStatus('获取用户信息失败', 'error'); - console.error('获取用户信息失败:', error); + + await this.startLogin(); + } + + // 登录成功处理函数 + handleLoginSuccess(result) { + console.log('阿里云盘登录成功:', result); } } +// 创建全局实例 +window.alicloudQRLogin = new AlicloudQRLogin(); + +// 开始登录 +function startAlicloud2Login() { + window.alicloudQRLogin.startLogin(); +} + // 刷新二维码 -async function refreshQRCode() { - document.getElementById('refresh-qr-btn').style.display = 'none'; - // 清理旧会话 - if (alicloud2SessionId) { - try { - await fetchWithFingerprint(`/alicloud2/logout?session_id=${alicloud2SessionId}`); - } catch (e) { - // console.log('清理旧会话失败:', e); - } - alicloud2SessionId = null; - } - await startAlicloud2Login(); +function refreshQRCode() { + window.alicloudQRLogin.refreshQRCode(); } // 关闭模态框 +// 全局关闭模态框函数 function closeQRModal() { - document.getElementById('qr-modal').style.display = 'none'; - stopStatusCheck(); - - // 清理会话 - if (alicloud2SessionId) { - fetchWithFingerprint(`/alicloud2/logout?session_id=${alicloud2SessionId}`); - alicloud2SessionId = null; + // 直接操作DOM关闭模态框,而不是调用实例方法 + const modal = document.getElementById('qr-modal'); + if (modal) { + modal.style.display = 'none'; } - // 重置界面 - document.getElementById('qr-code-container').style.display = 'none'; - document.getElementById('qr-status').style.display = 'none'; - document.getElementById('refresh-qr-btn').style.display = 'none'; -} + // 如果有活跃的检查间隔,清除它 + if (window.alicloudQRLogin && window.alicloudQRLogin.qrManager) { + window.alicloudQRLogin.qrManager.stopStatusCheck(); + window.alicloudQRLogin.qrManager.resetUI(); + } + // 同样处理aliTV的情况 + if (window.alitvQRLogin && window.alitvQRLogin.qrManager) { + window.alitvQRLogin.qrManager.stopStatusCheck(); + window.alitvQRLogin.qrManager.resetUI(); + } +} \ No newline at end of file diff --git a/public/static/event.js b/public/static/event.js index 894c537..a842a8d 100644 --- a/public/static/event.js +++ b/public/static/event.js @@ -23,7 +23,11 @@ function onSelect() { client_uid_input.disabled = false; client_uid_views.hidden = false; secret_key_views.hidden = true; - const driver_pre = driver_txt_input.value.split("_")[0]; + let driver_pre = driver_txt_input.value.split("_")[0]; + if (driver_txt_input.value === "alicloud_tv") { + driver_pre = "alitv" + } + direct_url_input.value = `${current_host}/${driver_pre}/callback`; // 修改一些样式 ======================================================== @@ -39,7 +43,6 @@ function onSelect() { clientIdContainer.style.display = 'none'; appSecretContainer.style.display = 'none'; serverUseContainer.style.display = 'none'; - callbackContainer.style.display = 'none'; server_use_input.checked = true; } else { clientIdContainer.style.display = 'block'; @@ -81,6 +84,7 @@ function onSelect() { driver_txt_input.value === "onedrive_us" || driver_txt_input.value === "onedrive_de" || driver_txt_input.value === "alicloud_cs" || + driver_txt_input.value === "alicloud_tv" || driver_txt_input.value === "dropboxs_go" ) { server_use_input.checked = false; diff --git a/public/static/login.js b/public/static/login.js index 1feaf31..d9877db 100644 --- a/public/static/login.js +++ b/public/static/login.js @@ -31,6 +31,13 @@ async function getLogin(refresh = false) { await startAlicloud2Login(); return; } + + // 阿里云盘TV版扫码登录,使用新的专用函数 + if (driver_txt === "alicloud_tv" && !refresh) { + await startAliTVLogin(); + return; + } + // 刷新秘钥情况 ================================================= let base_urls = "/requests?client_uid=" if (refresh) { diff --git a/public/static/qrlogin.js b/public/static/qrlogin.js new file mode 100644 index 0000000..bf24394 --- /dev/null +++ b/public/static/qrlogin.js @@ -0,0 +1,170 @@ +// 通用扫码登录模块 +class QRLoginManager { + constructor(options = {}) { + this.modalId = options.modalId || 'qr-modal'; + this.codeContainerId = options.codeContainerId || 'qr-code-container'; + this.codeDisplayId = options.codeDisplayId || 'qr-code-display'; + this.statusId = options.statusId || 'qr-status'; + this.refreshBtnId = options.refreshBtnId || 'refresh-qr-btn'; + this.closeModal = options.closeModal ? options.closeModal : this.defaultCloseModal.bind(this); + this.checkInterval = null; + this.sessionId = null; + this.startTime = null; + this.provider = null; // 提供商名称,如 'alicloud', 'alitv' 等 + this.onSuccess = options.onSuccess || function() {}; + this.maxCheckTime = options.maxCheckTime || 180000; // 默认3分钟 + this.checkFrequency = options.checkFrequency || 2500; // 默认2.5秒检查一次 + } + + // 显示二维码模态框 + showModal(title = '扫码登录') { + const modal = document.getElementById(this.modalId); + if (modal) { + // 设置标题 + const titleElement = modal.querySelector('h4'); + if (titleElement) { + titleElement.textContent = title; + } + modal.style.display = 'block'; + this.setStatus('正在生成二维码...', 'waiting'); + } + } + + // 默认关闭模态框方法 + defaultCloseModal() { + const modal = document.getElementById(this.modalId); + if (modal) { + modal.style.display = 'none'; + } + this.stopStatusCheck(); + this.resetUI(); + } + + // 重置UI状态 + resetUI() { + document.getElementById(this.codeContainerId).style.display = 'none'; + document.getElementById(this.statusId).style.display = 'none'; + document.getElementById(this.refreshBtnId).style.display = 'none'; + } + + // 显示二维码 + showQRCode(qrUrl, size = 200) { + try { + const codeDisplayElement = document.getElementById(this.codeDisplayId); + codeDisplayElement.innerHTML = ''; // 清除之前的内容 + // 创建canvas元素 + const canvas = document.createElement('canvas'); + codeDisplayElement.appendChild(canvas); + // 使用新创建的canvas元素 + QRCode.toCanvas(canvas, qrUrl, { + width: size, + margin: 1, + }, function(error) { + if (error) console.error('QR码生成错误:', error); + }); + + document.getElementById(this.codeContainerId).style.display = 'block'; + } catch (error) { + console.error('生成QR码失败:', error); + } + } + + // 设置状态 + setStatus(message, type) { + const statusEl = document.getElementById(this.statusId); + statusEl.textContent = message; + statusEl.className = `qr-status ${type}`; + statusEl.style.display = 'block'; + } + + // 开始状态检查 + startStatusCheck(checkFunction) { + this.stopStatusCheck(); + this.startTime = Date.now(); + this.checkInterval = setInterval(() => { + // 检查是否超过最大时间 + const elapsed = Date.now() - this.startTime; + if (elapsed > this.maxCheckTime) { + this.setStatus('二维码已过期,请点击刷新重新生成', 'error'); + document.getElementById(this.refreshBtnId).style.display = 'inline-block'; + this.stopStatusCheck(); + return; + } + + // 执行传入的检查函数 + if (typeof checkFunction === 'function') { + checkFunction(elapsed); + } + }, this.checkFrequency); + } + + // 停止状态检查 + stopStatusCheck() { + if (this.checkInterval) { + clearInterval(this.checkInterval); + this.checkInterval = null; + } + } + + // 生成随机会话ID + generateSessionId() { + return Date.now().toString(36) + Math.random().toString(36).substring(2, 15); + } + + // 获取客户端指纹 + getClientFingerprint() { + if (window.clientFingerprint) return window.clientFingerprint; + + // 简单指纹生成 + const fingerprint = [ + navigator.userAgent, + navigator.language, + screen.width + 'x' + screen.height, + new Date().getTimezoneOffset(), + navigator.hardwareConcurrency || 'unknown', + navigator.deviceMemory || 'unknown' + ].join('|'); + + // 生成简单的哈希 + let hash = 0; + for (let i = 0; i < fingerprint.length; i++) { + const char = fingerprint.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; // 转换为32位整数 + } + + window.clientFingerprint = Math.abs(hash).toString(36); + return window.clientFingerprint; + } + + // 发送带有客户端指纹的请求 + async fetchWithFingerprint(url, options = {}) { + const fingerprint = this.getClientFingerprint(); + const headers = { + 'X-Client-Fingerprint': fingerprint, + ...options.headers + }; + + return fetch(url, { + ...options, + headers + }); + } +} + +// 显示错误消息的辅助函数 +async function showErrorMessage(title, message, code = "") { + let errorMsg = message; + if (code) errorMsg += ` (错误码: ${code})`; + + await Swal.fire({ + icon: 'error', + title: title + '失败', + text: errorMsg, + showConfirmButton: true + }); +} + +// 导出模块 +window.QRLoginManager = QRLoginManager; +window.showErrorMessage = showErrorMessage; \ No newline at end of file diff --git a/public/static/token.js b/public/static/token.js index 25c4d80..86e1674 100644 --- a/public/static/token.js +++ b/public/static/token.js @@ -4,7 +4,6 @@ async function getToken() { const json_byte = Uint8Array.from(atob(url_hash), c => c.charCodeAt(0)); const json_text = new TextDecoder().decode(json_byte); const json_data = JSON.parse(json_text); - console.log(json_data); const server_use = json_data.server_use; const client_uid = json_data.client_uid; const secret_key = json_data.secret_key; diff --git a/src/driver/alicloud_oa.ts b/src/driver/alicloud_oa.ts index 3904b7b..7e654de 100644 --- a/src/driver/alicloud_oa.ts +++ b/src/driver/alicloud_oa.ts @@ -64,7 +64,6 @@ export async function alyLogin(c: Context) { const result = await pubLogin(c, JSON.stringify(params_info), request_urls, false, "POST", "json", {'Content-Type': 'application/json'}); - console.log(result); if (!result.qrCodeUrl) return c.json({"text": result.message}, 500); return c.json({"text": result.qrCodeUrl, "sid": result.sid}, 200); } @@ -73,7 +72,6 @@ export async function alyLogin(c: Context) { // 令牌申请 ############################################################################## export async function alyToken(c: Context) { const clients_info: configs.Clients = getCookie(c); - if (clients_info.drivers == "alicloud_tv") return await checkStatus(c, clients_info); let oauth_type: string | undefined = c.req.query('grant_type') if (!clients_info.servers) clients_info.servers = c.req.query('server_use') == "true" if (!clients_info.drivers) return c.json({text: 'No Cookies',}, 401); @@ -138,7 +136,6 @@ export async function genToken(c: Context) { const refresh_text: string | undefined = c.req.query('refresh_ui'); if (!clients_info) return c.json({text: "传入参数缺少"}, 500); if (!refresh_text) return c.json({text: "缺少刷新令牌"}, 500); - if (clients_info.drivers == "alicloud_tv") return await refreshToken(c, refresh_text); // 请求参数 ========================================================================== const params: Record = { client_id: clients_info.servers ? c.env.alicloud_uid : clients_info.app_uid, diff --git a/src/driver/alicloud_tv.ts b/src/driver/alicloud_tv.ts index ac71e35..c3eda86 100644 --- a/src/driver/alicloud_tv.ts +++ b/src/driver/alicloud_tv.ts @@ -1,17 +1,9 @@ import {Context} from "hono"; -import {encodeCallbackData, Secrets} from "../shares/secrets"; - -// 用于替代 Node.js 的 crypto.randomUUID -function generateUUID(): string { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - const r = Math.random() * 16 | 0; - const v = c === 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); -} +import {pubLogin} from "../shares/oauthv2"; +import {Requests} from "../shares/request"; // 定义API响应的接口 -interface ApiResponse { +interface AliCloudTVApiResponse { code?: number; data?: Record; t?: string; @@ -34,17 +26,13 @@ class AliyunPanTvToken { private akv: string; private apv: string; private headersBase: Record; - private initialized: boolean = false; constructor() { - // 构造函数中只设置默认值,不执行异步操作 - // this.timestamp = Date.now().toString(); // 设置默认时间戳 - this.timestamp = '' - this.uniqueId = generateUUID().replace(/-/g, ''); + this.timestamp = Date.now().toString(); // 设置默认时间戳 + this.uniqueId = this.generateUUID(); this.wifimac = Math.floor(100000000000 + Math.random() * 900000000000).toString(); - // this.wifimac = "020000000000"; this.model = "SM-S908E"; - this.brand = "samsung"; + this.brand = "Samsung"; this.akv = "2.6.1143"; this.apv = "1.4.0.2"; @@ -55,30 +43,69 @@ class AliyunPanTvToken { }; } - // 懒加载初始化方法,在首次API调用时执行 - private async ensureInitialized(): Promise { - if (this.initialized) return; + private generateUUID(): string { + return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + const r = Math.random() * 16 | 0; + const v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); + } + + private getHeaders(sign: string): Record { + return { + ...this.headersBase, + "akv": this.akv, + "apv": this.apv, + "b": this.brand, + "d": this.uniqueId, + "m": this.model, + "n": this.model, + "t": this.timestamp, + "wifiMac": this.wifimac, + "sign": sign, + }; + } + private getParams(): Record { + return { + "akv": this.akv, + "apv": this.apv, + "b": this.brand, + "d": this.uniqueId, + "m": this.model, + "mac": "", + "n": this.model, + "t": this.timestamp, + "wifiMac": this.wifimac, + }; + } + + // refreshTimestamp 刷新时间戳 + private async refreshTimestamp(c: Context): Promise { try { - const response = await fetch("http://api.extscreen.com/timestamp"); - const data = await response.json() as { data?: { timestamp?: number } }; - if (data?.data?.timestamp) { - this.timestamp = data.data.timestamp.toString(); + const response = await pubLogin( + c, + "", + "http://api.extscreen.com/timestamp", + false, + "GET", + "json", + this.headersBase, + ) as { data?: { timestamp?: number } }; + + if (response?.data?.timestamp) { + this.timestamp = response.data.timestamp.toString(); } } catch (error) { console.error("获取时间戳错误:", error); - // 保持默认时间戳 - } finally { - this.initialized = true; + this.timestamp = Date.now().toString(); // 如果获取失败,使用当前时间戳 } } - // 精确匹配Python版本的h函数 + // h 根据时间戳和字符数组生成哈希值 private h(charArray: string[], modifier: string): string { - // 获取唯一字符,与Python的list(dict.fromkeys(char_array))等效 const uniqueChars = Array.from(new Set(charArray)); const modifierStr = String(modifier); - // 与Python的substring逻辑完全一致 const numericModifierStr = modifierStr.length > 7 ? modifierStr.substring(7) : '0'; let numericModifier: number; @@ -100,31 +127,13 @@ class AliyunPanTvToken { newCharCode += 33; } - try { - transformedString += String.fromCharCode(newCharCode); - } catch { - // 跳过无效字符,与Python行为一致 - } + transformedString += String.fromCharCode(newCharCode); } return transformedString; } - private getParams(): Record { - return { - "akv": this.akv, - "apv": this.apv, - "b": this.brand, - "d": this.uniqueId, - "m": this.model, - "mac": "", - "n": this.model, - "t": this.timestamp, - "wifiMac": this.wifimac, - }; - } - - // 与Python版本完全匹配的MD5实现 + // md5 MD5实现 private async md5(str: string): Promise { const encoder = new TextEncoder(); const data = encoder.encode(str); @@ -133,7 +142,7 @@ class AliyunPanTvToken { return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); } - // 与Python版本完全匹配的SHA-256实现 + // sha256 SHA-256实现 private async sha256(str: string): Promise { const encoder = new TextEncoder(); const data = encoder.encode(str); @@ -142,11 +151,10 @@ class AliyunPanTvToken { return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); } - // 精确匹配Python版本的generateKey实现 + // generateKey 生成 aesKey private async generateKey(): Promise { const params = this.getParams(); const sortedKeys = Object.keys(params).sort(); - // 使用与Python完全相同的连接方式 let concatenatedParams = ""; for (const key of sortedKeys) { if (key !== 't') { @@ -159,11 +167,11 @@ class AliyunPanTvToken { return await this.md5(hashedKey); } + // generateKeyWithT 由时间戳参与生成 aesKey private async generateKeyWithT(t: string): Promise { const params = this.getParams(); params.t = t; const sortedKeys = Object.keys(params).sort(); - // 使用与Python完全相同的连接方式 let concatenatedParams = ""; for (const key of sortedKeys) { if (key !== 't') { @@ -176,7 +184,7 @@ class AliyunPanTvToken { return await this.md5(hashedKey); } - // 与Python版本完全匹配的随机IV生成 + // randomIvStr 随机IV生成 private randomIvStr(length: number = 16): string { const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; @@ -186,40 +194,36 @@ class AliyunPanTvToken { return result; } - // 与Python版本完全匹配的加密实现 + // encrypt 加密实现 private async encrypt(plainObj: any): Promise<{ iv: string, ciphertext: string }> { - // 1. 生成密钥 - 与Python完全一致 + // 生成 aes密钥 const key = await this.generateKey(); - - // 2. 生成随机IV - 与Python完全一致 + // 生成随机IV const ivStr = this.randomIvStr(16); - - // 3. 准备加密数据 - 确保使用与Python相同的JSON序列化格式 - // Python: json.dumps(plain_obj, separators=(',', ':')) + // 待加密数据 const plaintext = JSON.stringify(plainObj).replace(/\s/g, ''); - // 4. 创建UTF-8编码的数据 const encoder = new TextEncoder(); const keyBytes = encoder.encode(key); const ivBytes = encoder.encode(ivStr); const plaintextBytes = encoder.encode(plaintext); - // 6. 使用Web Crypto API进行AES-CBC加密 + // AES-CBC加密 const cryptoKey = await crypto.subtle.importKey( 'raw', keyBytes, - {name: 'AES-CBC', length: 128}, + { name: 'AES-CBC', length: 256 }, false, ['encrypt'] ); const encryptedBuffer = await crypto.subtle.encrypt( - {name: 'AES-CBC', iv: ivBytes}, + { name: 'AES-CBC', iv: ivBytes }, cryptoKey, plaintextBytes ); - // 7. 转换为Base64编码 - 与Python的base64.b64encode(ciphertext).decode("utf-8")一致 + // 转换为Base64编码 const encryptedArray = new Uint8Array(encryptedBuffer); let binary = ''; for (let i = 0; i < encryptedArray.length; i++) { @@ -227,49 +231,48 @@ class AliyunPanTvToken { } const base64Ciphertext = btoa(binary); - // 8. 返回与Python一致的结构 return { iv: ivStr, ciphertext: base64Ciphertext }; } - // 与Python版本完全匹配的解密实现 + // decrypt 解密实现 private async decrypt(ciphertext: string, iv: string, t?: string): Promise { try { - // 1. 生成密钥 - 与Python一致 + // 生成密钥 const key = t ? await this.generateKeyWithT(t) : await this.generateKey(); - // 2. 解码Base64密文 - 与Python一致 + // 解码Base64密文 const binaryString = atob(ciphertext); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } - // 3. 解码十六进制IV - 与Python中的bytes.fromhex(iv)一致 + // 解码十六进制IV const ivBytes = new Uint8Array(iv.length / 2); for (let i = 0; i < iv.length; i += 2) { ivBytes[i / 2] = parseInt(iv.substring(i, i + 2), 16); } - // 4. 导入密钥 + // 导入密钥 const cryptoKey = await crypto.subtle.importKey( 'raw', new TextEncoder().encode(key), - {name: 'AES-CBC', length: 256}, + { name: 'AES-CBC', length: 256 }, false, ['decrypt'] ); - // 5. 解密 + // 解密 const decryptedBuffer = await crypto.subtle.decrypt( - {name: 'AES-CBC', iv: ivBytes}, + { name: 'AES-CBC', iv: ivBytes }, cryptoKey, bytes ); - // 7. 转换为字符串 + // 转换为字符串 return new TextDecoder().decode(decryptedBuffer); } catch (error) { console.error("解密失败:", error); @@ -277,23 +280,7 @@ class AliyunPanTvToken { } } - private getHeaders(sign: string): Record { - const params = this.getParams(); - return { - ...this.headersBase, - "akv": this.akv, - "apv": this.apv, - "b": this.brand, - "d": this.uniqueId, - "m": this.model, - "n": this.model, - "t": this.timestamp, - "wifiMac": this.wifimac, - "sign": sign, - }; - } - - // 与Python版本完全匹配的计算sign实现 + // 请求sign生成 private async computeSign(method: string, apiPath: string): Promise { const apiPathAdjusted = "/api" + apiPath; const key = await this.generateKey(); @@ -301,110 +288,35 @@ class AliyunPanTvToken { return await this.sha256(content); } - public async getToken(refreshToken: string): Promise { - // 确保已初始化 - await this.ensureInitialized(); + // getTokenByCode 合并后的函数,处理刷新Token和通过授权码获取Token + public async getTokenByCode(c: Context, code: string, isRefreshToken: boolean = false): Promise { + // 刷新时间戳 + await this.refreshTimestamp(c); try { - const bodyObj = {refresh_token: refreshToken}; + // 根据是刷新token还是授权码设置不同的请求体 + const bodyObj = isRefreshToken ? { refresh_token: code } : { code: code }; const encrypted = await this.encrypt(bodyObj); const reqBody = { iv: encrypted.iv, ciphertext: encrypted.ciphertext }; - - // console.log("[*] (Sign) Request Body:", JSON.stringify(reqBody)); - const sign = await this.computeSign("POST", "/v4/token"); const headers = this.getHeaders(sign); - const response = await fetch( + // 使用pubLogin替代直接调用Requests + const responseData = await pubLogin( + c, + JSON.stringify(reqBody), "https://api.extscreen.com/aliyundrive/v4/token", - { - method: "POST", - headers: headers, - body: JSON.stringify(reqBody) - } - ); - - // console.log("[*] (Sign) Response Status:", response.status); - const responseData = await response.json() as ApiResponse; - // console.log("[*] (Sign) Response Body:", responseData); - - // 类型安全检查 - if (!responseData) { - throw new Error("Invalid response data"); - } - - // 检查响应数据中是否有code字段 - if (responseData.code !== undefined && responseData.code !== 200) { - throw new Error(JSON.stringify(responseData)); - } - - // 类型安全地访问data字段 - if (!responseData.data) { - throw new Error("Response missing data field"); - } - - const tokenData = responseData.data as TokenData; - const t = responseData.t ? responseData.t.toString() : this.timestamp; - - if (!tokenData.ciphertext || !tokenData.iv) { - throw new Error("Token data missing required fields"); - } - - return await this.decrypt(tokenData.ciphertext, tokenData.iv, t); - } catch (error) { - console.error("获取Token错误:", error); - throw error; - } - } - - public async getRefreshtoken(authToken: string): Promise { - // 确保已初始化 - await this.ensureInitialized(); - - try { - const bodyObj = {code: authToken}; - const encrypted = await this.encrypt(bodyObj); - const reqBody = { - iv: encrypted.iv, - ciphertext: encrypted.ciphertext - }; - - console.log("[*] (Sign) Request Body:", JSON.stringify(reqBody)); - - const sign = await this.computeSign("POST", "/v4/token"); - const headers = this.getHeaders(sign); - - console.log("[*] (Sign) Headers:", headers); - - const response = await fetch( - "https://api.extscreen.com/aliyundrive/v4/token", - { - method: "POST", - headers: headers, - body: JSON.stringify(reqBody) - } - ); - - console.log("[*] (Sign) Response Status:", response.status); - const responseData = await response.json() as ApiResponse; - console.log("[*] (Sign) Response Body:", responseData); - - // 类型安全检查 - if (!responseData) { - throw new Error("Invalid response data"); - } - - // 检查响应数据中是否有code字段 - if (responseData.code !== undefined && responseData.code !== 200) { - throw new Error(JSON.stringify(responseData)); - } + false, + "POST", + "json", + headers + ) as AliCloudTVApiResponse; - // 类型安全地访问data字段 - if (!responseData.data) { - throw new Error("Response missing data field"); + if (!responseData || responseData.code !== 200 || !responseData.data) { + throw new Error(responseData ? JSON.stringify(responseData) : "Invalid response data"); } const tokenData = responseData.data as TokenData; @@ -416,60 +328,44 @@ class AliyunPanTvToken { return await this.decrypt(tokenData.ciphertext, tokenData.iv, t); } catch (error) { - console.error("获取RefreshToken错误:", error); + console.error(`获取${isRefreshToken ? "Token" : "RefreshToken"}错误:`, error); throw error; } } - public async getQrcodeUrl(): Promise<{ qr_link: string, sid: string }> { - // 确保已初始化 - await this.ensureInitialized(); + // getQrcodeUrl 获取二维码链接 + public async getQrcodeUrl(c: Context): Promise<{ qr_link: string, sid: string }> { + // 刷新时间戳 + await this.refreshTimestamp(c); try { - // 使用与Python代码完全一致的参数结构 const bodyObj = { scopes: ["user:base", "file:all:read", "file:all:write"].join(","), width: 500, height: 500 }; - const encrypted = await this.encrypt(bodyObj); const reqBody = { iv: encrypted.iv, ciphertext: encrypted.ciphertext }; - console.log("[*] (Qrcode) Request Body:", JSON.stringify(reqBody)); - const sign = await this.computeSign("POST", "/v2/qrcode"); const headers = this.getHeaders(sign); - const response = await fetch( + // 使用pubLogin替代直接调用Requests + const responseData = await pubLogin( + c, + JSON.stringify(reqBody), "https://api.extscreen.com/aliyundrive/v2/qrcode", - { - method: "POST", - headers: headers, - body: JSON.stringify(reqBody) - } - ); - - // console.log("[*] (Qrcode) Response Status:", response.status); - const responseData = await response.json() as ApiResponse; - // console.log("[*] (Qrcode) Response Body:", responseData); - - // 类型安全检查 - if (!responseData) { - throw new Error("Invalid response data"); - } - - // 检查响应数据中是否有code字段 - if (responseData.code !== undefined && responseData.code !== 200) { - throw new Error(JSON.stringify(responseData)); - } + false, + "POST", + "json", + headers + ) as AliCloudTVApiResponse; - // 类型安全地访问data字段 - if (!responseData.data) { - throw new Error("Response missing data field"); + if (!responseData || responseData.code !== 200 || !responseData.data) { + throw new Error(responseData ? JSON.stringify(responseData) : "Invalid response data"); } const qrcodeData = responseData.data as TokenData; @@ -480,16 +376,14 @@ class AliyunPanTvToken { } const decryptedData = await this.decrypt(qrcodeData.ciphertext, qrcodeData.iv, t); - const data = JSON.parse(decryptedData) as { sid?: string; qrCodeUrl?: string }; - // console.log("[*] (Qrcode) Decrypted Data:", data); + const data = JSON.parse(decryptedData) as { sid?: string }; if (!data.sid) { throw new Error("Missing sid in decrypted data"); } - // const qrLink = "https://www.aliyundrive.com/o/oauth/authorize?sid=" + data.sid] - return {qr_link: data.qrCodeUrl, sid: data.sid}; - // return { qr_link: qrLink, sid: data.sid }; + const qrLink = "https://www.aliyundrive.com/o/oauth/authorize?sid=" + data.sid; + return { qr_link: qrLink, sid: data.sid }; } catch (error) { console.error("获取二维码错误:", error); throw error; @@ -497,7 +391,6 @@ class AliyunPanTvToken { } } -// 延迟创建实例 - 不在全局作用域中执行 let clientInstance: AliyunPanTvToken | null = null; // 获取客户端实例的函数 @@ -508,101 +401,102 @@ function getClient(): AliyunPanTvToken { return clientInstance; } +// checkQrcodeStatus 检查二维码状态 +async function checkQrcodeStatus(c: Context, sid: string): Promise<{ auth_code: string } | null> { + let headersBase ; + try { + headersBase = { + "User-Agent": "Mozilla/5.0 (Linux; U; Android 15; zh-cn; SM-S908E Build/UKQ1.231108.001) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1", + "Host": "openapi.alipan.com", + "Content-Type": "text/plain;charset=UTF-8", + }; + const response = await Requests( + c, + "", + `https://openapi.alipan.com/oauth/qrcode/${sid}/status`, + "GET", + false, + headersBase, + "json" + ); + + if (response.text) { + return null; + } + + if (response && response.status === "LoginSuccess" && response.authCode) { + return { auth_code: response.authCode }; + } + + return null; + } catch (error) { + console.error("检查二维码状态错误:", error); + throw error; + } +} -// 导出的接口函数保持不变 +// getQRCode 获取二维码链接 export async function getQRCode(c: Context) { try { const client = getClient(); - const qrData = await client.getQrcodeUrl(); - return c.json({text: qrData.qr_link, sid: qrData.sid}); + const qrData = await client.getQrcodeUrl(c); + return c.json({ text: qrData.qr_link, sid: qrData.sid }); } catch (error) { console.error("获取二维码失败:", error); - return c.json({text: "获取二维码失败"}, 500); + return c.json({ text: "获取二维码失败" }, 500); } } -export async function checkStatus(c: Context, client: Record) { +// checkStatus 检查二维码状态 +export async function checkStatus(c: Context) { try { const sid = c.req.query('sid'); if (!sid) { - return c.json({text: "缺少sid参数"}, 400); + return c.json({ text: "缺少sid参数" }, 400); } - const status = await checkQrcodeStatus(sid); + const status = await checkQrcodeStatus(c, sid); if (status) { - // return c.json(status); - const result_data: Record = await getTokenByAuthCode(c, status.auth_code) - const result_json = await result_data.json(); - // console.log(result_json); - const callbackData: Secrets = { - access_token: result_json.access_token, - refresh_token: result_json.refresh_token, - client_uid: client.app_uid, - client_key: client.app_key, - driver_txt: client.drivers, - server_use: client.servers, - } - // console.log(callbackData); - return c.json(callbackData, 200); - + return c.json(status); } - return c.json({text: "等待扫码"}, 202); + return c.json({ text: "等待扫码" }, 202); } catch (error) { console.error("检查状态失败:", error); - return c.json({text: "检查状态失败"}, 500); - } -} - -async function checkQrcodeStatus(sid: string): Promise<{ auth_code: string } | null> { - try { - const response = await fetch( - `https://openapi.alipan.com/oauth/qrcode/${sid}/status` - ); - - if (!response.ok) { - return null; - } - - const data = await response.json() as { status?: string; authCode?: string }; - if (data && data.status === "LoginSuccess" && data.authCode) { - return {auth_code: data.authCode}; - } - return null; - } catch (error) { - console.error("检查二维码状态错误:", error); - throw error; + return c.json({ text: "检查状态失败" }, 500); } } -export async function getTokenByAuthCode(c: Context, authCode: string = "") { +// getTokenByAuthCode 使用authCode获取Token +export async function getTokenByAuthCode(c: Context) { try { - // const authCode = c.req.query('auth_code'); + const authCode = c.req.query('auth_code'); if (!authCode) { - return c.json({text: "缺少auth_code参数"}, 400); + return c.json({ text: "缺少auth_code参数" }, 400); } const client = getClient(); - const tokenData = await client.getRefreshtoken(authCode); + const tokenData = await client.getTokenByCode(c, authCode, false); return c.json(JSON.parse(tokenData)); } catch (error) { console.error("获取Token失败:", error); - return c.json({text: "获取Token失败"}, 500); + return c.json({ text: "获取Token失败" }, 500); } } -export async function refreshToken(c: Context, refreshToken: string) { +// refreshToken 刷新Token +export async function refreshToken(c: Context) { try { - // const refreshToken = c.req.query('refresh_ui'); + const refreshToken = c.req.query('refresh_ui'); if (!refreshToken) { - return c.json({text: "缺少refresh_token参数"}, 400); + return c.json({ text: "缺少refresh_token参数" }, 400); } const client = getClient(); - const tokenData = await client.getToken(refreshToken); + const tokenData = await client.getTokenByCode(c, refreshToken, true); return c.json(JSON.parse(tokenData)); } catch (error) { console.error("刷新Token失败:", error); - return c.json({text: "刷新Token失败"}, 500); + return c.json({ text: "刷新Token失败" }, 500); } } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 112b6bb..887ed46 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ import * as goapi from './driver/googleui_oa'; import * as yanui from './driver/yandexui_oa'; import * as drops from './driver/dropboxs_oa'; import * as quark from './driver/quarkpan_oa'; +import * as alitv from './driver/alicloud_tv'; export type Bindings = { MAIN_URLS: string, baiduyun_ext: string, @@ -27,27 +28,22 @@ export const app = new Hono<{ Bindings: Bindings }>() app.get('/dropboxs/requests', async (c) => { return drops.getLogin(c); }) - // 令牌申请 ############################################################################## app.get('/dropboxs/callback', async (c) => { return drops.urlParse(c); }) - // 令牌刷新 ############################################################################## app.get('/dropboxs/renewapi', async (c: Context) => { return drops.apiRenew(c); }); - // 登录申请 ############################################################################## app.get('/onedrive/requests', async (c) => { return oneui.oneLogin(c); }) - // 令牌申请 ############################################################################## app.get('/onedrive/callback', async (c) => { return oneui.oneToken(c); }) - // 令牌刷新 ############################################################################## app.get('/onedrive/renewapi', async (c: Context) => { return oneui.genToken(c); @@ -57,12 +53,10 @@ app.get('/onedrive/renewapi', async (c: Context) => { app.get('/alicloud/requests', async (c: Context) => { return aliui.alyLogin(c); }); - // 令牌申请 ############################################################################## app.get('/alicloud/callback', async (c: Context) => { return aliui.alyToken(c); }); - // 令牌刷新 ############################################################################## app.get('/alicloud/renewapi', async (c: Context) => { return aliui.genToken(c); @@ -72,17 +66,14 @@ app.get('/alicloud/renewapi', async (c: Context) => { app.get('/alicloud2/generate_qr', async (c: Context) => { return aliqr.generateQR(c); }); - // 阿里云盘扫码2 - 检查登录状态 ############################################################################## app.get('/alicloud2/check_login', async (c: Context) => { return aliqr.checkLogin(c); }); - // 令牌刷新 ############################################################################## app.get('/alicloud2/renewapi', async (c: Context) => { return aliqr.genToken(c); }); - // 阿里云盘扫码2 - 获取用户信息 ############################################################################## app.get('/alicloud2/get_user_info', async (c: Context) => { return aliqr.getUserInfo(c); @@ -183,5 +174,24 @@ app.get('/quarkyun/renewapi', async (c) => { return await quark.apiRenew(c); }); +// 阿里云盘TV版 - 获取二维码 ############################################################################## +app.get('/alitv/qrcode', async (c: Context) => { + return await alitv.getQRCode(c); +}); + +// 阿里云盘TV版 - 检查扫码状态 ############################################################################## +app.get('/alitv/check', async (c: Context) => { + return await alitv.checkStatus(c); +}); + +// 阿里云盘TV版 - 获取Token ############################################################################## +app.get('/alitv/token', async (c: Context) => { + return await alitv.getTokenByAuthCode(c); +}); + +// 阿里云盘TV版 - 刷新Token ############################################################################## +app.get('/alitv/renewapi', async (c: Context) => { + return await alitv.refreshToken(c); +}); export default app