chatGpt plus拼车神器UI版本 plus ----优雅再接力

本文基于

在@ tttt 的UI版本基础上做了一些自认为是优化的的优化
感谢两位大佬以及大佬文中提到的所有大佬的前期工作。让我得以方便的使用

我在@ tttt 的UI版本的基础上做了以下工作:

1.增加用户名用户白名单 ,参考@ Maple 本文的第二篇引用中的白名单内容

2.增加用户自定义密码的变量,用户名为变量key,用户名的密码为 变量value,使一起拼车的用户方便记住自己的密码(白名单用户第一次登录判定为密码正确,并存到变量表中后续验证取变量表中的密码进行验证)无需管理员手动加变量。

3.原UI版使用 https://yourdomain/auth/login_share?token=fk-xxx 的方式会暴露share_token,有一定风险。我对其进行了转OAuth的方式登陆,提高安全性,参考@ Maple 本文的第二篇引用中的转OAuth的方式登陆相关内容

4.对错误界面做了一定优化。@ tttt 的UI版本的UI版本中的错误页面就一行文字,观感相对不太友好。我对其做了一定优化。效果如下:

5.对密码输入界面的密码做了隐藏,免得旁边有人给你偷看去了 :grinning:,效果如下:

workers代码:

addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request))
})

function parseJwt(token) {
    const base64Url = token.split('.')[1]; // 获取载荷部分
    const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); // 将 Base64Url 转为 Base64
    const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));

    return JSON.parse(jsonPayload); // 返回载荷解析后的 JSON 对象
}

function isTokenExpired(token) {
    const payload = parseJwt(token);
    const currentTime = Math.floor(Date.now() / 1000); // 获取当前时间戳(秒)
    return payload.exp < currentTime; // 检查 token 是否过期
}


async function handleRequest(request) {
    const requestURL = new URL(request.url);

    // ------------ 反代到 new.oaifree.com
    const path = requestURL.pathname;
    if (path !== '/auth/login_auth0' && path !== '/auth/login') {
        requestURL.host = 'new.oaifree.com';
        return fetch(new Request(requestURL, request))
    }

    // ------------ 进行拿share_token去登录
    const token = await oai_global_variables.get('at'); // 这里填入你的 JWT
    if (isTokenExpired(token)) {
        // 如果 Token 过期,执行获取新 Token 的逻辑
        const url = 'https://token.oaifree.com/api/auth/refresh';
        // @ts-ignore
        const refreshToken = await oai_global_variables.get('rt');  // 实际情况下你可能会从某处获取这个值
        // 发送 POST 请求
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
            },
            body: `refresh_token=${refreshToken}`
        });
        // 检查响应状态
        if (response.ok) {
            const data = await response.json();
            const token = data.access_token;
            // @ts-ignore
            await oai_global_variables.put('at', token);
        } else {
            return getErrorResponse( response.status)
        }
    }
    // 如果 Token 未过期,继续执行原来的逻辑
    if (request.method === "POST") {
        const formData = await request.formData();
        // @ts-ignore
        const access_token = await oai_global_variables.get('at')
        const unique_name = formData.get('unique_name');
        const site_limit = '';
        const expires_in = '0';
        const gpt35_limit = '-1';
        const gpt4_limit = '-1';
        const show_conversations = 'false';
        const show_userinfo = 'false';// 是否显示用户信息
        const reset_limit = 'false';
        // @ts-ignore
        // 验证用户名是否存在
        const users = await oai_global_variables.get("users");

        if (!users.split(",").includes(unique_name)) {
            return getErrorResponse(401);
        }
        const site_password = formData.get('site_password') || '';
        const userPassword = await oai_global_variables.get(unique_name);
        const userPasswordIsNull =userPassword === undefined || userPassword === null || userPassword === ''
        if (userPasswordIsNull) {
            // 首次登录,认定密码正确,并将密码存储
            await oai_global_variables.put(unique_name, site_password);
        }

        // 变量中有密码且不对则拒绝访问
        if (!userPasswordIsNull&&site_password !== userPassword) {
            return getErrorResponse(401);
        }
        const url = 'https://chat.oaifree.com/token/register';
        const body = new URLSearchParams({
            unique_name,
            access_token, // 使用来自表单v或KV变量的 access_token
            site_limit,
            expires_in,
            gpt35_limit,
            gpt4_limit,
            show_conversations,
            show_userinfo,
            reset_limit
        }).toString();

        const apiResponse = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: body
        });

        const respJson = await apiResponse.json();
        const tokenKey = 'token_key' in respJson ? respJson.token_key : '未找到 Share_token';

        // @ts-ignore
        const DOMAIN = await oai_global_variables.get('DOMAIN') || requestURL.host;
        // 重定向到登录 URL
        return Response.redirect(await getOAuthLink(tokenKey, DOMAIN), 301);
    }
    return getLoginPage();
}

// 获取错误页面的函数
function getErrorResponse(statusCode) {
    const errorMessageMap = {
        401: '访问被拒绝,请检查您的凭据。',
        404: '请求的资源未找到。',
        500: '服务器内部错误,请稍后再试。'
    };

    const message = errorMessageMap[statusCode] || '发生未知错误。';
    const html = `
<!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>
    body {
      font-family: Arial, sans-serif;
      background-color: #f4f4f4;
      padding: 20px;
      text-align: center;
    }
    .error-container {
      background: white;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 5px rgba(0,0,0,0.1);
      max-width: 600px;
      margin: 50px auto;
    }
    h1 {
      color: #333;
    }
    p {
      color: #666;
    }
  </style>
</head>
<body>
  <div class="error-container">
    <h1>错误</h1>
    <p>${message}</p>
  </div>
</body>
</html>
`;
    return new Response(html, {
        headers: {
            'Content-Type': 'text/html; charset=utf-8'
        },
        status: statusCode
    });
}

//获取登录页面的函数
function getLoginPage() {
    const formHtml = `
  <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
  padding: 20px;
}
form, .response-container {
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
  max-width: 600px;
  margin: 20px auto;
}
h1 {
  text-align: center; 
}
h2 {
  text-align: center; 
}
p {
  display: block;
  margin-bottom: 10px;
  font-size: 16px;
}
input[type="text"], textarea {
  width: calc(100% - 22px);
  padding: 10px;
  margin-top: 5px;
  margin-bottom: 20px;
  border-radius: 5px;
  border: 1px solid #ccc;
}
input[type="password"], textarea {
  width: calc(100% - 22px);
  padding: 10px;
  margin-top: 5px;
  margin-bottom: 20px;
  border-radius: 5px;
  border: 1px solid #ccc;
}
textarea {
  font-family: 'Courier New', monospace;
  background-color: #f8f8f8;
  height: 150px; /* Adjust height based on your needs */
}
button {
  background-color: #000000;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 16px;
  font-weight:600;
  width:100% !important
}
button:hover {
  background-color: #1e293b;
}
@media (max-width: 768px) {
  body, form, .response-container {
    padding: 10px;
  }
}
.checkbox-group {
  display: flex;
  justify-content: space-between;
}
.checkbox-group input[type="checkbox"] {
  margin-right: 5px;
}
.checkbox-group label {
  margin-right: 10px;
}
</style>
</head>
<body>
<h1>欢迎使用</h1>
<form method="POST">
<label for="unique_name">请输入你的用户名:</label>
<input type="text" id="unique_name" name="unique_name" placeholder="" required value="">
<label for="unique_name">请输入你的密码:</label>
<input type="password" id="site_password" name="site_password" placeholder="">

<br></br>
<button type="submit">登录</button>
</form>
</body>
</html>
`;

    return new Response(formHtml, {
        headers: {
            'Content-Type': 'text/html; charset=utf-8'
        },
    });
}

// 获取 OAuth 登录链接的函数
async function getOAuthLink(tokenKey, DOMAIN) {
    const url = `https://new.oaifree.com/api/auth/oauth_token`;
    const response = await fetch(url, {
        method: 'POST',
        headers: {
            'Origin': `https://${DOMAIN}`,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            share_token: tokenKey
        })
    })
    const data = await response.json();
    return data.login_url;
}
22 个赞

玩的花啊 :smiley:

4 个赞

看上去很厉害的样子

1 个赞

接力好啊

1 个赞

优雅永不过时

1 个赞

都说优雅 然而 屎黄说 花

1 个赞

一个 worker 都给搞定了 6

1 个赞

优雅…太优雅了

1 个赞

报错
{“error”:“Error”,“message”:“Token and remote not found”}
而且,看代码好像密码是看变量unique_name。而不是作者提到的key和value?

1 个赞

kv里添加用户名,密码,对应key和value

2 个赞

看到了,多谢。看岔了。unique_name是变量名不是字符串。明天再试试

1 个赞

大佬,用户名和密码咋设置啊

不用自己设置了,看我最新worker 代码 以及第二条内容描述

不用自己设置用户名密码kv了,设置白名单就行。看我新的代码以及第二点的内容描述

1 个赞

感谢收藏了

哈哈哈

哈哈哈哈,各位大佬弄的东西挺好玩

挺花~

这个是我的kv设置,我用users中的一个登录提示:访问被拒绝,请检查您的凭据。

你的YOUR_DOMAIN改了吗,我代码里面用的DOMAIN