yeahow
(小叶)
1
明天就三级了,终于可以拿到refresh token了!!!
平时用chatgpt都是用的始皇 new.oaifree.com
,跟官网功能几乎一样可以免梯子,用得很舒服,唯一一个痛点就是在 token.oaifree.com/auth
生成的 access token 十天就会过期,那么也就是说每十天就要手动点几下,完成 在 token.oaifree.com
获取 access token → 复制 → 回到 new.oaifree.com
粘贴填入 → 点击OK 这几步。
通过奥特曼这个帖子 手把手教你用refresh roken获取access token 知道了 refresh token 可以刷新出一个access token,只需发送一个post请求(带上refresh token)即可。
那是不是可以写一个油猴脚本来自动化以上流程?即当访问 new.oaifree.com
时,如果没有登录的话,会重定向到 https://new.oaifree.com/auth/login_auth0
,这时候脚本就可以通过 refresh token(提前填好rk)发送post请求获取到 access token ,然后模拟鼠标点击 continue with access token
,并填入 刚刚获取到的at,最后模拟鼠标点击 OK,完成登录。这样,只要有了refresh token,就不需要自己用鼠标操作,一直保持登录状态。
论坛里搜了一下,没有找到类似的脚本,只找到一个 可以手动通过rt获取at的html (【优雅】Refresh token to Access token )。我没有写过油猴脚本,想问一下大佬们,理论上是可以实现的对吧?要是可以的话我打算借助chatgpt看能不能自己实现一下。
另外,感觉模拟鼠标点击的操作是不是太低级了,是不是可以直接对底层的数据进行操作?未登录状态到登录状态传递了什么参数,参数里肯定是有access token的,那脚本应该也可以实现填入这个参数并发送get请求?
二更:
在chatgpt的帮助下写了一个(第一次写脚本可能写得很烂),在14楼,不过还没测试,明天拿到rt了来试一下。
9 个赞
很容易实现,通过如下的接口可以实现refreshtoken–>Accesstoken
const response = await fetch('https://token.oaifree.com/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
body: `refresh_token=${encodeURIComponent(refreshToken)}`
});
mark一下,期待你能写出来。
3 个赞
yeahow
(小叶)
6
嗯嗯,刚刚搜了一下也看到大佬的这个啦,不过我主要是想要一个能自动填入并登录的功能![:joy: :joy:](https://cdn.linux.do/images/emoji/apple/joy.png?v=12)
后面我搞搞access token的自动登录?现在可以先用share token的 https://tokens.jerryz.com.cn/share/your_id
Varc
11
始皇的new站可以直接用share token登录吧?我也没有自测过
或许可以通过share token实现?
rt → at → st
# rt 换 at
curl -X POST https://token.oaifree.com/api/auth/refresh \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "refresh_token=xxxxx"
# at 生成 st
curl 'https://chat.oaifree.com/token/register' \
-H 'content-type: application/x-www-form-urlencoded; charset=UTF-8' \
--data-raw "unique_name=$(openssl rand -hex 8)" \
--data-raw 'access_token=xxxxx' \
--data-raw 'expires_in=0' \
--data-raw 'site_limit=' \
--data-raw 'gpt35_limit=-1' \
--data-raw 'gpt4_limit=-1' \
--data-raw 'show_conversations=true'
# st 登录
https://new.oaifree.com/auth/login_share?token=fk-xxxx
更新可以通过st返回的时间错 expire_at 判断
1 个赞
yeahow
(小叶)
14
在chatgpt的帮助下写了个勉强能用的,不过明天才有rt,还没测试,只测试了自动填入at,没啥问题。
使用方法:在源代码里填好自己的refresh token,访问 new.oaifree.com,如果处于未登录状态则会自动登录。
// @name oaifree自动登录
// @namespace https://linux.do/u/yeahow/
// @version 1.0
// @description 通过refresh token获取access token后自动填入并登录new.oaifree.com
// @author yeahow
// @match https://new.oaifree.com/auth/login_auth0
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 预先设置好的refreshToken
var refreshToken = 'your-refresh-token-here';
var accessToken = '';
// 立即获取accessToken
(async function fetchAccessToken() {
const response = await fetch('https://token.oaifree.com/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
body: `refresh_token=${encodeURIComponent(refreshToken)}`
});
const data = await response.json();
accessToken = data.access_token;
// 页面加载完成后执行
window.addEventListener('load', function() {
clickContinueButton();
waitForSwal();
});
})();
// 自动点击 "Continue with Access Token" 按钮
/* function clickContinueButton0() {
var continueButton = document.querySelector('#submit-token');
if (continueButton) {
continueButton.click();
}
}*/
// 修改后的 clickContinueButton 函数
function clickContinueButton() {
var continueButton = document.querySelector('#submit-token');
if (continueButton) {
continueButton.click();
setTimeout(fillAccessToken, 300); // 增加一个300毫秒的延迟,等待方框完全加载出来
}
}
// 填入accessToken并点击OK
function fillAccessToken() {
var inputField = document.querySelector('.swal2-textarea');
var okButton = document.querySelector('.swal2-confirm');
if (inputField && okButton) {
inputField.value = accessToken;
okButton.click();
}
}
// 等待Swal弹窗出现并填入token
function waitForSwal() {
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length) {
fillAccessToken();
observer.disconnect(); // 一旦找到,停止观察
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
}
})();
第一次写脚本,写的很烂轻喷,本来也是写着自己用的()
1 个赞
我也用gpt简单糊了一个
![:grinning: :grinning:](https://cdn.linux.do/images/emoji/apple/grinning.png?v=12)
// ==UserScript==
// @name OAIFree Auto Login
// @namespace http://tampermonkey.net/
// @version 0.1
// @description 自动判断st是否过期,如果过期则重新获取,并自动跳转登陆,同时在控制台打印日志输出
// @author You
// @match https://new.oaifree.com/auth/login_auth0
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @connect token.oaifree.com
// @connect chat.oaifree.com
// ==/UserScript==
(function() {
'use strict';
const refreshToken = 'xxxxxx'; // 替换为你的 refresh token
// 获取当前时间戳
function getCurrentTimestamp() {
return Math.floor(Date.now() / 1000);
}
// 检查 st 是否过期
function isSTExpired() {
const expireAt = GM_getValue('expire_at', 0);
console.log("st expire at: "+ expireAt )
return isNaN(expireAt) || getCurrentTimestamp() >= expireAt;
}
// 使用 rt 换取 at
function getAccessToken(refreshToken) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
url: 'https://token.oaifree.com/api/auth/refresh',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: `refresh_token=${refreshToken}`,
onload: function(response) {
if (response.status === 200) {
const data = JSON.parse(response.responseText);
if(data.access_token){
resolve(data.access_token)
}else{
reject('Failed to generate access token, response: ' + data);
}
} else {
reject('Failed to refresh access token');
}
},
onerror: function(e) {
console.error(e)
reject('Failed to refresh access token');
}
});
});
}
// 使用 at 生成 st
function getShareToken(accessToken) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
url: 'https://chat.oaifree.com/token/register',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
data: `unique_name=${generateRandomHex(8)}&access_token=${accessToken}&expires_in=0&site_limit=&gpt35_limit=-1&gpt4_limit=-1&show_conversations=true`,
onload: function(response) {
if (response.status === 200) {
const data = JSON.parse(response.responseText);
GM_setValue('expire_at', data.expire_at);
if(data.token_key){
resolve(data.token_key)
}else{
reject('Failed to generate share token, response: ' + data);
}
} else {
reject('Failed to generate share token');
}
},
onerror: function(e) {
console.error(e)
reject('Failed to generate share token');
}
});
});
}
// 生成随机字符串
function generateRandomHex(length) {
let result = '';
const characters = '0123456789abcdef';
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
// 自动登录
function autoLogin(shareToken) {
const loginUrl = `https://new.oaifree.com/auth/login_share?token=${shareToken}`;
console.log('Logging in with URL: ' + loginUrl);
window.location.href = loginUrl;
}
(async function() {
try {
let shareToken = GM_getValue("share_token")
if (isSTExpired() || !shareToken) {
console.log('ST token is expired. Refreshing tokens...');
const accessToken = await getAccessToken(refreshToken);
console.log('Access token obtained: ' + accessToken);
shareToken = await getShareToken(accessToken);
console.log('Share token obtained: ' + shareToken);
GM_setValue("share_token", shareToken)
} else {
console.log('ST token is still valid.');
}
autoLogin(shareToken);
} catch (error) {
console.error(error);
}
})();
})();
2 个赞