From 4b396c4f3a1f11a18ecf71528d873c38b4f1ad1d Mon Sep 17 00:00:00 2001 From: AiHaibara <166741903+jyx04@users.noreply.github.com> Date: Sat, 8 Jun 2024 15:23:24 +0800 Subject: [PATCH] Update _worker.js --- _worker.js | 648 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 487 insertions(+), 161 deletions(-) diff --git a/_worker.js b/_worker.js index baeaa99..fd5d544 100644 --- a/_worker.js +++ b/_worker.js @@ -55,6 +55,7 @@ async function usermatch(userName, usertype) { //各种路径的功能 async function handleRequest(request) { const url = new URL(request.url); + const voiceURL = await KV.get('VoiceURL'); const admin = await KV.get('Admin'); //处理直链登陆形式 const params = new URLSearchParams(url.search); @@ -64,8 +65,6 @@ async function handleRequest(request) { return await handleLogin(userName, accountNumber, 'do not need Turnstle',''); } - - if (!admin){ return handleInitialRequest(request); } @@ -90,6 +89,15 @@ async function handleRequest(request) { } } + if(url.pathname.startsWith('/export')){ + if (request.method === 'GET') { + return handleExportGetRequest(request); + } else if (request.method === 'POST') { + return handleExportPostRequest(request); + }else { + return new Response('Method not allowed', { status: 405 }); + } + } if (url.pathname.startsWith('/user')) { if (request.method === 'GET') { return handleUserGetRequest(); @@ -115,7 +123,9 @@ async function handleRequest(request) { if(url.pathname.startsWith('/usage')){ return handleUsageRequest(request) } - // Specific handling for /auth/login_auth0 + + + // for oaifree if (url.pathname === '/auth/login_auth0') { if (request.method === 'GET') { return handleLoginGetRequest(request); @@ -125,8 +135,11 @@ async function handleRequest(request) { return new Response('Method not allowed', { status: 200 }); } } + if (url.pathname === '/auth/login') { - /* const token = url.searchParams.get('token'); + /* + //如需退出登陆立即返回登陆页,取消注释此段 + const token = url.searchParams.get('token'); if (!token) { if (request.method === 'GET') { return handleLoginGetRequest(request); @@ -141,11 +154,15 @@ async function handleRequest(request) { return fetch(new Request(url, request)); } - // Forward other requests to new.oaifree.com + //Voice地址和其他 url.host = 'new.oaifree.com'; - const response = await fetch(new Request(url, request)); - - // Special case for /backend-api/conversations + const modifiedRequest = new Request(url, request); + if(voiceURL){ + modifiedRequest.headers.set('X-Voice-Base', `${voiceURL}`); + } + const response = await fetch(modifiedRequest); + + //去掉小锁 if (url.pathname === '/backend-api/conversations') { const data = await response.json(); data.items = data.items.filter(item => item.title !== "🔒"); @@ -154,9 +171,7 @@ async function handleRequest(request) { headers: response.headers }); } - - return response; - +return response } //初始化信息填入功能 @@ -180,7 +195,7 @@ async function handleInitialPostRequest(request) { const fields = [ 'TurnstileKeys', 'TurnstileSiteKey', 'Users', 'VIPUsers', 'FreeUsers', 'Admin', 'ForceAN', 'SetAN', 'PlusMode', 'FreeMode', 'WebName', - 'WorkerURL', 'LogoURL', 'CDKEY', 'AutoDeleteCDK', 'FKDomain', 'Status', + 'WorkerURL','VoiceURL', 'LogoURL', 'CDKEY', 'AutoDeleteCDK', 'FKDomain', 'Status', 'PlusAliveAccounts', 'FreeAliveAccounts', 'rt_1', 'rt_2', 'at_1', 'at_2' ]; @@ -189,9 +204,14 @@ async function handleInitialPostRequest(request) { if (field === 'WorkerURL' && !value) { value = (new URL(request.url)).hostname; } + if (field === 'VoiceURL' && !value) { + let hostname = (new URL(request.url)).hostname; + let parts = hostname.split('.'); + parts[0] = 'voice'; + value = parts.join('.'); + } if (value) { - // @ts-ignore - await oai_global_variables.put(field, value); + await KV.put(field, value); } } @@ -285,10 +305,11 @@ async function getInitialHTML() { function getInitialFieldsHTML() { const fields = [ - { name: 'Admin', label: '【必填】管理员 (用于管理面板的验证使用,且可看所有聊天记录)' }, - { name: 'TurnstileKeys', label: '【必填】Turnstile密钥' }, - { name: 'TurnstileSiteKey', label: '【必填】Turnstile站点密钥' }, - { name: 'WorkerURL', label: '站点域名 (无需https://【选填,不填则自动储存当前worker域名】' }, + { name: 'Admin', label: '【必填】管理员 (用于管理面板的验证使用,且可看所有聊天记录)' ,isrequired: 'required'}, + { name: 'TurnstileKeys', label: '【必填】Turnstile密钥' ,isrequired: 'required'}, + { name: 'TurnstileSiteKey', label: '【必填】Turnstile站点密钥' ,isrequired: 'required'}, + { name: 'WorkerURL', label: '站点域名 (无需https://【选填,不填则自动储存worker的域名】' }, + { name: 'VoiceURL', label: 'voice服务域名 (无需https://【选填,不填则自动储存worker的域名】' }, { name: 'WebName', label: '站点名称' }, { name: 'LogoURL', label: 'Logo图片地址 (需https://)' }, { name: 'Users', label: '默认用户 (以aaa,bbb,ccc形式填写)' }, @@ -310,7 +331,7 @@ function getInitialFieldsHTML() { return fields.map(field => ` - + `).join(''); } @@ -640,6 +661,216 @@ async function getPlusHTML() { } +//token export功能 +async function handleExportGetRequest(request) { + const url = new URL(request.url); + const adminUserName = url.searchParams.get('admin'); + const tokenType = url.searchParams.get('token'); + const accountType = url.searchParams.get('type'); + if (!adminUserName || !tokenType || !accountType) { + const html = await getExportHTML(); + return new Response(html, { headers: { 'Content-Type': 'text/html' } }); + } + const adminusers = await KV.get('Admin'); + if (adminusers.split(',').includes(adminUserName)) { + const validTokenTypes = ['rt', 'at']; + const validAccountTypes = ['Free', 'Plus']; + if (!validTokenTypes.includes(tokenType) || !validAccountTypes.includes(accountType)) { + return new Response('Invalid token or account type', { status: 400 }); + } + return await exportToken(tokenType, accountType); +} +else{return new Response('Unauthorized access', { status: 403 }); +} +} + +async function exportToken(tokenType, accountType) { + const accountTypeKey = `${accountType}AliveAccounts`; + + // 获取对应类型的账户列表 + let aliveAccount = await KV.get(accountTypeKey); + if (!aliveAccount) { + return new Response('No accounts found', { status: 404 }); + } + + let accountNumbers = aliveAccount.split(','); + + // 获取所有账户号码对应的令牌 + let tokens = []; + for (let accountNumber of accountNumbers) { + let tokenKey = `${tokenType}_${accountNumber}`; + let token = await KV.get(tokenKey); + if (token) { + tokens.push(token); + } + } + + // 创建txt文件 + let fileContent = tokens.join('\n'); + let fileName = `${tokenType}.txt`; + + // 创建文件响应 + return new Response(fileContent, { + headers: { + 'Content-Type': 'text/plain', + 'Content-Disposition': `attachment; filename=${fileName}` + } + }); +} +async function handleExportPostRequest(request) { + const formData = await request.formData(); + const adminPassword = formData.get('adminpassword'); + const tokenType = formData.get('token_type'); + const accountType = formData.get('account_type'); + const operationType = formData.get('operation_type'); + const turnstileResponse = formData.get('cf-turnstile-response'); + + // 验证 Turnstile 响应 + if (!turnstileResponse || !await verifyTurnstile(turnstileResponse)) { + return new Response('Turnstile verification failed', { status: 403 }); + } + + // 获取 adminusers 列表 + const adminusers = await KV.get('Admin'); + if (!adminusers) { + return new Response('Admin list is empty', { status: 500 }); + } + + // 检查管理员密码是否正确 + if (adminusers.split(',').includes(adminPassword)) { + + if (operationType=='txt'){ + // 验证 tokenType 和 accountType 是否有效 + const validTokenTypes = ['rt', 'at']; + const validAccountTypes = ['Free', 'Plus']; + if (!validTokenTypes.includes(tokenType) || !validAccountTypes.includes(accountType)) { + return new Response('Invalid token or account type', { status: 400 }); + } + + // 调用 exportToken 函数并返回结果 + return await exportToken(tokenType, accountType);} + else{ + const WorkerURL=await KV.get('WorkerURL'); + return new Response(`https://${WorkerURL}/export?admin=${adminPassword}&type=${accountType}&token=${tokenType}`, { status: 200 }); + } +} + +else {return new Response('Unauthorized access', { status: 403 }); +} +} + + +async function getExportHTML() { + const turnstileSiteKey = await KV.get('TurnstileSiteKey'); + return ` + + + + + Export Tokens + + + +
+

Export Tokens

+
+ + + + + + + + + +
+ +
+
+ + + + + `; +} + + + //admin页面 @@ -773,11 +1004,11 @@ async function getAdminHTML() { .login-container button:hover { background-color: #005fcb; } - .management-buttons, .usage-return-buttons { + .tokenmanagement-buttons, .usagemanagement-buttons { display: flex; justify-content: space-between; } - .management-buttons a, .usage-link, .return-button { + .tokenmanagement-buttons a, .usage-link, .return-button { display: block; padding: 12px; border: 1px solid #ddd; @@ -792,7 +1023,7 @@ async function getAdminHTML() { transition: background-color 0.3s; margin-top: 10px; } - .management-buttons a:hover, .usage-link:hover, .return-button:hover { + .tokenmanagement-buttons a:hover, .usage-link:hover, .return-button:hover { background-color: #005fcb; } .ulp-field.ulp-error .ulp-error-info { @@ -828,13 +1059,13 @@ async function getAdminHTML() { -
+
Token Management - User Management + Export Tokens
-
+
@@ -1678,6 +1909,22 @@ async function getRegisterHTML() { margin-right: 4px; } + .footer { + text-align: center; + font-size: 12px; + padding: 10px; + } + + .footer a { + color: black; + text-decoration: none; + } + + .footer a:hover { + text-decoration: none; + color: black; + } + @@ -1735,6 +1982,9 @@ async function getRegisterHTML() {
+ - - `; + row.addEventListener('mouseout', function() { + if (isMasked) { + this.querySelector('.user-name').classList.add('masked'); + } + }); + }); + + + + + `; } function combineData(usersData, historyData) { @@ -2220,6 +2491,41 @@ async function getHistoryData(queryType) { } +function combineData(usersData, historyData) { + let combinedData = []; + let allUsers = new Set(usersData.map(u => u.user).concat(historyData.flatMap(h => h.usersData.map(u => u.user)))); + + allUsers.forEach(user => { + let historyUsage = historyData.map(h => { + let userUsage = h.usersData.find(u => u.user === user); + return userUsage ? { gpt4: userUsage.gpt4, gpt35: userUsage.gpt35 } : { gpt4: '', gpt35: '' }; + }); + let realTimeUsage = usersData.find(u => u.user === user); + combinedData.push({ + user, + historyUsage, + realTimeUsage: realTimeUsage ? { gpt4: realTimeUsage.gpt4, gpt35: realTimeUsage.gpt35 } : { gpt4: '', gpt35: '' } + }); + }); + + return combinedData; +} + +function generateHeaderRow(historyData) { + return historyData.map(h => `GPT-4GPT-3.5`).join(''); +} + +function generateTimestampRow(historyData) { + return historyData.map(h => `${h.timestamp}`).join(''); +} + +async function getHistoryData(queryType) { + const logType = queryType === 'plus' ? 'PlusUsageLogs' : 'FreeUsageLogs'; + const historyLogs = await KV.get(logType); + return historyLogs ? JSON.parse(historyLogs) : []; +} + + @@ -2460,7 +2766,7 @@ accountNumber = await getAccountNumber(fullUserName,initialaccountNumber, antype if (isTokenExpired(accessToken)) { // 给没有refresh token的萌新用(比如我),取消下面这行注释即可享用 - // return generateLoginResponse('The current access token has not been updated, please contact Joe to update it.', false); + // return generateLoginResponse('The current access token has not been updated.', false); // 如果 Token 过期,执行获取新 Token 的逻辑 const url = 'https://token.oaifree.com/api/auth/refresh'; @@ -2488,7 +2794,7 @@ accountNumber = await getAccountNumber(fullUserName,initialaccountNumber, antype } } else { - return generateLoginResponse('The current access token has not been updated, please contact Joe to update it.'); + return generateLoginResponse('The current access token has not been updated.'); } } const finalaccessToken = await KV.get(accessTokenKey); @@ -3085,6 +3391,22 @@ async function getLoginHTML(setan) { content: "🚫"; margin-right: 0px; } + .footer { + text-align: center; + font-size: 12px; + padding: 10px; + } + + .footer a { + color: black; + text-decoration: none; + } + + .footer a:hover { + text-decoration: none; + color: black; + } + @@ -3149,6 +3471,10 @@ async function getLoginHTML(setan) { + +