|
1 | | -import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync, statSync } from 'fs'; |
2 | | -import { getCredentialsPath, ensureConfigDir } from '../config/paths'; |
| 1 | +import { readConfigFile, writeConfigFile } from '../config/loader'; |
3 | 2 | import type { CredentialFile } from './types'; |
4 | 3 |
|
5 | | -export async function loadCredentials(): Promise<CredentialFile | null> { |
6 | | - const path = getCredentialsPath(); |
7 | | - if (!existsSync(path)) return null; |
| 4 | +/** |
| 5 | + * OAuth credentials live inside the user's main config file |
| 6 | + * (`~/.mmx/config.json`) under the `oauth` subobject. This keeps a |
| 7 | + * single source of truth for all CLI state. |
| 8 | + */ |
8 | 9 |
|
9 | | - try { |
10 | | - checkPermissions(path); |
11 | | - const raw = readFileSync(path, 'utf-8'); |
12 | | - const data = JSON.parse(raw) as CredentialFile; |
13 | | - if (!data.access_token || !data.refresh_token) return null; |
14 | | - return data; |
15 | | - } catch (err) { |
16 | | - const e = err as Error; |
17 | | - if (e instanceof SyntaxError || e.message.includes('JSON')) { |
18 | | - process.stderr.write(`Warning: credentials file is corrupted. Run 'mmx auth logout' to reset.\n`); |
19 | | - } |
20 | | - return null; |
21 | | - } |
| 10 | +export async function loadCredentials(): Promise<CredentialFile | null> { |
| 11 | + const cfg = readConfigFile(); |
| 12 | + return cfg.oauth ?? null; |
22 | 13 | } |
23 | 14 |
|
24 | 15 | export async function saveCredentials(creds: CredentialFile): Promise<void> { |
25 | | - await ensureConfigDir(); |
26 | | - const path = getCredentialsPath(); |
27 | | - const tmp = path + '.tmp'; |
28 | | - writeFileSync(tmp, JSON.stringify(creds, null, 2) + '\n', { mode: 0o600 }); |
29 | | - renameSync(tmp, path); |
| 16 | + const existing = readConfigFile() as Record<string, unknown>; |
| 17 | + existing.oauth = creds; |
| 18 | + await writeConfigFile(existing); |
30 | 19 | } |
31 | 20 |
|
32 | 21 | export async function clearCredentials(): Promise<void> { |
33 | | - const path = getCredentialsPath(); |
34 | | - if (existsSync(path)) { |
35 | | - unlinkSync(path); |
36 | | - } |
37 | | -} |
38 | | - |
39 | | -function checkPermissions(path: string): void { |
40 | | - try { |
41 | | - const stat = statSync(path); |
42 | | - const mode = stat.mode & 0o777; |
43 | | - if (mode !== 0o600) { |
44 | | - process.stderr.write( |
45 | | - `Warning: ${path} has permissions ${mode.toString(8)}, expected 600.\n`, |
46 | | - ); |
47 | | - } |
48 | | - } catch { |
49 | | - // Ignore permission check errors on platforms that don't support it |
50 | | - } |
| 22 | + const existing = readConfigFile() as Record<string, unknown>; |
| 23 | + if (!('oauth' in existing)) return; |
| 24 | + delete existing.oauth; |
| 25 | + await writeConfigFile(existing); |
51 | 26 | } |
0 commit comments