





















@@ -6,10 +6,13 @@ import {
66markMigrationItemError,
77markMigrationItemSkipped,
88} from "openclaw/plugin-sdk/migration";
9-import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
109import type { MigrationItem, MigrationProviderContext } from "openclaw/plugin-sdk/plugin-entry";
1110import {
11+buildOpenAICodexCredentialExtra,
1212buildOauthProviderAuthResult,
13+resolveOpenAICodexAccessTokenExpiry,
14+resolveOpenAICodexAuthIdentity,
15+resolveOpenAICodexImportProfileName,
1316updateAuthProfileStoreWithLock,
1417type AuthProfileStore,
1518type OAuthCredential,
@@ -61,13 +64,6 @@ type HermesCodexAuthProfile = {
6164sourceProfileId: string;
6265};
636664-type CodexIdentity = {
65-accountId?: string;
66-chatgptPlanType?: string;
67-email?: string;
68-profileName?: string;
69-};
70-7167function readTimestamp(value: unknown): number | undefined {
7268if (typeof value !== "string" || !value.trim()) {
7369return undefined;
@@ -76,66 +72,6 @@ function readTimestamp(value: unknown): number | undefined {
7672return Number.isFinite(parsed) ? parsed : undefined;
7773}
787479-function decodeJwtPayload(token: string): Record<string, unknown> | undefined {
80-const payload = token.split(".")[1];
81-if (!payload) {
82-return undefined;
83-}
84-try {
85-const parsed = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
86-return isRecord(parsed) ? parsed : undefined;
87-} catch {
88-return undefined;
89-}
90-}
91-92-function resolveCodexIdentity(access: string, accountId?: string): CodexIdentity {
93-const payload = decodeJwtPayload(access);
94-const auth = isRecord(payload?.["https://api.openai.com/auth"])
95- ? payload["https://api.openai.com/auth"]
96- : {};
97-const profile = isRecord(payload?.["https://api.openai.com/profile"])
98- ? payload["https://api.openai.com/profile"]
99- : {};
100-const email = readString(profile.email);
101-const resolvedAccountId = accountId ?? readString(auth.chatgpt_account_id);
102-const chatgptPlanType = readString(auth.chatgpt_plan_type);
103-if (email) {
104-return {
105- ...(resolvedAccountId ? { accountId: resolvedAccountId } : {}),
106- ...(chatgptPlanType ? { chatgptPlanType } : {}),
107- email,
108-profileName: email,
109-};
110-}
111-const stableSubject =
112-readString(auth.chatgpt_account_user_id) ??
113-readString(auth.chatgpt_user_id) ??
114-readString(auth.user_id) ??
115-readString(payload?.sub) ??
116-resolvedAccountId;
117-return {
118- ...(resolvedAccountId ? { accountId: resolvedAccountId } : {}),
119- ...(chatgptPlanType ? { chatgptPlanType } : {}),
120- ...(stableSubject
121- ? { profileName: `id-${Buffer.from(stableSubject).toString("base64url")}` }
122- : {}),
123-};
124-}
125-126-function resolveAccessTokenExpiry(access: string): number | undefined {
127-const payload = decodeJwtPayload(access);
128-const exp = payload?.exp;
129-if (typeof exp === "number" && Number.isFinite(exp) && exp > 0) {
130-return Math.trunc(exp) * 1000;
131-}
132-if (typeof exp === "string") {
133-const seconds = parseStrictPositiveInteger(exp);
134-return seconds === undefined ? undefined : seconds * 1000;
135-}
136-return undefined;
137-}
138-13975function sourceCredentialFingerprint(candidate: HermesCodexAuthCandidate): string {
14076const hash = createHash("sha256");
14177for (const part of [
@@ -266,39 +202,24 @@ async function readOpenCodeOpenAICandidates(
266202];
267203}
268204269-function credentialExtra(identity: CodexIdentity): Record<string, unknown> | undefined {
270-const extra = {
271- ...(identity.accountId ? { accountId: identity.accountId } : {}),
272- ...(identity.chatgptPlanType ? { chatgptPlanType: identity.chatgptPlanType } : {}),
273-};
274-return Object.keys(extra).length > 0 ? extra : undefined;
275-}
276-277-function importProfileName(identity: CodexIdentity, fallback: string): string {
278-if (identity.accountId) {
279-return `account-${identity.accountId.replaceAll(/[^A-Za-z0-9._-]+/gu, "-")}`;
280-}
281-if (identity.profileName?.startsWith("id-")) {
282-return identity.profileName;
283-}
284-return fallback;
285-}
286-287205function buildAuthResult(
288206candidate: HermesCodexAuthCandidate,
289207fallbackProfileName = "hermes-import",
290208): ProviderAuthResult {
291-const identity = resolveCodexIdentity(candidate.access, candidate.accountId);
209+const identity = resolveOpenAICodexAuthIdentity({
210+access: candidate.access,
211+accountId: candidate.accountId,
212+});
292213return buildOauthProviderAuthResult({
293214providerId: OPENAI_CODEX_PROVIDER_ID,
294215defaultModel: OPENAI_CODEX_DEFAULT_MODEL,
295216access: candidate.access,
296217refresh: candidate.refresh,
297-expires: resolveAccessTokenExpiry(candidate.access),
218+expires: resolveOpenAICodexAccessTokenExpiry(candidate.access),
298219email: identity.email,
299-profileName: importProfileName(identity, fallbackProfileName),
220+profileName: resolveOpenAICodexImportProfileName(identity, fallbackProfileName),
300221displayName: HERMES_AUTH_DISPLAY_NAME,
301-credentialExtra: credentialExtra(identity),
222+credentialExtra: buildOpenAICodexCredentialExtra(identity),
302223});
303224}
304225此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。