| <!DOCTYPE html> |
| <html lang="zh-CN"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Cursor To OpenAI - API Key 管理</title> |
| <style> |
| body { |
| font-family: 'Arial', sans-serif; |
| line-height: 1.6; |
| margin: 0; |
| padding: 20px; |
| color: #333; |
| max-width: 1200px; |
| margin: 0 auto; |
| } |
| h1, h2 { |
| color: #2c3e50; |
| } |
| .container { |
| display: flex; |
| flex-direction: column; |
| gap: 20px; |
| } |
| .card { |
| background: #fff; |
| border-radius: 8px; |
| box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
| padding: 20px; |
| } |
| .form-group { |
| margin-bottom: 15px; |
| } |
| label { |
| display: block; |
| margin-bottom: 5px; |
| font-weight: bold; |
| } |
| input, textarea { |
| width: 100%; |
| padding: 8px; |
| border: 1px solid #ddd; |
| border-radius: 4px; |
| font-size: 16px; |
| } |
| textarea { |
| min-height: 100px; |
| font-family: monospace; |
| } |
| button { |
| background: #3498db; |
| color: white; |
| border: none; |
| padding: 10px 15px; |
| border-radius: 4px; |
| cursor: pointer; |
| font-size: 16px; |
| } |
| button:hover { |
| background: #2980b9; |
| } |
| table { |
| width: 100%; |
| border-collapse: collapse; |
| } |
| th, td { |
| padding: 12px; |
| text-align: left; |
| border-bottom: 1px solid #ddd; |
| } |
| th { |
| background-color: #f2f2f2; |
| } |
| .action-btn { |
| background: #e74c3c; |
| margin-right: 5px; |
| } |
| .action-btn:hover { |
| background: #c0392b; |
| } |
| .edit-btn { |
| background: #f39c12; |
| margin-right: 5px; |
| } |
| .edit-btn:hover { |
| background: #d35400; |
| } |
| .info { |
| background-color: #d4edda; |
| color: #155724; |
| padding: 10px; |
| border-radius: 4px; |
| margin-bottom: 15px; |
| } |
| .error { |
| background-color: #f8d7da; |
| color: #721c24; |
| padding: 10px; |
| border-radius: 4px; |
| margin-bottom: 15px; |
| } |
| .modal { |
| display: none; |
| position: fixed; |
| z-index: 1; |
| left: 0; |
| top: 0; |
| width: 100%; |
| height: 100%; |
| overflow: auto; |
| background-color: rgba(0,0,0,0.4); |
| } |
| .modal-content { |
| background-color: #fefefe; |
| margin: 15% auto; |
| padding: 20px; |
| border: 1px solid #888; |
| width: 80%; |
| max-width: 600px; |
| border-radius: 8px; |
| } |
| .close { |
| color: #aaa; |
| float: right; |
| font-size: 28px; |
| font-weight: bold; |
| cursor: pointer; |
| } |
| .close:hover, |
| .close:focus { |
| color: black; |
| text-decoration: none; |
| } |
| |
| .cookie-text { |
| max-width: 80%; |
| word-break: break-all; |
| } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <div class="card"> |
| <h1>Cursor To OpenAI - API Key 管理</h1> |
| <p>在此页面上,您可以管理自定义 API Key 与 Cursor Cookie 的映射关系。</p> |
| <div style="margin-top: 10px; display: flex; justify-content: space-between; align-items: center;"> |
| <div> |
| <button id="testApiBtn" style="margin-right: 10px;">测试API连接</button> |
| <button id="clearCacheBtn">清除缓存并刷新</button> |
| </div> |
| <div> |
| <span id="adminUsername" style="margin-right: 10px;"></span> |
| <button id="logoutBtn" style="background: #e74c3c;">退出登录</button> |
| </div> |
| </div> |
| <div id="testApiResult" style="margin-top: 10px;"></div> |
| </div> |
|
|
| <div class="card"> |
| <h2>添加/更新 API Key</h2> |
| <div id="addKeyMessage"></div> |
| <form id="addKeyForm"> |
| <div class="form-group"> |
| <label for="apiKey">API Key(自定义)</label> |
| <input type="text" id="apiKey" name="apiKey" placeholder="输入您想使用的自定义 API Key" required> |
| </div> |
| <div class="form-group"> |
| <label for="cookieValues">Cursor Cookie 值(多个值请用逗号分隔)</label> |
| <textarea id="cookieValues" name="cookieValues" placeholder="输入 WorkosCursorSessionToken 值,多个值请用逗号分隔" required></textarea> |
| </div> |
| <button type="submit">保存</button> |
| </form> |
| </div> |
|
|
| <div class="card"> |
| <h2>现有 API Key</h2> |
| <div id="keyListMessage"></div> |
| <table id="keyTable"> |
| <thead> |
| <tr> |
| <th>API Key</th> |
| <th>Cookie 数量</th> |
| <th>操作</th> |
| </tr> |
| </thead> |
| <tbody id="keyList"> |
| |
| </tbody> |
| </table> |
| </div> |
|
|
| <div class="card"> |
| <h2>使用说明</h2> |
| <ol> |
| <li>添加自定义 API Key 和对应的 Cursor Cookie 值。</li> |
| <li>使用自定义 API Key 作为 OpenAI API 的认证凭证。</li> |
| <li>系统将自动在多个 Cookie 之间进行轮询。</li> |
| <li>API 端点: |
| <ul> |
| <li>模型列表:<code>/v1/models</code></li> |
| <li>聊天补全:<code>/v1/chat/completions</code></li> |
| </ul> |
| </li> |
| </ol> |
| </div> |
| </div> |
|
|
| |
| <div id="editModal" class="modal"> |
| <div class="modal-content"> |
| <span class="close">×</span> |
| <h2>修改 API Key 的 Cookie</h2> |
| <div id="editModalMessage"></div> |
| <form id="editCookieForm"> |
| <input type="hidden" id="editApiKey" name="editApiKey"> |
| <div class="form-group"> |
| <label for="editCookieValues">Cursor Cookie 值(多个值请用逗号分隔)</label> |
| <textarea id="editCookieValues" name="editCookieValues" placeholder="输入 WorkosCursorSessionToken 值,多个值请用逗号分隔" required></textarea> |
| </div> |
| <button type="submit">保存修改</button> |
| </form> |
| </div> |
| </div> |
|
|
| <div class="card"> |
| <h2>无效Cookie管理</h2> |
| <div class="form-group"> |
| <div class="info"> |
| 以下是系统自动检测到的无效Cookie列表。这些Cookie在请求过程中被发现无效,已被自动从API Key中移除。 |
| </div> |
| <div id="invalidCookiesContainer"> |
| <div style="text-align: center; padding: 20px;"> |
| <div>加载中...</div> |
| </div> |
| </div> |
| <button id="clearAllInvalidCookies" style="background: #e74c3c;">清除所有无效Cookie</button> |
| </div> |
| </div> |
|
|
| |
| <div class="card"> |
| <h2>Cookie自动刷新</h2> |
| <div class="form-group"> |
| <div class="info"> |
| 系统支持自动刷新Cookie,确保API Key始终有足够的可用Cookie。您可以在此手动触发刷新操作。 |
| </div> |
| <div id="refreshCookieMessage"></div> |
| <div style="margin-top: 15px;"> |
| <div class="form-group"> |
| <label for="refreshApiKey">选择要刷新的API Key(不选则刷新所有)</label> |
| <select id="refreshApiKey" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px;"> |
| <option value="">所有API Key</option> |
| |
| </select> |
| </div> |
| <button id="refreshCookieBtn" style="background: #27ae60;">刷新Cookie</button> |
| </div> |
| <div id="refreshStatusContainer" style="margin-top: 15px; display: none;"> |
| <div class="info"> |
| <div>刷新状态:<span id="refreshStatus">准备中...</span></div> |
| <div style="margin-top: 10px;"> |
| <progress id="refreshProgress" value="0" max="100" style="width: 100%;"></progress> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| const modal = document.getElementById('editModal'); |
| const closeBtn = document.getElementsByClassName('close')[0]; |
| |
| |
| closeBtn.onclick = function() { |
| modal.style.display = 'none'; |
| } |
| |
| |
| window.onclick = function(event) { |
| if (event.target == modal) { |
| modal.style.display = 'none'; |
| } |
| } |
| |
| |
| async function loadApiKeys() { |
| try { |
| console.log('开始加载API Keys...'); |
| const response = await fetch('/v1/api-keys', { |
| method: 'GET', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| if (!response.ok) { |
| throw new Error(`HTTP错误: ${response.status} ${response.statusText}`); |
| } |
| |
| console.log('API响应状态:', response.status); |
| const data = await response.json(); |
| console.log('获取到的数据:', data); |
| |
| const keyList = document.getElementById('keyList'); |
| keyList.innerHTML = ''; |
| |
| if (data.success && data.apiKeys.length > 0) { |
| data.apiKeys.forEach(key => { |
| const row = document.createElement('tr'); |
| row.innerHTML = ` |
| <td>${key.key}</td> |
| <td>${key.cookieCount}</td> |
| <td> |
| <button class="edit-btn" onclick="editApiKey('${key.key}')">修改</button> |
| <button class="action-btn" onclick="deleteApiKey('${key.key}')">删除</button> |
| </td> |
| `; |
| keyList.appendChild(row); |
| }); |
| } else { |
| keyList.innerHTML = '<tr><td colspan="3">暂无 API Key</td></tr>'; |
| } |
| } catch (error) { |
| console.error('加载 API Key 失败:', error); |
| document.getElementById('keyListMessage').innerHTML = ` |
| <div class="error">加载 API Key 失败: ${error.message}</div> |
| `; |
| } |
| } |
| |
| |
| document.getElementById('addKeyForm').addEventListener('submit', async function(e) { |
| e.preventDefault(); |
| |
| const apiKey = document.getElementById('apiKey').value.trim(); |
| const cookieValuesText = document.getElementById('cookieValues').value.trim(); |
| |
| if (!apiKey || !cookieValuesText) { |
| document.getElementById('addKeyMessage').innerHTML = ` |
| <div class="error">API Key 和 Cookie 值不能为空</div> |
| `; |
| return; |
| } |
| |
| |
| const cookieValues = cookieValuesText.split(',').map(cookie => cookie.trim()).filter(cookie => cookie); |
| |
| try { |
| const response = await fetch('/v1/api-keys', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| }, |
| body: JSON.stringify({ |
| apiKey, |
| cookieValues, |
| }), |
| }); |
| |
| const data = await response.json(); |
| |
| if (data.success) { |
| document.getElementById('addKeyMessage').innerHTML = ` |
| <div class="info">API Key 添加/更新成功</div> |
| `; |
| document.getElementById('apiKey').value = ''; |
| document.getElementById('cookieValues').value = ''; |
| loadApiKeys(); |
| } else { |
| document.getElementById('addKeyMessage').innerHTML = ` |
| <div class="error">API Key 添加/更新失败: ${data.error}</div> |
| `; |
| } |
| } catch (error) { |
| console.error('添加/更新 API Key 失败:', error); |
| document.getElementById('addKeyMessage').innerHTML = ` |
| <div class="error">添加/更新 API Key 失败: ${error.message}</div> |
| `; |
| } |
| }); |
| |
| |
| async function deleteApiKey(apiKey) { |
| if (!confirm(`确定要删除 API Key "${apiKey}" 吗?`)) { |
| return; |
| } |
| |
| try { |
| const response = await fetch(`/v1/api-keys/${encodeURIComponent(apiKey)}`, { |
| method: 'DELETE', |
| }); |
| |
| const data = await response.json(); |
| |
| if (data.success) { |
| document.getElementById('keyListMessage').innerHTML = ` |
| <div class="info">API Key 删除成功</div> |
| `; |
| loadApiKeys(); |
| } else { |
| document.getElementById('keyListMessage').innerHTML = ` |
| <div class="error">API Key 删除失败: ${data.error}</div> |
| `; |
| } |
| } catch (error) { |
| console.error('删除 API Key 失败:', error); |
| document.getElementById('keyListMessage').innerHTML = ` |
| <div class="error">删除 API Key 失败: ${error.message}</div> |
| `; |
| } |
| } |
| |
| |
| async function getCookiesForApiKey(apiKey) { |
| try { |
| const response = await fetch(`/v1/api-keys/${encodeURIComponent(apiKey)}/cookies`, { |
| method: 'GET', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| if (!response.ok) { |
| throw new Error(`HTTP错误: ${response.status} ${response.statusText}`); |
| } |
| |
| const data = await response.json(); |
| return data.cookies; |
| } catch (error) { |
| console.error(`获取 ${apiKey} 的Cookie值失败:`, error); |
| throw error; |
| } |
| } |
| |
| |
| async function editApiKey(apiKey) { |
| try { |
| document.getElementById('editModalMessage').innerHTML = ''; |
| document.getElementById('editApiKey').value = apiKey; |
| |
| |
| const cookies = await getCookiesForApiKey(apiKey); |
| document.getElementById('editCookieValues').value = cookies.join(','); |
| |
| |
| modal.style.display = 'block'; |
| } catch (error) { |
| alert(`获取 ${apiKey} 的Cookie值失败: ${error.message}`); |
| } |
| } |
| |
| |
| document.getElementById('editCookieForm').addEventListener('submit', async function(e) { |
| e.preventDefault(); |
| |
| const apiKey = document.getElementById('editApiKey').value.trim(); |
| const cookieValuesText = document.getElementById('editCookieValues').value.trim(); |
| |
| if (!apiKey || !cookieValuesText) { |
| document.getElementById('editModalMessage').innerHTML = ` |
| <div class="error">API Key 和 Cookie 值不能为空</div> |
| `; |
| return; |
| } |
| |
| |
| const cookieValues = cookieValuesText.split(',').map(cookie => cookie.trim()).filter(cookie => cookie); |
| |
| try { |
| const response = await fetch('/v1/api-keys', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| }, |
| body: JSON.stringify({ |
| apiKey, |
| cookieValues, |
| }), |
| }); |
| |
| const data = await response.json(); |
| |
| if (data.success) { |
| document.getElementById('editModalMessage').innerHTML = ` |
| <div class="info">Cookie 修改成功</div> |
| `; |
| setTimeout(() => { |
| modal.style.display = 'none'; |
| loadApiKeys(); |
| }, 1500); |
| } else { |
| document.getElementById('editModalMessage').innerHTML = ` |
| <div class="error">Cookie 修改失败: ${data.error}</div> |
| `; |
| } |
| } catch (error) { |
| console.error('修改 Cookie 失败:', error); |
| document.getElementById('editModalMessage').innerHTML = ` |
| <div class="error">修改 Cookie 失败: ${error.message}</div> |
| `; |
| } |
| }); |
| |
| |
| document.getElementById('testApiBtn').addEventListener('click', async function() { |
| const resultDiv = document.getElementById('testApiResult'); |
| resultDiv.innerHTML = '<div class="info">正在测试API连接...</div>'; |
| |
| try { |
| const response = await fetch('/v1/api-keys', { |
| method: 'GET', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| resultDiv.innerHTML = `<div class="info">API响应状态: ${response.status}</div>`; |
| |
| if (!response.ok) { |
| throw new Error(`HTTP错误: ${response.status} ${response.statusText}`); |
| } |
| |
| const data = await response.json(); |
| resultDiv.innerHTML += `<div class="info">获取到的数据: ${JSON.stringify(data)}</div>`; |
| } catch (error) { |
| console.error('测试API失败:', error); |
| resultDiv.innerHTML = `<div class="error">测试API失败: ${error.message}</div>`; |
| } |
| }); |
| |
| |
| document.getElementById('clearCacheBtn').addEventListener('click', function() { |
| |
| if ('caches' in window) { |
| caches.keys().then(function(names) { |
| for (let name of names) { |
| caches.delete(name); |
| } |
| }); |
| } |
| |
| |
| window.location.reload(true); |
| }); |
| |
| |
| async function getInvalidCookies() { |
| try { |
| const response = await fetch('/v1/invalid-cookies', { |
| method: 'GET', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| if (!response.ok) { |
| throw new Error(`HTTP错误: ${response.status} ${response.statusText}`); |
| } |
| |
| const data = await response.json(); |
| return data.invalidCookies; |
| } catch (error) { |
| console.error('获取无效Cookie失败:', error); |
| throw error; |
| } |
| } |
| |
| |
| async function clearInvalidCookie(cookie) { |
| try { |
| const response = await fetch(`/v1/invalid-cookies/${encodeURIComponent(cookie)}`, { |
| method: 'DELETE', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| if (!response.ok) { |
| throw new Error(`HTTP错误: ${response.status} ${response.statusText}`); |
| } |
| |
| const data = await response.json(); |
| return data.success; |
| } catch (error) { |
| console.error(`清除无效Cookie失败:`, error); |
| throw error; |
| } |
| } |
| |
| |
| async function clearAllInvalidCookies() { |
| try { |
| const response = await fetch('/v1/invalid-cookies', { |
| method: 'DELETE', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| if (!response.ok) { |
| throw new Error(`HTTP错误: ${response.status} ${response.statusText}`); |
| } |
| |
| const data = await response.json(); |
| return data.success; |
| } catch (error) { |
| console.error('清除所有无效Cookie失败:', error); |
| throw error; |
| } |
| } |
| |
| |
| async function renderInvalidCookies() { |
| const container = document.getElementById('invalidCookiesContainer'); |
| |
| try { |
| const invalidCookies = await getInvalidCookies(); |
| |
| if (invalidCookies.length === 0) { |
| container.innerHTML = '<div class="info">没有检测到无效Cookie</div>'; |
| return; |
| } |
| |
| let html = '<table><thead><tr><th>无效Cookie</th><th>操作</th></tr></thead><tbody>'; |
| |
| invalidCookies.forEach(cookie => { |
| |
| const displayCookie = cookie.length > 50 ? cookie.substring(0, 50) + '...' : cookie; |
| |
| html += ` |
| <tr> |
| <td class="cookie-text" title="${cookie}">${displayCookie}</td> |
| <td> |
| <button class="action-btn clear-invalid-cookie" data-cookie="${cookie}"> |
| 清除 |
| </button> |
| </td> |
| </tr> |
| `; |
| }); |
| |
| html += '</tbody></table>'; |
| container.innerHTML = html; |
| |
| |
| document.querySelectorAll('.clear-invalid-cookie').forEach(button => { |
| button.addEventListener('click', async function() { |
| const cookie = this.getAttribute('data-cookie'); |
| |
| try { |
| await clearInvalidCookie(cookie); |
| showMessage('invalidCookiesContainer', '无效Cookie已清除', 'info'); |
| renderInvalidCookies(); |
| } catch (error) { |
| showMessage('invalidCookiesContainer', `清除失败: ${error.message}`, 'error'); |
| } |
| }); |
| }); |
| |
| } catch (error) { |
| container.innerHTML = `<div class="error">加载失败: ${error.message}</div>`; |
| } |
| } |
| |
| |
| document.getElementById('clearAllInvalidCookies').addEventListener('click', async function() { |
| try { |
| await clearAllInvalidCookies(); |
| showMessage('invalidCookiesContainer', '所有无效Cookie已清除', 'info'); |
| renderInvalidCookies(); |
| } catch (error) { |
| showMessage('invalidCookiesContainer', `清除失败: ${error.message}`, 'error'); |
| } |
| }); |
| |
| |
| document.addEventListener('DOMContentLoaded', function() { |
| checkAuth(); |
| loadApiKeys(); |
| renderInvalidCookies(); |
| populateRefreshApiKeySelect(); |
| }); |
| |
| |
| function showMessage(containerId, message, type) { |
| const container = document.getElementById(containerId); |
| container.innerHTML = `<div class="${type}">${message}</div>`; |
| } |
| |
| |
| async function populateRefreshApiKeySelect() { |
| try { |
| const apiKeys = await getApiKeys(); |
| const select = document.getElementById('refreshApiKey'); |
| |
| |
| while (select.options.length > 1) { |
| select.remove(1); |
| } |
| |
| |
| apiKeys.forEach(key => { |
| const option = document.createElement('option'); |
| option.value = key.key; |
| option.textContent = `${key.key} (${key.cookieCount} 个Cookie)`; |
| select.appendChild(option); |
| }); |
| } catch (error) { |
| console.error('加载API Key选项失败:', error); |
| } |
| } |
| |
| |
| async function getApiKeys() { |
| const response = await fetch('/v1/api-keys', { |
| method: 'GET', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| if (!response.ok) { |
| throw new Error(`HTTP错误: ${response.status} ${response.statusText}`); |
| } |
| |
| const data = await response.json(); |
| return data.success ? data.apiKeys : []; |
| } |
| |
| |
| document.getElementById('refreshCookieBtn').addEventListener('click', async function() { |
| const refreshBtn = this; |
| const apiKey = document.getElementById('refreshApiKey').value; |
| const statusContainer = document.getElementById('refreshStatusContainer'); |
| const statusText = document.getElementById('refreshStatus'); |
| const progressBar = document.getElementById('refreshProgress'); |
| |
| |
| refreshBtn.disabled = true; |
| statusContainer.style.display = 'block'; |
| statusText.textContent = '正在发送刷新请求...'; |
| progressBar.value = 10; |
| |
| try { |
| |
| let url = '/v1/refresh-cookies'; |
| if (apiKey) { |
| url += `?apiKey=${encodeURIComponent(apiKey)}`; |
| } |
| |
| |
| statusText.textContent = '正在发送刷新请求...'; |
| progressBar.value = 20; |
| |
| const response = await fetch(url, { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| if (!response.ok) { |
| throw new Error(`HTTP错误: ${response.status} ${response.statusText}`); |
| } |
| |
| |
| statusText.textContent = '刷新请求已发送,请耐心等待2-12分钟...'; |
| progressBar.value = 50; |
| showMessage('refreshCookieMessage', '刷新请求已发送,由于需要访问Cursor官网获取新Cookie,整个过程可能需要2-12分钟,请耐心等待。您可以关闭此页面,稍后再来查看结果。', 'info'); |
| |
| |
| let checkInterval = setInterval(async () => { |
| try { |
| const statusResponse = await fetch('/v1/refresh-status', { |
| method: 'GET', |
| headers: { |
| 'Cache-Control': 'no-cache' |
| } |
| }); |
| |
| if (!statusResponse.ok) { |
| throw new Error(`HTTP错误: ${statusResponse.status} ${statusResponse.statusText}`); |
| } |
| |
| const statusData = await statusResponse.json(); |
| const refreshData = statusData.data; |
| |
| |
| statusText.textContent = refreshData.message || '正在刷新...'; |
| |
| |
| if (refreshData.status === 'completed') { |
| |
| progressBar.value = 100; |
| statusText.textContent = `刷新完成: ${refreshData.message}`; |
| clearInterval(checkInterval); |
| |
| |
| await loadApiKeys(); |
| await populateRefreshApiKeySelect(); |
| |
| |
| showMessage('refreshCookieMessage', `刷新完成: ${refreshData.message}`, 'success'); |
| |
| |
| refreshBtn.disabled = false; |
| |
| |
| setTimeout(() => { |
| statusContainer.style.display = 'none'; |
| }, 3000); |
| } else if (refreshData.status === 'failed') { |
| |
| progressBar.value = 0; |
| statusText.textContent = `刷新失败: ${refreshData.message}`; |
| clearInterval(checkInterval); |
| |
| |
| showMessage('refreshCookieMessage', `刷新失败: ${refreshData.message}`, 'error'); |
| |
| |
| refreshBtn.disabled = false; |
| } else if (refreshData.status === 'running') { |
| |
| progressBar.value = 75; |
| } else if (!refreshData.isRunning) { |
| |
| clearInterval(checkInterval); |
| refreshBtn.disabled = false; |
| } |
| } catch (error) { |
| console.error('检查刷新状态失败:', error); |
| } |
| }, 5000); |
| |
| |
| setTimeout(() => { |
| if (checkInterval) { |
| clearInterval(checkInterval); |
| refreshBtn.disabled = false; |
| statusContainer.style.display = 'none'; |
| } |
| }, 720000); |
| } catch (error) { |
| console.error('刷新Cookie失败:', error); |
| statusText.textContent = '刷新请求发送失败'; |
| progressBar.value = 0; |
| showMessage('refreshCookieMessage', `刷新请求发送失败: ${error.message}`, 'error'); |
| refreshBtn.disabled = false; |
| } |
| }); |
| |
| |
| function checkAuth() { |
| const token = localStorage.getItem('adminToken'); |
| if (!token) { |
| window.location.href = '/login.html'; |
| return; |
| } |
| |
| |
| fetch('/v1/admin/verify', { |
| headers: { |
| 'Authorization': `Bearer ${token}` |
| } |
| }) |
| .then(response => response.json()) |
| .then(data => { |
| if (!data.success) { |
| localStorage.removeItem('adminToken'); |
| window.location.href = '/login.html'; |
| } else { |
| |
| document.getElementById('adminUsername').textContent = `管理员:${data.username}`; |
| } |
| }) |
| .catch(error => { |
| console.error('验证失败:', error); |
| localStorage.removeItem('adminToken'); |
| window.location.href = '/login.html'; |
| }); |
| } |
| |
| |
| document.getElementById('logoutBtn').addEventListener('click', () => { |
| localStorage.removeItem('adminToken'); |
| window.location.href = '/login.html'; |
| }); |
| |
| |
| function addAuthHeader(headers = {}) { |
| const token = localStorage.getItem('adminToken'); |
| return { |
| ...headers, |
| 'Authorization': `Bearer ${token}` |
| }; |
| } |
| |
| |
| const originalFetch = window.fetch; |
| window.fetch = function(url, options = {}) { |
| |
| if (url.includes('/v1/api-keys') || |
| url.includes('/v1/invalid-cookies') || |
| url.includes('/v1/refresh-cookies')) { |
| options.headers = addAuthHeader(options.headers); |
| } |
| return originalFetch(url, options); |
| }; |
| </script> |
| </body> |
| </html> |