@modelprofile.com/authswitch 6.1.0 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.codexauth.d.ts +8 -5
- package/dist_ts/classes.codexauth.js +78 -69
- package/dist_ts/classes.codexharness.d.ts +25 -0
- package/dist_ts/classes.codexharness.js +59 -6
- package/dist_ts/classes.stashstore.d.ts +10 -0
- package/dist_ts/classes.stashstore.js +22 -1
- package/package.json +1 -1
- package/readme.md +28 -8
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.codexauth.ts +85 -75
- package/ts/classes.codexharness.ts +58 -6
- package/ts/classes.stashstore.ts +22 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@modelprofile.com/authswitch',
|
|
6
|
-
version: '6.
|
|
6
|
+
version: '6.2.0',
|
|
7
7
|
description: 'Manage Codex, OpenCode and Claude Code accounts with guided switching and live usage status'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSw4QkFBOEI7SUFDcEMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDZGQUE2RjtDQUMzRyxDQUFBIn0=
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { IActiveAuth, ICodexIdentity } from './interfaces.js';
|
|
2
2
|
import { CodexHome } from './classes.codexhome.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts the account identity from the content of an auth.json.
|
|
5
|
+
* Returns null when the content holds no recognisable credential.
|
|
6
|
+
*
|
|
7
|
+
* It stands outside the class because the stash store keys and guards its entries by the same identity and has
|
|
8
|
+
* no Codex installation to read: the credential itself is all this derivation needs.
|
|
9
|
+
*/
|
|
10
|
+
export declare const codexIdentityFromRaw: (rawArg: string) => ICodexIdentity | null;
|
|
3
11
|
/**
|
|
4
12
|
* Reads, writes and clears the Codex file credential store, and derives the
|
|
5
13
|
* account identity used to key a stash.
|
|
@@ -15,11 +23,6 @@ export declare class CodexAuth {
|
|
|
15
23
|
* Returns null when the file holds no recognisable credential.
|
|
16
24
|
*/
|
|
17
25
|
identityFromRaw(rawArg: string): ICodexIdentity | null;
|
|
18
|
-
/**
|
|
19
|
-
* A short, non-reversible label for an API key so two different keys get two
|
|
20
|
-
* different stashes without the key itself ever being written down.
|
|
21
|
-
*/
|
|
22
|
-
private fingerprint;
|
|
23
26
|
/** Reads the active credential, if any. */
|
|
24
27
|
readActive(): IActiveAuth;
|
|
25
28
|
/**
|
|
@@ -53,6 +53,82 @@ const findFirstJwt = (valueArg, depthArg = 0) => {
|
|
|
53
53
|
}
|
|
54
54
|
return null;
|
|
55
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* A short, non-reversible label for an API key so two different keys get two
|
|
58
|
+
* different stashes without the key itself ever being written down.
|
|
59
|
+
*/
|
|
60
|
+
const fingerprint = (secretArg) => {
|
|
61
|
+
let hash = 0x811c9dc5;
|
|
62
|
+
for (let index = 0; index < secretArg.length; index++) {
|
|
63
|
+
hash ^= secretArg.charCodeAt(index);
|
|
64
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
65
|
+
}
|
|
66
|
+
return hash.toString(16).padStart(8, '0');
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Extracts the account identity from the content of an auth.json.
|
|
70
|
+
* Returns null when the content holds no recognisable credential.
|
|
71
|
+
*
|
|
72
|
+
* It stands outside the class because the stash store keys and guards its entries by the same identity and has
|
|
73
|
+
* no Codex installation to read: the credential itself is all this derivation needs.
|
|
74
|
+
*/
|
|
75
|
+
export const codexIdentityFromRaw = (rawArg) => {
|
|
76
|
+
let parsed;
|
|
77
|
+
try {
|
|
78
|
+
parsed = JSON.parse(rawArg);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const record = parsed;
|
|
87
|
+
const tokens = (record.tokens ?? null);
|
|
88
|
+
const idToken = (tokens ? asString(tokens.id_token) : null) ?? findFirstJwt(record);
|
|
89
|
+
if (idToken) {
|
|
90
|
+
const claims = decodeJwtPayload(idToken) ?? {};
|
|
91
|
+
const authClaim = (claims['https://api.openai.com/auth'] ?? {});
|
|
92
|
+
const profileClaim = (claims['https://api.openai.com/profile'] ?? {});
|
|
93
|
+
const email = asString(claims.email) ??
|
|
94
|
+
asString(profileClaim.email) ??
|
|
95
|
+
asString(authClaim.user_email);
|
|
96
|
+
const accountId = asString(authClaim.chatgpt_account_id) ??
|
|
97
|
+
(tokens ? asString(tokens.account_id) : null) ??
|
|
98
|
+
asString(record.account_id);
|
|
99
|
+
if (email) {
|
|
100
|
+
return {
|
|
101
|
+
kind: 'chatgpt',
|
|
102
|
+
email: email.toLowerCase(),
|
|
103
|
+
accountId,
|
|
104
|
+
planType: asString(authClaim.chatgpt_plan_type),
|
|
105
|
+
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (accountId) {
|
|
109
|
+
// An OAuth credential we cannot label by email is still worth stashing;
|
|
110
|
+
// key it by account id so it round-trips instead of being silently dropped.
|
|
111
|
+
return {
|
|
112
|
+
kind: 'chatgpt',
|
|
113
|
+
email: `account:${accountId}`,
|
|
114
|
+
accountId,
|
|
115
|
+
planType: asString(authClaim.chatgpt_plan_type),
|
|
116
|
+
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const apiKey = asString(record.OPENAI_API_KEY) ?? asString(record.openai_api_key);
|
|
121
|
+
if (apiKey) {
|
|
122
|
+
return {
|
|
123
|
+
kind: 'apikey',
|
|
124
|
+
email: `apikey:${fingerprint(apiKey)}`,
|
|
125
|
+
accountId: null,
|
|
126
|
+
planType: null,
|
|
127
|
+
userId: null,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
};
|
|
56
132
|
/**
|
|
57
133
|
* Reads, writes and clears the Codex file credential store, and derives the
|
|
58
134
|
* account identity used to key a stash.
|
|
@@ -70,74 +146,7 @@ export class CodexAuth {
|
|
|
70
146
|
* Returns null when the file holds no recognisable credential.
|
|
71
147
|
*/
|
|
72
148
|
identityFromRaw(rawArg) {
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
parsed = JSON.parse(rawArg);
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
const record = parsed;
|
|
84
|
-
const tokens = (record.tokens ?? null);
|
|
85
|
-
const idToken = (tokens ? asString(tokens.id_token) : null) ?? findFirstJwt(record);
|
|
86
|
-
if (idToken) {
|
|
87
|
-
const claims = decodeJwtPayload(idToken) ?? {};
|
|
88
|
-
const authClaim = (claims['https://api.openai.com/auth'] ?? {});
|
|
89
|
-
const profileClaim = (claims['https://api.openai.com/profile'] ?? {});
|
|
90
|
-
const email = asString(claims.email) ??
|
|
91
|
-
asString(profileClaim.email) ??
|
|
92
|
-
asString(authClaim.user_email);
|
|
93
|
-
const accountId = asString(authClaim.chatgpt_account_id) ??
|
|
94
|
-
(tokens ? asString(tokens.account_id) : null) ??
|
|
95
|
-
asString(record.account_id);
|
|
96
|
-
if (email) {
|
|
97
|
-
return {
|
|
98
|
-
kind: 'chatgpt',
|
|
99
|
-
email: email.toLowerCase(),
|
|
100
|
-
accountId,
|
|
101
|
-
planType: asString(authClaim.chatgpt_plan_type),
|
|
102
|
-
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
if (accountId) {
|
|
106
|
-
// An OAuth credential we cannot label by email is still worth stashing;
|
|
107
|
-
// key it by account id so it round-trips instead of being silently dropped.
|
|
108
|
-
return {
|
|
109
|
-
kind: 'chatgpt',
|
|
110
|
-
email: `account:${accountId}`,
|
|
111
|
-
accountId,
|
|
112
|
-
planType: asString(authClaim.chatgpt_plan_type),
|
|
113
|
-
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
const apiKey = asString(record.OPENAI_API_KEY) ?? asString(record.openai_api_key);
|
|
118
|
-
if (apiKey) {
|
|
119
|
-
const fingerprint = this.fingerprint(apiKey);
|
|
120
|
-
return {
|
|
121
|
-
kind: 'apikey',
|
|
122
|
-
email: `apikey:${fingerprint}`,
|
|
123
|
-
accountId: null,
|
|
124
|
-
planType: null,
|
|
125
|
-
userId: null,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* A short, non-reversible label for an API key so two different keys get two
|
|
132
|
-
* different stashes without the key itself ever being written down.
|
|
133
|
-
*/
|
|
134
|
-
fingerprint(secretArg) {
|
|
135
|
-
let hash = 0x811c9dc5;
|
|
136
|
-
for (let index = 0; index < secretArg.length; index++) {
|
|
137
|
-
hash ^= secretArg.charCodeAt(index);
|
|
138
|
-
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
139
|
-
}
|
|
140
|
-
return hash.toString(16).padStart(8, '0');
|
|
149
|
+
return codexIdentityFromRaw(rawArg);
|
|
141
150
|
}
|
|
142
151
|
/** Reads the active credential, if any. */
|
|
143
152
|
readActive() {
|
|
@@ -181,4 +190,4 @@ export class CodexAuth {
|
|
|
181
190
|
}
|
|
182
191
|
}
|
|
183
192
|
}
|
|
184
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
193
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jb2RleGF1dGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmNvZGV4YXV0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDbkQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRXpEOzs7OztHQUtHO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLFFBQWdCLEVBQWtDLEVBQUU7SUFDNUUsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNyQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDeEIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQ0QsSUFBSSxDQUFDO1FBQ0gsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sTUFBTSxHQUFZLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDNUMsSUFBSSxNQUFNLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQ25FLE9BQU8sTUFBaUMsQ0FBQztRQUMzQyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0FBQ0gsQ0FBQyxDQUFDO0FBRUYsTUFBTSxRQUFRLEdBQUcsQ0FBQyxRQUFpQixFQUFpQixFQUFFLENBQ3BELE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxR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
|
|
@@ -19,7 +19,32 @@ export declare class CodexHarness implements IAuthHarness {
|
|
|
19
19
|
readonly autoSwitch = true;
|
|
20
20
|
constructor(switcher?: CodexSwitcher, accountStatus?: Pick<CodexAccountStatus, 'read'>, preuse?: Pick<CodexPreuse, 'run'>);
|
|
21
21
|
beginLogin(options?: IHarnessLoginOptions): Promise<import("./interfaces.harness.js").IHarnessLoginHandle>;
|
|
22
|
+
/**
|
|
23
|
+
* The harness's accounts, with the saved copy of the active login brought up to date first.
|
|
24
|
+
*
|
|
25
|
+
* A saved login is one whose stored credential is readable and belongs to the account its record names. The
|
|
26
|
+
* exact tokens are not part of that: Codex' app-server refreshes the login it runs on its own schedule, so
|
|
27
|
+
* comparing bytes reported every saved active login as unsaved from its first refresh on, and the guide then
|
|
28
|
+
* offered to save what was already saved.
|
|
29
|
+
*/
|
|
22
30
|
readState(): IHarnessState;
|
|
31
|
+
/** Whether a saved record is the record of this identity: same account, same email, same kind of login. */
|
|
32
|
+
private recordOf;
|
|
33
|
+
/**
|
|
34
|
+
* Writes the credential Codex is running on into that account's own saved record, and reports why it could
|
|
35
|
+
* not when the write failed.
|
|
36
|
+
*
|
|
37
|
+
* Codex rotates the tokens of the active login, and until now only a switch or a save wrote that rotation
|
|
38
|
+
* back -- `use()` re-saves the outgoing login, and re-selecting the active account updates its record before
|
|
39
|
+
* restoring the pairings. Every read now keeps the saved copy on the credential Codex last wrote, so the copy
|
|
40
|
+
* is one a switch can restore rather than one the service has moved past.
|
|
41
|
+
*
|
|
42
|
+
* The write goes only into the stash: Codex' own files are read, nothing is stopped or signalled, no daemon
|
|
43
|
+
* has to be down for it, and the record keeps its save time and its enrollments. A login with no saved record
|
|
44
|
+
* of its own is never saved implicitly -- `stash` is what saves a login -- and a record whose credential is
|
|
45
|
+
* missing or belongs to another account is left for `stash` to repair rather than quietly overwritten.
|
|
46
|
+
*/
|
|
47
|
+
private mirrorActiveLogin;
|
|
23
48
|
readAccountStatus(accountIdArg: string, optionsArg?: IHarnessStatusOptions): Promise<IHarnessAccountStatus>;
|
|
24
49
|
preuseAccount(accountIdArg: string, optionsArg: IHarnessPreuseOptions): Promise<IHarnessPreuseResult>;
|
|
25
50
|
private readAccountCredential;
|
|
@@ -5,6 +5,14 @@ import { PreuseError } from './preuse.js';
|
|
|
5
5
|
import { countPaired, enrollmentState } from './helpers.js';
|
|
6
6
|
import { beginSavedOpenAiLogin } from './classes.login.js';
|
|
7
7
|
import { plainText } from './formatting.js';
|
|
8
|
+
/**
|
|
9
|
+
* Why a write into the stash failed, as its system error code. The message of a filesystem error names the path
|
|
10
|
+
* it was writing, and that path leads to a credential.
|
|
11
|
+
*/
|
|
12
|
+
const writeFailureCause = (errorArg) => {
|
|
13
|
+
const code = errorArg?.code;
|
|
14
|
+
return typeof code === 'string' ? code : 'unknown cause';
|
|
15
|
+
};
|
|
8
16
|
/** Codex-specific credentials, remote-control handling and service status. */
|
|
9
17
|
export class CodexHarness {
|
|
10
18
|
switcher;
|
|
@@ -41,21 +49,28 @@ export class CodexHarness {
|
|
|
41
49
|
return { outcome: { lines: [`Saved ${plainText(identity.email)}. Select it to switch Codex.`], problems: [] }, account: { id: identity.email, label: identity.email } };
|
|
42
50
|
}, options);
|
|
43
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The harness's accounts, with the saved copy of the active login brought up to date first.
|
|
54
|
+
*
|
|
55
|
+
* A saved login is one whose stored credential is readable and belongs to the account its record names. The
|
|
56
|
+
* exact tokens are not part of that: Codex' app-server refreshes the login it runs on its own schedule, so
|
|
57
|
+
* comparing bytes reported every saved active login as unsaved from its first refresh on, and the guide then
|
|
58
|
+
* offered to save what was already saved.
|
|
59
|
+
*/
|
|
44
60
|
readState() {
|
|
45
61
|
const active = this.switcher.readActive();
|
|
62
|
+
const mirrorFailure = this.mirrorActiveLogin(active);
|
|
46
63
|
const accounts = this.switcher.list().map((entryArg) => {
|
|
47
64
|
const raw = this.switcher.stashes.readAuth(entryArg.email);
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const isActive = active.identity !== null && active.identity.email === entryArg.email && active.identity.accountId === entryArg.accountId && active.identity.kind === entryArg.kind;
|
|
51
|
-
const isStashed = valid && (!isActive || raw === active.raw);
|
|
65
|
+
const isStashed = this.recordOf(entryArg, raw === null ? null : this.switcher.auth.identityFromRaw(raw));
|
|
66
|
+
const isActive = this.recordOf(entryArg, active.identity);
|
|
52
67
|
return {
|
|
53
68
|
id: entryArg.email,
|
|
54
69
|
label: entryArg.email,
|
|
55
70
|
isActive,
|
|
56
71
|
isStashed,
|
|
57
72
|
savedAt: entryArg.stashedAt,
|
|
58
|
-
details: [this.formatRemoteControl(entryArg).trim(), ...(!
|
|
73
|
+
details: [this.formatRemoteControl(entryArg).trim(), ...(!isStashed ? ['saved credential missing or does not match its metadata'] : isActive && mirrorFailure !== null ? [mirrorFailure] : [])],
|
|
59
74
|
};
|
|
60
75
|
});
|
|
61
76
|
if (active.identity && !accounts.some((accountArg) => accountArg.isActive)) {
|
|
@@ -71,6 +86,44 @@ export class CodexHarness {
|
|
|
71
86
|
? 'A different Codex account with this email is already saved. The email-based Codex store cannot keep both; refusing to replace it.' : null,
|
|
72
87
|
};
|
|
73
88
|
}
|
|
89
|
+
/** Whether a saved record is the record of this identity: same account, same email, same kind of login. */
|
|
90
|
+
recordOf(entryArg, identityArg) {
|
|
91
|
+
return identityArg !== null && entryArg.email === identityArg.email && entryArg.accountId === identityArg.accountId && entryArg.kind === identityArg.kind;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Writes the credential Codex is running on into that account's own saved record, and reports why it could
|
|
95
|
+
* not when the write failed.
|
|
96
|
+
*
|
|
97
|
+
* Codex rotates the tokens of the active login, and until now only a switch or a save wrote that rotation
|
|
98
|
+
* back -- `use()` re-saves the outgoing login, and re-selecting the active account updates its record before
|
|
99
|
+
* restoring the pairings. Every read now keeps the saved copy on the credential Codex last wrote, so the copy
|
|
100
|
+
* is one a switch can restore rather than one the service has moved past.
|
|
101
|
+
*
|
|
102
|
+
* The write goes only into the stash: Codex' own files are read, nothing is stopped or signalled, no daemon
|
|
103
|
+
* has to be down for it, and the record keeps its save time and its enrollments. A login with no saved record
|
|
104
|
+
* of its own is never saved implicitly -- `stash` is what saves a login -- and a record whose credential is
|
|
105
|
+
* missing or belongs to another account is left for `stash` to repair rather than quietly overwritten.
|
|
106
|
+
*/
|
|
107
|
+
mirrorActiveLogin(activeArg) {
|
|
108
|
+
if (activeArg.source !== 'file' || activeArg.identity === null || activeArg.raw === null)
|
|
109
|
+
return null;
|
|
110
|
+
const email = activeArg.identity.email;
|
|
111
|
+
const saved = this.switcher.stashes.readAuth(email);
|
|
112
|
+
if (saved === null || saved === activeArg.raw)
|
|
113
|
+
return null;
|
|
114
|
+
const meta = this.switcher.stashes.readMeta(email);
|
|
115
|
+
if (meta === null || !this.recordOf(meta, activeArg.identity) || !this.recordOf(meta, this.switcher.auth.identityFromRaw(saved)))
|
|
116
|
+
return null;
|
|
117
|
+
try {
|
|
118
|
+
this.switcher.stashes.replaceAuth(email, activeArg.raw);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
catch (errorArg) {
|
|
122
|
+
// A saved copy that could not be brought up to date is no reason to fail a read: the record still holds a
|
|
123
|
+
// credential of this account, and the next read tries again.
|
|
124
|
+
return `the current login could not be copied into its saved record (${writeFailureCause(errorArg)}); the record still holds the credential from the last save`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
74
127
|
async readAccountStatus(accountIdArg, optionsArg) {
|
|
75
128
|
const credential = this.readAccountCredential(accountIdArg);
|
|
76
129
|
if (!credential)
|
|
@@ -200,4 +253,4 @@ export class CodexHarness {
|
|
|
200
253
|
return { lines, problems: [] };
|
|
201
254
|
}
|
|
202
255
|
}
|
|
203
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jb2RleGhhcm5lc3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmNvZGV4aGFybmVzcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDOUQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHMUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDNUQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDM0QsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRzVDLDhFQUE4RTtBQUM5RSxNQUFNLE9BQU8sWUFBWTtJQVlKO0lBQ0E7SUFDQTtJQWJILEVBQUUsR0FBRyxPQUFPLENBQUM7SUFDYixLQUFLLEdBQUcsT0FBTyxDQUFDO0lBQ2hCLFNBQVMsR0FBRyxpRUFBaUUsQ0FBQztJQUM5RSxjQUFjLEdBQTRCLENBQUMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3pHLGdCQUFnQixHQUFHLDZDQUE2QyxDQUFDO0lBQ2pGLDRHQUE0RztJQUM1RixRQUFRLEdBQUcsS0FBSyxDQUFDO0lBQ2pDLHNHQUFzRztJQUN0RixVQUFVLEdBQUcsSUFBSSxDQUFDO0lBRWxDLFlBQ21CLFdBQVcsSUFBSSxhQUFhLEVBQUUsRUFDOUIsZ0JBQWtELElBQUksa0JBQWtCLEVBQUUsRUFDMUUsU0FBbUMsSUFBSSxXQUFXLEVBQUU7UUFGcEQsYUFBUSxHQUFSLFFBQVEsQ0FBc0I7UUFD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
|
|
256
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jb2RleGhhcm5lc3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmNvZGV4aGFybmVzcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDOUQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHMUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDNUQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDM0QsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRzVDOzs7R0FHRztBQUNILE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxRQUFpQixFQUFVLEVBQUU7SUFDdEQsTUFBTSxJQUFJLEdBQUksUUFBc0MsRUFBRSxJQUFJLENBQUM7SUFDM0QsT0FBTyxPQUFPLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDO0FBQzNELENBQUMsQ0FBQztBQUVGLDhFQUE4RTtBQUM5RSxNQUFNLE9BQU8sWUFBWTtJQVlKO0lBQ0E7SUFDQTtJQWJILEVBQUUsR0FBRyxPQUFPLENBQUM7SUFDYixLQUFLLEdBQUcsT0FBTyxDQUFDO0lBQ2hCLFNBQVMsR0FBRyxpRUFBaUUsQ0FBQztJQUM5RSxjQUFjLEdBQTRCLENBQUMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3pHLGdCQUFnQixHQUFHLDZDQUE2QyxDQUFDO0lBQ2pGLDRH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
|
|
@@ -30,6 +30,16 @@ export declare class StashStore {
|
|
|
30
30
|
* verify with `readBack()` before destroying the original.
|
|
31
31
|
*/
|
|
32
32
|
write(identityArg: ICodexIdentity, rawAuthArg: string, enrollmentsArg: IRemoteControlEnrollment[], codexHomeArg: string): IStashEntry;
|
|
33
|
+
/**
|
|
34
|
+
* Replaces the credential of an existing stash and leaves its metadata exactly as it is.
|
|
35
|
+
*
|
|
36
|
+
* Codex refreshes the login it is running on its own schedule, so a saved copy of that login holds older
|
|
37
|
+
* tokens until something writes the rotation back. Doing so is an update of one account's credential, not a
|
|
38
|
+
* new save: the record keeps its account, its enrollments and the moment it was saved, which `write()` would
|
|
39
|
+
* stamp anew. The credential must belong to the account the metadata names -- the same guard `write()`
|
|
40
|
+
* applies -- so a mirror can never move one account's login into another account's record.
|
|
41
|
+
*/
|
|
42
|
+
replaceAuth(emailArg: string, rawAuthArg: string): void;
|
|
33
43
|
/**
|
|
34
44
|
* Reads a stash back and confirms it matches what was meant to be written.
|
|
35
45
|
* Callers use this before clearing the active credential, so a stash is only
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
2
|
import { writeSecretFileAtomically } from './helpers.js';
|
|
3
|
+
import { codexIdentityFromRaw } from './classes.codexauth.js';
|
|
3
4
|
const AUTH_FILE_NAME = 'auth.json';
|
|
4
5
|
const META_FILE_NAME = 'stash.json';
|
|
5
6
|
/**
|
|
@@ -80,6 +81,26 @@ export class StashStore {
|
|
|
80
81
|
writeSecretFileAtomically(plugins.path.join(dir, META_FILE_NAME), `${JSON.stringify(entry, null, 2)}\n`);
|
|
81
82
|
return entry;
|
|
82
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Replaces the credential of an existing stash and leaves its metadata exactly as it is.
|
|
86
|
+
*
|
|
87
|
+
* Codex refreshes the login it is running on its own schedule, so a saved copy of that login holds older
|
|
88
|
+
* tokens until something writes the rotation back. Doing so is an update of one account's credential, not a
|
|
89
|
+
* new save: the record keeps its account, its enrollments and the moment it was saved, which `write()` would
|
|
90
|
+
* stamp anew. The credential must belong to the account the metadata names -- the same guard `write()`
|
|
91
|
+
* applies -- so a mirror can never move one account's login into another account's record.
|
|
92
|
+
*/
|
|
93
|
+
replaceAuth(emailArg, rawAuthArg) {
|
|
94
|
+
const meta = this.readMeta(emailArg);
|
|
95
|
+
if (!meta) {
|
|
96
|
+
throw new Error(`no stash for "${emailArg}" whose credential could be replaced`);
|
|
97
|
+
}
|
|
98
|
+
const identity = codexIdentityFromRaw(rawAuthArg);
|
|
99
|
+
if (!identity || identity.email !== meta.email || identity.accountId !== meta.accountId || identity.kind !== meta.kind) {
|
|
100
|
+
throw new Error('the credential does not belong to the account this stash holds; refusing to replace it');
|
|
101
|
+
}
|
|
102
|
+
writeSecretFileAtomically(plugins.path.join(this.entryDir(emailArg), AUTH_FILE_NAME), rawAuthArg);
|
|
103
|
+
}
|
|
83
104
|
/**
|
|
84
105
|
* Reads a stash back and confirms it matches what was meant to be written.
|
|
85
106
|
* Callers use this before clearing the active credential, so a stash is only
|
|
@@ -189,4 +210,4 @@ export class StashStore {
|
|
|
189
210
|
return true;
|
|
190
211
|
}
|
|
191
212
|
}
|
|
192
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
213
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zdGFzaHN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5zdGFzaHN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBT3hDLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN6RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUU5RCxNQUFNLGNBQWMsR0FBRyxXQUFXLENBQUM7QUFDbkMsTUFBTSxjQUFjLEdBQUcsWUFBWSxDQUFDO0FBRXBDOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxPQUFPLFVBQVU7SUFDTCxPQUFPLENBQVM7SUFDaEIsT0FBTyxDQUFlO0lBRXRDLFlBQVksVUFBd0IsRUFBRSxVQUFtQjtRQUN2RCxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDMUMsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1FBQy9DLENBQUM7UUFDRCxJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQztRQUMxQixNQUFNLElBQUksR0FDUixVQUFVO1lBQ1YsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlO1lBQzNCLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFDekQsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVEOzs7T0FHRztJQUNJLE9BQU8sQ0FBQyxRQUFnQjtRQUM3QixNQUFNLElBQUksR0FBRyxRQUFRO2FBQ2xCLFdBQVcsRUFBRTthQUNiLE9BQU8sQ0FBQyxrQkFBa0IsRUFBRSxHQUFHLENBQUM7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
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -32,10 +32,11 @@ control, or remove a saved account. The guide shows the current account and retu
|
|
|
32
32
|
to the menu after each successful action; choose **Back** in a submenu or **Exit** to finish.
|
|
33
33
|
|
|
34
34
|
Before showing the actions, the guide checks whether the current credential has a
|
|
35
|
-
|
|
36
|
-
while keeping it active
|
|
37
|
-
|
|
38
|
-
automatically through the harness
|
|
35
|
+
readable saved copy of its own account. A login without one gets an offer to save it
|
|
36
|
+
while keeping it active; a login its harness merely refreshed is already saved. The
|
|
37
|
+
switch action checks again before offering targets; declining that save cancels the
|
|
38
|
+
switch. Scripts still preserve the outgoing login automatically through the harness
|
|
39
|
+
adapter.
|
|
39
40
|
|
|
40
41
|
When saving, choose whether to keep the account active or clear the active login so
|
|
41
42
|
you can run `codex login` for another account. Removing a saved account requires
|
|
@@ -302,6 +303,19 @@ saved implicitly; `stash` is what saves a login. An installation whose native lo
|
|
|
302
303
|
authswitch cannot read mirrors nothing, and a read waits at most a second for a lock a
|
|
303
304
|
switch or Claude Code holds before leaving the saved copy to the next read.
|
|
304
305
|
|
|
306
|
+
Codex is mirrored the same way, for the same reason: its app-server refreshes the login it
|
|
307
|
+
runs on its own schedule, so the saved copy of that login held older tokens between
|
|
308
|
+
switches -- and, because a saved login used to mean the *exact* credential in
|
|
309
|
+
`~/.codex/auth.json`, an account read as unsaved from its first refresh on and the guide
|
|
310
|
+
offered to save what was already saved. A saved Codex login is now one whose stored
|
|
311
|
+
credential belongs to the account its record names, and reading the accounts writes the
|
|
312
|
+
refreshed credential into that record. Only the saved copy is written: `~/.codex/auth.json`
|
|
313
|
+
is read, no app-server is stopped or signalled for it, and the record keeps its account,
|
|
314
|
+
its remote-control enrollments and its save time. A login with no saved record of its own,
|
|
315
|
+
a record whose credential is missing, and a record that belongs to another Codex account
|
|
316
|
+
with the same email are all left alone; `stash` is what saves or repairs those. A copy that
|
|
317
|
+
could not be written says so beside the account and is tried again on the next read.
|
|
318
|
+
|
|
305
319
|
An account the service has put **on hold** is not a dead login: the hold refuses the grant
|
|
306
320
|
while it lasts and the same login works again once it is lifted, so such an account keeps
|
|
307
321
|
its stored plan, says that it is on hold and where to appeal, and is asked again on the
|
|
@@ -820,9 +834,10 @@ unsaved current login adds how to keep it (`authswitch <harness> stash --keep sa
|
|
|
820
834
|
it`).
|
|
821
835
|
|
|
822
836
|
`authswitch <harness> current` prints the same sentence. The same account with a
|
|
823
|
-
rotated token is that account refreshing itself and is not reported; for Claude Code
|
|
824
|
-
rotation is copied into that account's saved record
|
|
825
|
-
check against the file's current contents
|
|
837
|
+
rotated token is that account refreshing itself and is not reported; for Claude Code and
|
|
838
|
+
Codex the rotation is copied into that account's saved record. Re-running the switch
|
|
839
|
+
re-arms the Claude Code and OpenCode check against the file's current contents; Codex has
|
|
840
|
+
no such check.
|
|
826
841
|
|
|
827
842
|
Both commands accept a harness qualifier (`authswitch claude limits`) and `--json`.
|
|
828
843
|
Neither changes which account is in use: they never activate, switch or clear a login and
|
|
@@ -895,7 +910,9 @@ another workspace's default entry cannot supply its billing information.
|
|
|
895
910
|
Each request uses that account's access token and account ID. For the active
|
|
896
911
|
account it reads the current credential, which may be newer than the stash.
|
|
897
912
|
Listing never switches accounts, starts or stops an app-server, refreshes tokens,
|
|
898
|
-
writes
|
|
913
|
+
writes `~/.codex/auth.json`, stores status results, or consumes an earned reset. The one
|
|
914
|
+
write it makes is the saved copy of the active login, brought onto the credential Codex is
|
|
915
|
+
running on as described above.
|
|
899
916
|
|
|
900
917
|
These backend contracts come from Codex's source and can change. Missing fields,
|
|
901
918
|
expired logins, denied requests, timeouts, and unsupported responses are shown
|
|
@@ -940,6 +957,9 @@ process.exitCode = await cli.run(process.argv.slice(2));
|
|
|
940
957
|
Each adapter owns discovery, identity matching, save verification, credential
|
|
941
958
|
storage, switching and process lifecycle, live status APIs, and diagnostics.
|
|
942
959
|
`readState()` and `readAccountStatus()` must never activate, switch or clear a login.
|
|
960
|
+
`readState()` may bring the saved copy of the active login onto the credential that login's
|
|
961
|
+
harness last wrote -- the Claude Code and Codex adapters do, because both harnesses rotate
|
|
962
|
+
the login they run -- and must write nothing else.
|
|
943
963
|
`readAccountStatus()` may renew the tokens of the saved copy it is reading, when the provider
|
|
944
964
|
gives it no other way to answer (the Claude Code adapter does, under the store's lock, for
|
|
945
965
|
saved and inactive logins only); it must never touch the active login's credential. `readAccountStatus(accountId,
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/classes.codexauth.ts
CHANGED
|
@@ -56,6 +56,90 @@ const findFirstJwt = (valueArg: unknown, depthArg = 0): string | null => {
|
|
|
56
56
|
return null;
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* A short, non-reversible label for an API key so two different keys get two
|
|
61
|
+
* different stashes without the key itself ever being written down.
|
|
62
|
+
*/
|
|
63
|
+
const fingerprint = (secretArg: string): string => {
|
|
64
|
+
let hash = 0x811c9dc5;
|
|
65
|
+
for (let index = 0; index < secretArg.length; index++) {
|
|
66
|
+
hash ^= secretArg.charCodeAt(index);
|
|
67
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
68
|
+
}
|
|
69
|
+
return hash.toString(16).padStart(8, '0');
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Extracts the account identity from the content of an auth.json.
|
|
74
|
+
* Returns null when the content holds no recognisable credential.
|
|
75
|
+
*
|
|
76
|
+
* It stands outside the class because the stash store keys and guards its entries by the same identity and has
|
|
77
|
+
* no Codex installation to read: the credential itself is all this derivation needs.
|
|
78
|
+
*/
|
|
79
|
+
export const codexIdentityFromRaw = (rawArg: string): ICodexIdentity | null => {
|
|
80
|
+
let parsed: unknown;
|
|
81
|
+
try {
|
|
82
|
+
parsed = JSON.parse(rawArg);
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const record = parsed as Record<string, unknown>;
|
|
90
|
+
|
|
91
|
+
const tokens = (record.tokens ?? null) as Record<string, unknown> | null;
|
|
92
|
+
const idToken =
|
|
93
|
+
(tokens ? asString(tokens.id_token) : null) ?? findFirstJwt(record);
|
|
94
|
+
|
|
95
|
+
if (idToken) {
|
|
96
|
+
const claims = decodeJwtPayload(idToken) ?? {};
|
|
97
|
+
const authClaim = (claims['https://api.openai.com/auth'] ?? {}) as Record<string, unknown>;
|
|
98
|
+
const profileClaim = (claims['https://api.openai.com/profile'] ?? {}) as Record<string, unknown>;
|
|
99
|
+
const email =
|
|
100
|
+
asString(claims.email) ??
|
|
101
|
+
asString(profileClaim.email) ??
|
|
102
|
+
asString(authClaim.user_email);
|
|
103
|
+
const accountId =
|
|
104
|
+
asString(authClaim.chatgpt_account_id) ??
|
|
105
|
+
(tokens ? asString(tokens.account_id) : null) ??
|
|
106
|
+
asString(record.account_id);
|
|
107
|
+
if (email) {
|
|
108
|
+
return {
|
|
109
|
+
kind: 'chatgpt',
|
|
110
|
+
email: email.toLowerCase(),
|
|
111
|
+
accountId,
|
|
112
|
+
planType: asString(authClaim.chatgpt_plan_type),
|
|
113
|
+
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (accountId) {
|
|
117
|
+
// An OAuth credential we cannot label by email is still worth stashing;
|
|
118
|
+
// key it by account id so it round-trips instead of being silently dropped.
|
|
119
|
+
return {
|
|
120
|
+
kind: 'chatgpt',
|
|
121
|
+
email: `account:${accountId}`,
|
|
122
|
+
accountId,
|
|
123
|
+
planType: asString(authClaim.chatgpt_plan_type),
|
|
124
|
+
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const apiKey = asString(record.OPENAI_API_KEY) ?? asString(record.openai_api_key);
|
|
130
|
+
if (apiKey) {
|
|
131
|
+
return {
|
|
132
|
+
kind: 'apikey',
|
|
133
|
+
email: `apikey:${fingerprint(apiKey)}`,
|
|
134
|
+
accountId: null,
|
|
135
|
+
planType: null,
|
|
136
|
+
userId: null,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return null;
|
|
141
|
+
};
|
|
142
|
+
|
|
59
143
|
/**
|
|
60
144
|
* Reads, writes and clears the Codex file credential store, and derives the
|
|
61
145
|
* account identity used to key a stash.
|
|
@@ -75,81 +159,7 @@ export class CodexAuth {
|
|
|
75
159
|
* Returns null when the file holds no recognisable credential.
|
|
76
160
|
*/
|
|
77
161
|
public identityFromRaw(rawArg: string): ICodexIdentity | null {
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
parsed = JSON.parse(rawArg);
|
|
81
|
-
} catch {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
const record = parsed as Record<string, unknown>;
|
|
88
|
-
|
|
89
|
-
const tokens = (record.tokens ?? null) as Record<string, unknown> | null;
|
|
90
|
-
const idToken =
|
|
91
|
-
(tokens ? asString(tokens.id_token) : null) ?? findFirstJwt(record);
|
|
92
|
-
|
|
93
|
-
if (idToken) {
|
|
94
|
-
const claims = decodeJwtPayload(idToken) ?? {};
|
|
95
|
-
const authClaim = (claims['https://api.openai.com/auth'] ?? {}) as Record<string, unknown>;
|
|
96
|
-
const profileClaim = (claims['https://api.openai.com/profile'] ?? {}) as Record<string, unknown>;
|
|
97
|
-
const email =
|
|
98
|
-
asString(claims.email) ??
|
|
99
|
-
asString(profileClaim.email) ??
|
|
100
|
-
asString(authClaim.user_email);
|
|
101
|
-
const accountId =
|
|
102
|
-
asString(authClaim.chatgpt_account_id) ??
|
|
103
|
-
(tokens ? asString(tokens.account_id) : null) ??
|
|
104
|
-
asString(record.account_id);
|
|
105
|
-
if (email) {
|
|
106
|
-
return {
|
|
107
|
-
kind: 'chatgpt',
|
|
108
|
-
email: email.toLowerCase(),
|
|
109
|
-
accountId,
|
|
110
|
-
planType: asString(authClaim.chatgpt_plan_type),
|
|
111
|
-
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
if (accountId) {
|
|
115
|
-
// An OAuth credential we cannot label by email is still worth stashing;
|
|
116
|
-
// key it by account id so it round-trips instead of being silently dropped.
|
|
117
|
-
return {
|
|
118
|
-
kind: 'chatgpt',
|
|
119
|
-
email: `account:${accountId}`,
|
|
120
|
-
accountId,
|
|
121
|
-
planType: asString(authClaim.chatgpt_plan_type),
|
|
122
|
-
userId: asString(authClaim.user_id) ?? asString(claims.sub),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const apiKey = asString(record.OPENAI_API_KEY) ?? asString(record.openai_api_key);
|
|
128
|
-
if (apiKey) {
|
|
129
|
-
const fingerprint = this.fingerprint(apiKey);
|
|
130
|
-
return {
|
|
131
|
-
kind: 'apikey',
|
|
132
|
-
email: `apikey:${fingerprint}`,
|
|
133
|
-
accountId: null,
|
|
134
|
-
planType: null,
|
|
135
|
-
userId: null,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* A short, non-reversible label for an API key so two different keys get two
|
|
144
|
-
* different stashes without the key itself ever being written down.
|
|
145
|
-
*/
|
|
146
|
-
private fingerprint(secretArg: string): string {
|
|
147
|
-
let hash = 0x811c9dc5;
|
|
148
|
-
for (let index = 0; index < secretArg.length; index++) {
|
|
149
|
-
hash ^= secretArg.charCodeAt(index);
|
|
150
|
-
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
151
|
-
}
|
|
152
|
-
return hash.toString(16).padStart(8, '0');
|
|
162
|
+
return codexIdentityFromRaw(rawArg);
|
|
153
163
|
}
|
|
154
164
|
|
|
155
165
|
/** Reads the active credential, if any. */
|
|
@@ -3,12 +3,21 @@ import { CodexAccountStatus } from './classes.codexstatus.js';
|
|
|
3
3
|
import { CodexPreuse } from './classes.codexpreuse.js';
|
|
4
4
|
import { PreuseError } from './preuse.js';
|
|
5
5
|
import type { IAuthHarness, IHarnessAccount, IHarnessAccountStatus, IHarnessOutcome, IHarnessState, IHarnessPreuseOptions, IHarnessPreuseResult, IHarnessStatusOptions } from './interfaces.harness.js';
|
|
6
|
-
import type { IStashListing } from './interfaces.js';
|
|
6
|
+
import type { IActiveAuth, ICodexIdentity, IStashEntry, IStashListing } from './interfaces.js';
|
|
7
7
|
import { countPaired, enrollmentState } from './helpers.js';
|
|
8
8
|
import { beginSavedOpenAiLogin } from './classes.login.js';
|
|
9
9
|
import { plainText } from './formatting.js';
|
|
10
10
|
import type { IHarnessLoginOptions, IHarnessLoginProvider } from './interfaces.harness.js';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Why a write into the stash failed, as its system error code. The message of a filesystem error names the path
|
|
14
|
+
* it was writing, and that path leads to a credential.
|
|
15
|
+
*/
|
|
16
|
+
const writeFailureCause = (errorArg: unknown): string => {
|
|
17
|
+
const code = (errorArg as { code?: unknown } | null)?.code;
|
|
18
|
+
return typeof code === 'string' ? code : 'unknown cause';
|
|
19
|
+
};
|
|
20
|
+
|
|
12
21
|
/** Codex-specific credentials, remote-control handling and service status. */
|
|
13
22
|
export class CodexHarness implements IAuthHarness {
|
|
14
23
|
public readonly id = 'codex';
|
|
@@ -43,21 +52,28 @@ export class CodexHarness implements IAuthHarness {
|
|
|
43
52
|
}, options);
|
|
44
53
|
}
|
|
45
54
|
|
|
55
|
+
/**
|
|
56
|
+
* The harness's accounts, with the saved copy of the active login brought up to date first.
|
|
57
|
+
*
|
|
58
|
+
* A saved login is one whose stored credential is readable and belongs to the account its record names. The
|
|
59
|
+
* exact tokens are not part of that: Codex' app-server refreshes the login it runs on its own schedule, so
|
|
60
|
+
* comparing bytes reported every saved active login as unsaved from its first refresh on, and the guide then
|
|
61
|
+
* offered to save what was already saved.
|
|
62
|
+
*/
|
|
46
63
|
public readState(): IHarnessState {
|
|
47
64
|
const active = this.switcher.readActive();
|
|
65
|
+
const mirrorFailure = this.mirrorActiveLogin(active);
|
|
48
66
|
const accounts: IHarnessAccount[] = this.switcher.list().map((entryArg) => {
|
|
49
67
|
const raw = this.switcher.stashes.readAuth(entryArg.email);
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const isActive = active.identity !== null && active.identity.email === entryArg.email && active.identity.accountId === entryArg.accountId && active.identity.kind === entryArg.kind;
|
|
53
|
-
const isStashed = valid && (!isActive || raw === active.raw);
|
|
68
|
+
const isStashed = this.recordOf(entryArg, raw === null ? null : this.switcher.auth.identityFromRaw(raw));
|
|
69
|
+
const isActive = this.recordOf(entryArg, active.identity);
|
|
54
70
|
return {
|
|
55
71
|
id: entryArg.email,
|
|
56
72
|
label: entryArg.email,
|
|
57
73
|
isActive,
|
|
58
74
|
isStashed,
|
|
59
75
|
savedAt: entryArg.stashedAt,
|
|
60
|
-
details: [this.formatRemoteControl(entryArg).trim(), ...(!
|
|
76
|
+
details: [this.formatRemoteControl(entryArg).trim(), ...(!isStashed ? ['saved credential missing or does not match its metadata'] : isActive && mirrorFailure !== null ? [mirrorFailure] : [])],
|
|
61
77
|
};
|
|
62
78
|
});
|
|
63
79
|
if (active.identity && !accounts.some((accountArg) => accountArg.isActive)) {
|
|
@@ -74,6 +90,42 @@ export class CodexHarness implements IAuthHarness {
|
|
|
74
90
|
};
|
|
75
91
|
}
|
|
76
92
|
|
|
93
|
+
/** Whether a saved record is the record of this identity: same account, same email, same kind of login. */
|
|
94
|
+
private recordOf(entryArg: IStashEntry, identityArg: ICodexIdentity | null): boolean {
|
|
95
|
+
return identityArg !== null && entryArg.email === identityArg.email && entryArg.accountId === identityArg.accountId && entryArg.kind === identityArg.kind;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Writes the credential Codex is running on into that account's own saved record, and reports why it could
|
|
100
|
+
* not when the write failed.
|
|
101
|
+
*
|
|
102
|
+
* Codex rotates the tokens of the active login, and until now only a switch or a save wrote that rotation
|
|
103
|
+
* back -- `use()` re-saves the outgoing login, and re-selecting the active account updates its record before
|
|
104
|
+
* restoring the pairings. Every read now keeps the saved copy on the credential Codex last wrote, so the copy
|
|
105
|
+
* is one a switch can restore rather than one the service has moved past.
|
|
106
|
+
*
|
|
107
|
+
* The write goes only into the stash: Codex' own files are read, nothing is stopped or signalled, no daemon
|
|
108
|
+
* has to be down for it, and the record keeps its save time and its enrollments. A login with no saved record
|
|
109
|
+
* of its own is never saved implicitly -- `stash` is what saves a login -- and a record whose credential is
|
|
110
|
+
* missing or belongs to another account is left for `stash` to repair rather than quietly overwritten.
|
|
111
|
+
*/
|
|
112
|
+
private mirrorActiveLogin(activeArg: IActiveAuth): string | null {
|
|
113
|
+
if (activeArg.source !== 'file' || activeArg.identity === null || activeArg.raw === null) return null;
|
|
114
|
+
const email = activeArg.identity.email;
|
|
115
|
+
const saved = this.switcher.stashes.readAuth(email);
|
|
116
|
+
if (saved === null || saved === activeArg.raw) return null;
|
|
117
|
+
const meta = this.switcher.stashes.readMeta(email);
|
|
118
|
+
if (meta === null || !this.recordOf(meta, activeArg.identity) || !this.recordOf(meta, this.switcher.auth.identityFromRaw(saved))) return null;
|
|
119
|
+
try {
|
|
120
|
+
this.switcher.stashes.replaceAuth(email, activeArg.raw);
|
|
121
|
+
return null;
|
|
122
|
+
} catch (errorArg) {
|
|
123
|
+
// A saved copy that could not be brought up to date is no reason to fail a read: the record still holds a
|
|
124
|
+
// credential of this account, and the next read tries again.
|
|
125
|
+
return `the current login could not be copied into its saved record (${writeFailureCause(errorArg)}); the record still holds the credential from the last save`;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
77
129
|
public async readAccountStatus(accountIdArg: string, optionsArg?: IHarnessStatusOptions): Promise<IHarnessAccountStatus> {
|
|
78
130
|
const credential = this.readAccountCredential(accountIdArg);
|
|
79
131
|
if (!credential) return { facts: [], problems: ['No matching credential is available for status lookup.'] };
|
package/ts/classes.stashstore.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
THarnessName,
|
|
7
7
|
} from './interfaces.js';
|
|
8
8
|
import { writeSecretFileAtomically } from './helpers.js';
|
|
9
|
+
import { codexIdentityFromRaw } from './classes.codexauth.js';
|
|
9
10
|
|
|
10
11
|
const AUTH_FILE_NAME = 'auth.json';
|
|
11
12
|
const META_FILE_NAME = 'stash.json';
|
|
@@ -105,6 +106,27 @@ export class StashStore {
|
|
|
105
106
|
return entry;
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Replaces the credential of an existing stash and leaves its metadata exactly as it is.
|
|
111
|
+
*
|
|
112
|
+
* Codex refreshes the login it is running on its own schedule, so a saved copy of that login holds older
|
|
113
|
+
* tokens until something writes the rotation back. Doing so is an update of one account's credential, not a
|
|
114
|
+
* new save: the record keeps its account, its enrollments and the moment it was saved, which `write()` would
|
|
115
|
+
* stamp anew. The credential must belong to the account the metadata names -- the same guard `write()`
|
|
116
|
+
* applies -- so a mirror can never move one account's login into another account's record.
|
|
117
|
+
*/
|
|
118
|
+
public replaceAuth(emailArg: string, rawAuthArg: string): void {
|
|
119
|
+
const meta = this.readMeta(emailArg);
|
|
120
|
+
if (!meta) {
|
|
121
|
+
throw new Error(`no stash for "${emailArg}" whose credential could be replaced`);
|
|
122
|
+
}
|
|
123
|
+
const identity = codexIdentityFromRaw(rawAuthArg);
|
|
124
|
+
if (!identity || identity.email !== meta.email || identity.accountId !== meta.accountId || identity.kind !== meta.kind) {
|
|
125
|
+
throw new Error('the credential does not belong to the account this stash holds; refusing to replace it');
|
|
126
|
+
}
|
|
127
|
+
writeSecretFileAtomically(plugins.path.join(this.entryDir(emailArg), AUTH_FILE_NAME), rawAuthArg);
|
|
128
|
+
}
|
|
129
|
+
|
|
108
130
|
/**
|
|
109
131
|
* Reads a stash back and confirms it matches what was meant to be written.
|
|
110
132
|
* Callers use this before clearing the active credential, so a stash is only
|