Add CPA session token output
This commit is contained in:
@@ -6,13 +6,17 @@
|
|||||||
|
|
||||||
### [**》》 点我直接使用 《《**](https://gtxx3600.github.io/GPTSession2CPAandSub2API/)
|
### [**》》 点我直接使用 《《**](https://gtxx3600.github.io/GPTSession2CPAandSub2API/)
|
||||||
|
|
||||||
|
## 使用提示
|
||||||
|
|
||||||
|
Plus 号可以用此方式导入中转站使用;Free 号的 access token 不能用于调用接口。
|
||||||
|
|
||||||
## 支持输入
|
## 支持输入
|
||||||
|
|
||||||
支持粘贴或拖入 ChatGPT Web session JSON,例如包含:
|
支持粘贴或拖入 ChatGPT Web session JSON,例如包含:
|
||||||
|
|
||||||
- `user.email`
|
- `user.email`
|
||||||
- `user.name`
|
|
||||||
- `accessToken`
|
- `accessToken`
|
||||||
|
- `sessionToken`
|
||||||
- `expires`
|
- `expires`
|
||||||
- `account.id`
|
- `account.id`
|
||||||
- `account.planType`
|
- `account.planType`
|
||||||
@@ -21,7 +25,7 @@
|
|||||||
|
|
||||||
## 输出格式
|
## 输出格式
|
||||||
|
|
||||||
- `CPA`:生成最小 Codex CPA JSON,包含 `type: "codex"`、`access_token`、`email`、`name`、过期时间等可推导字段。
|
- `CPA`:生成最小 Codex CPA JSON,包含 `type: "codex"`、`access_token`、`session_token`、`email`、`name`、过期时间等可推导字段。
|
||||||
- `sub2api`:生成参考 `CPA2sub2API` 项目的 `exported_at/proxies/accounts` 结构,账号平台为 `openai`,类型为 `oauth`。
|
- `sub2api`:生成参考 `CPA2sub2API` 项目的 `exported_at/proxies/accounts` 结构,账号平台为 `openai`,类型为 `oauth`。
|
||||||
ChatGPT Web session 通常不包含 CPA OAuth 文件里常见的 `refresh_token` 和 `id_token`,因此 CPA 输出不会伪造这些字段。
|
ChatGPT Web session 通常不包含 CPA OAuth 文件里常见的 `refresh_token` 和 `id_token`,因此 CPA 输出不会伪造这些字段。
|
||||||
|
|
||||||
|
|||||||
+13
-11
@@ -573,7 +573,7 @@
|
|||||||
<a href="https://chatgpt.com/api/auth/session" target="_blank" rel="noreferrer">https://chatgpt.com/api/auth/session</a>
|
<a href="https://chatgpt.com/api/auth/session" target="_blank" rel="noreferrer">https://chatgpt.com/api/auth/session</a>
|
||||||
,复制页面显示的整段 JSON,粘贴到下方输入框。
|
,复制页面显示的整段 JSON,粘贴到下方输入框。
|
||||||
</p>
|
</p>
|
||||||
<p class="session-warning">这段 JSON 包含 accessToken,等同敏感登录凭证,不要发给别人。</p>
|
<p class="session-warning">这段 JSON 包含 accessToken 和 sessionToken,等同敏感登录凭证,不要发给别人。</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropzone" id="dropzone" tabindex="0" role="button">
|
<div class="dropzone" id="dropzone" tabindex="0" role="button">
|
||||||
<div>
|
<div>
|
||||||
@@ -590,7 +590,7 @@
|
|||||||
<textarea
|
<textarea
|
||||||
id="session-input"
|
id="session-input"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
placeholder='{"user":{"name":"Mark Anderson","email":"mark@example.com"},"expires":"2026-08-06T14:29:36.155Z","account":{"id":"...","planType":"free"},"accessToken":"..."}'
|
placeholder='{"user":{"email":"mark@example.com"},"expires":"2026-08-06T14:29:36.155Z","account":{"id":"...","planType":"plus"},"accessToken":"...","sessionToken":"..."}'
|
||||||
></textarea>
|
></textarea>
|
||||||
<div class="status-line" id="input-status">等待输入。</div>
|
<div class="status-line" id="input-status">等待输入。</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -692,15 +692,15 @@
|
|||||||
const exampleSession = {
|
const exampleSession = {
|
||||||
user: {
|
user: {
|
||||||
id: "user-example",
|
id: "user-example",
|
||||||
name: "Mark Anderson",
|
|
||||||
email: "mark@example.com",
|
email: "mark@example.com",
|
||||||
},
|
},
|
||||||
expires: "2026-08-06T14:29:36.155Z",
|
expires: "2026-08-06T14:29:36.155Z",
|
||||||
account: {
|
account: {
|
||||||
id: "00000000-0000-4000-9000-000000000000",
|
id: "00000000-0000-4000-9000-000000000000",
|
||||||
planType: "free",
|
planType: "plus",
|
||||||
},
|
},
|
||||||
accessToken: "paste-real-access-token-here",
|
accessToken: "paste-real-access-token-here",
|
||||||
|
sessionToken: "paste-real-session-token-here",
|
||||||
authProvider: "openai",
|
authProvider: "openai",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -948,6 +948,13 @@
|
|||||||
if (!accessToken) {
|
if (!accessToken) {
|
||||||
throw new Error("缺少 accessToken");
|
throw new Error("缺少 accessToken");
|
||||||
}
|
}
|
||||||
|
const sessionToken = firstNonEmpty(
|
||||||
|
record.sessionToken,
|
||||||
|
record.session_token,
|
||||||
|
record.token?.sessionToken,
|
||||||
|
record.token?.session_token,
|
||||||
|
record.credentials?.session_token,
|
||||||
|
);
|
||||||
|
|
||||||
const payload = parseJwtPayload(accessToken);
|
const payload = parseJwtPayload(accessToken);
|
||||||
const auth = getOpenAIAuthSection(payload);
|
const auth = getOpenAIAuthSection(payload);
|
||||||
@@ -965,13 +972,6 @@
|
|||||||
profile.email,
|
profile.email,
|
||||||
payload?.email,
|
payload?.email,
|
||||||
);
|
);
|
||||||
const name = firstNonEmpty(
|
|
||||||
record.user?.name,
|
|
||||||
record.name,
|
|
||||||
profile.name,
|
|
||||||
email,
|
|
||||||
"ChatGPT Account",
|
|
||||||
);
|
|
||||||
const accountId = firstNonEmpty(
|
const accountId = firstNonEmpty(
|
||||||
record.account?.id,
|
record.account?.id,
|
||||||
record.account_id,
|
record.account_id,
|
||||||
@@ -994,10 +994,12 @@
|
|||||||
const exportedAt = normalizeTimestamp(options.now || new Date());
|
const exportedAt = normalizeTimestamp(options.now || new Date());
|
||||||
const expiresIn = getExpiresIn(expiresAt, options.now || new Date());
|
const expiresIn = getExpiresIn(expiresAt, options.now || new Date());
|
||||||
const sourceName = firstNonEmpty(options.sourceName, "pasted-json");
|
const sourceName = firstNonEmpty(options.sourceName, "pasted-json");
|
||||||
|
const name = firstNonEmpty(email, sourceName, "ChatGPT Account");
|
||||||
|
|
||||||
const cpa = stripUnavailable({
|
const cpa = stripUnavailable({
|
||||||
type: "codex",
|
type: "codex",
|
||||||
access_token: accessToken,
|
access_token: accessToken,
|
||||||
|
session_token: sessionToken,
|
||||||
account_id: accountId,
|
account_id: accountId,
|
||||||
email,
|
email,
|
||||||
name,
|
name,
|
||||||
|
|||||||
Reference in New Issue
Block a user