axauth 1.0.0 → 1.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/README.md +201 -84
- package/dist/auth/adapter.d.ts +51 -17
- package/dist/auth/agents/{claude-code-storage.d.ts → claude-storage.d.ts} +13 -5
- package/dist/auth/agents/{claude-code-storage.js → claude-storage.js} +51 -3
- package/dist/auth/agents/{claude-code.js → claude.js} +29 -61
- package/dist/auth/agents/codex-config.js +1 -1
- package/dist/auth/agents/codex.js +23 -12
- package/dist/auth/agents/copilot-storage.js +1 -2
- package/dist/auth/agents/copilot.js +22 -9
- package/dist/auth/agents/gemini-auth-check.d.ts +3 -3
- package/dist/auth/agents/gemini-auth-check.js +32 -45
- package/dist/auth/agents/gemini-install.d.ts +11 -0
- package/dist/auth/agents/gemini-install.js +115 -0
- package/dist/auth/agents/gemini-storage.d.ts +2 -4
- package/dist/auth/agents/gemini-storage.js +4 -12
- package/dist/auth/agents/gemini.js +13 -86
- package/dist/auth/agents/opencode-schema.d.ts +24 -0
- package/dist/auth/agents/opencode-schema.js +42 -0
- package/dist/auth/agents/opencode.d.ts +4 -0
- package/dist/auth/agents/opencode.js +49 -13
- package/dist/auth/registry.d.ts +45 -8
- package/dist/auth/registry.js +91 -8
- package/dist/auth/resolve-config-directory.d.ts +11 -7
- package/dist/auth/resolve-config-directory.js +12 -8
- package/dist/auth/types.d.ts +26 -8
- package/dist/auth/types.js +20 -1
- package/dist/auth/validate-directories.d.ts +25 -0
- package/dist/auth/validate-directories.js +29 -0
- package/dist/cli.js +19 -4
- package/dist/commands/auth.d.ts +5 -11
- package/dist/commands/auth.js +15 -74
- package/dist/commands/install-credentials.d.ts +16 -0
- package/dist/commands/install-credentials.js +77 -0
- package/dist/commands/validate-agent.d.ts +14 -0
- package/dist/commands/validate-agent.js +22 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +5 -4
- /package/dist/auth/agents/{claude-code.d.ts → claude.d.ts} +0 -0
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Supports OAuth via keychain (macOS) or file, and API key via env var.
|
|
5
5
|
*/
|
|
6
|
+
import path from "node:path";
|
|
6
7
|
import { isMacOS } from "../keychain.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
8
|
+
import { resolveCustomDirectory } from "../validate-directories.js";
|
|
9
|
+
import { AGENT_ID, checkAuth, deleteFileCreds, deleteKeychainCreds, extractRawCredentials, getDefaultCredsFilePath, saveFileCreds, saveKeychainCreds, } from "./claude-storage.js";
|
|
10
|
+
const CREDS_FILE_NAME = ".credentials.json";
|
|
9
11
|
/** Claude Code authentication adapter */
|
|
10
12
|
const claudeCodeAdapter = {
|
|
11
13
|
agentId: AGENT_ID,
|
|
@@ -16,60 +18,20 @@ const claudeCodeAdapter = {
|
|
|
16
18
|
installApiKey: false,
|
|
17
19
|
},
|
|
18
20
|
checkAuth() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
const keychainCreds = loadKeychainCreds();
|
|
23
|
-
if (keychainCreds) {
|
|
24
|
-
const subType = keychainCreds.subscriptionType;
|
|
25
|
-
return {
|
|
26
|
-
agentId: AGENT_ID,
|
|
27
|
-
authenticated: true,
|
|
28
|
-
method: `OAuth (${subType ?? "keychain"})`,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
if (loadFileCreds()) {
|
|
32
|
-
return { agentId: AGENT_ID, authenticated: true, method: "OAuth (file)" };
|
|
33
|
-
}
|
|
34
|
-
if (process.env.ANTHROPIC_API_KEY) {
|
|
35
|
-
return { agentId: AGENT_ID, authenticated: true, method: "API key" };
|
|
36
|
-
}
|
|
37
|
-
return { agentId: AGENT_ID, authenticated: false };
|
|
21
|
+
const result = checkAuth();
|
|
22
|
+
return { agentId: AGENT_ID, ...result };
|
|
38
23
|
},
|
|
39
24
|
extractRawCredentials() {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
data: { accessToken: process.env.CLAUDE_CODE_OAUTH_TOKEN },
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
const keychainCreds = loadKeychainCreds();
|
|
48
|
-
if (keychainCreds) {
|
|
49
|
-
return {
|
|
50
|
-
agent: AGENT_ID,
|
|
51
|
-
type: "oauth",
|
|
52
|
-
data: { ...keychainCreds, _source: "keychain" },
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
const fileCreds = loadFileCreds();
|
|
56
|
-
if (fileCreds) {
|
|
57
|
-
return {
|
|
58
|
-
agent: AGENT_ID,
|
|
59
|
-
type: "oauth",
|
|
60
|
-
data: { ...fileCreds, _source: "file" },
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
if (process.env.ANTHROPIC_API_KEY) {
|
|
64
|
-
return {
|
|
65
|
-
agent: AGENT_ID,
|
|
66
|
-
type: "api-key",
|
|
67
|
-
data: { apiKey: process.env.ANTHROPIC_API_KEY },
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
return undefined;
|
|
25
|
+
const result = extractRawCredentials();
|
|
26
|
+
if (!result)
|
|
27
|
+
return undefined;
|
|
28
|
+
return { agent: AGENT_ID, ...result };
|
|
71
29
|
},
|
|
72
30
|
installCredentials(creds, options) {
|
|
31
|
+
// Resolve custom directory with validation
|
|
32
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
33
|
+
if (!resolved.ok)
|
|
34
|
+
return resolved.error;
|
|
73
35
|
if (creds.type === "api-key") {
|
|
74
36
|
return {
|
|
75
37
|
ok: false,
|
|
@@ -77,17 +39,18 @@ const claudeCodeAdapter = {
|
|
|
77
39
|
};
|
|
78
40
|
}
|
|
79
41
|
const { _source, ...oauthData } = creds.data;
|
|
80
|
-
// Custom
|
|
81
|
-
if (
|
|
82
|
-
|
|
42
|
+
// Custom directory forces file storage (keychain only for default location)
|
|
43
|
+
if (resolved.customDir) {
|
|
44
|
+
const targetPath = path.join(resolved.customDir, CREDS_FILE_NAME);
|
|
45
|
+
if (saveFileCreds(oauthData, targetPath)) {
|
|
83
46
|
return {
|
|
84
47
|
ok: true,
|
|
85
|
-
message: `Installed credentials to ${
|
|
48
|
+
message: `Installed credentials to ${targetPath}`,
|
|
86
49
|
};
|
|
87
50
|
}
|
|
88
51
|
return {
|
|
89
52
|
ok: false,
|
|
90
|
-
message: `Failed to install credentials to ${
|
|
53
|
+
message: `Failed to install credentials to ${targetPath}`,
|
|
91
54
|
};
|
|
92
55
|
}
|
|
93
56
|
// Default location: use storage option or _source marker
|
|
@@ -114,10 +77,15 @@ const claudeCodeAdapter = {
|
|
|
114
77
|
};
|
|
115
78
|
},
|
|
116
79
|
removeCredentials(options) {
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
80
|
+
// Resolve custom directory with validation
|
|
81
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
82
|
+
if (!resolved.ok)
|
|
83
|
+
return resolved.error;
|
|
84
|
+
// Custom directory: only remove that specific file (no keychain)
|
|
85
|
+
if (resolved.customDir) {
|
|
86
|
+
const targetPath = path.join(resolved.customDir, CREDS_FILE_NAME);
|
|
87
|
+
if (deleteFileCreds(targetPath)) {
|
|
88
|
+
return { ok: true, message: `Removed ${targetPath}` };
|
|
121
89
|
}
|
|
122
90
|
return {
|
|
123
91
|
ok: true,
|
|
@@ -8,7 +8,7 @@ import { codexConfigReader } from "axconfig";
|
|
|
8
8
|
import { getResolvedConfigDirectory } from "../resolve-config-directory.js";
|
|
9
9
|
/** Get the codex home directory */
|
|
10
10
|
function getCodexHome() {
|
|
11
|
-
return getResolvedConfigDirectory(
|
|
11
|
+
return getResolvedConfigDirectory("codex");
|
|
12
12
|
}
|
|
13
13
|
/** Get auth file path */
|
|
14
14
|
function getAuthFilePath() {
|
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { ensureDirectory } from "../file-storage.js";
|
|
8
8
|
import { isMacOS } from "../keychain.js";
|
|
9
|
+
import { resolveCustomDirectory } from "../validate-directories.js";
|
|
9
10
|
import { checkAuth, extractRawCredentials } from "./codex-auth-check.js";
|
|
10
11
|
import { getAuthFilePath, getCodexHome, updateConfigStorage, } from "./codex-config.js";
|
|
11
12
|
import { buildAuthContent, deleteFileCreds, deleteKeychainCreds, saveFileCreds, saveKeychainCreds, } from "./codex-storage.js";
|
|
12
13
|
const AGENT_ID = "codex";
|
|
14
|
+
const CREDS_FILE_NAME = "auth.json";
|
|
13
15
|
/** Codex authentication adapter */
|
|
14
16
|
const codexAdapter = {
|
|
15
17
|
agentId: AGENT_ID,
|
|
@@ -22,25 +24,29 @@ const codexAdapter = {
|
|
|
22
24
|
checkAuth,
|
|
23
25
|
extractRawCredentials,
|
|
24
26
|
installCredentials(creds, options) {
|
|
27
|
+
// Resolve custom directory with validation
|
|
28
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
29
|
+
if (!resolved.ok)
|
|
30
|
+
return resolved.error;
|
|
25
31
|
const authContent = buildAuthContent(creds.type, creds.data);
|
|
26
|
-
// Custom
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
if (!ensureDirectory(parentDirectory)) {
|
|
32
|
+
// Custom directory forces file storage (keychain only for default location)
|
|
33
|
+
if (resolved.customDir) {
|
|
34
|
+
if (!ensureDirectory(resolved.customDir)) {
|
|
30
35
|
return {
|
|
31
36
|
ok: false,
|
|
32
|
-
message: `Failed to create directory ${
|
|
37
|
+
message: `Failed to create directory ${resolved.customDir}`,
|
|
33
38
|
};
|
|
34
39
|
}
|
|
35
|
-
|
|
40
|
+
const targetPath = path.join(resolved.customDir, CREDS_FILE_NAME);
|
|
41
|
+
if (saveFileCreds(authContent, targetPath)) {
|
|
36
42
|
return {
|
|
37
43
|
ok: true,
|
|
38
|
-
message: `Installed credentials to ${
|
|
44
|
+
message: `Installed credentials to ${targetPath}`,
|
|
39
45
|
};
|
|
40
46
|
}
|
|
41
47
|
return {
|
|
42
48
|
ok: false,
|
|
43
|
-
message: `Failed to install credentials to ${
|
|
49
|
+
message: `Failed to install credentials to ${targetPath}`,
|
|
44
50
|
};
|
|
45
51
|
}
|
|
46
52
|
// Default location: use storage option or _source marker
|
|
@@ -72,10 +78,15 @@ const codexAdapter = {
|
|
|
72
78
|
return { ok: false, message: "Failed to install credentials to file" };
|
|
73
79
|
},
|
|
74
80
|
removeCredentials(options) {
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
// Resolve custom directory with validation
|
|
82
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
83
|
+
if (!resolved.ok)
|
|
84
|
+
return resolved.error;
|
|
85
|
+
// Custom directory: only remove that specific file (no keychain)
|
|
86
|
+
if (resolved.customDir) {
|
|
87
|
+
const targetPath = path.join(resolved.customDir, CREDS_FILE_NAME);
|
|
88
|
+
if (deleteFileCreds(targetPath)) {
|
|
89
|
+
return { ok: true, message: `Removed ${targetPath}` };
|
|
79
90
|
}
|
|
80
91
|
return {
|
|
81
92
|
ok: true,
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { existsSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
9
9
|
import path from "node:path";
|
|
10
|
-
import { copilotConfigReader } from "axconfig";
|
|
11
10
|
import { ensureDirectory, loadJsonFile, saveJsonFile, } from "../file-storage.js";
|
|
12
11
|
import { deleteFromKeychain, isMacOS, loadFromKeychain, saveToKeychain, } from "../keychain.js";
|
|
13
12
|
import { getResolvedConfigDirectory } from "../resolve-config-directory.js";
|
|
@@ -15,7 +14,7 @@ const KEYCHAIN_SERVICE = "copilot-cli";
|
|
|
15
14
|
const DEFAULT_HOST = "https://github.com";
|
|
16
15
|
/** Get the copilot config directory */
|
|
17
16
|
function getConfigDirectory() {
|
|
18
|
-
return getResolvedConfigDirectory(
|
|
17
|
+
return getResolvedConfigDirectory("copilot");
|
|
19
18
|
}
|
|
20
19
|
/** Get the default config file path */
|
|
21
20
|
function getConfigFilePath() {
|
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* Supports OAuth via keychain (macOS) or file, and GitHub token via env var.
|
|
5
5
|
* Also supports GitHub CLI (`gh auth login`) as a fallback.
|
|
6
6
|
*/
|
|
7
|
+
import path from "node:path";
|
|
7
8
|
import { ensureDirectory } from "../file-storage.js";
|
|
8
9
|
import { isMacOS } from "../keychain.js";
|
|
10
|
+
import { resolveCustomDirectory } from "../validate-directories.js";
|
|
9
11
|
import { findFirstAvailableToken } from "./copilot-auth-check.js";
|
|
10
12
|
import { deleteFileToken, deleteKeychainToken, deleteTokenFromPath, getConfigDirectory, getConfigFilePath, saveFileToken, saveKeychainToken, saveTokenToPath, } from "./copilot-storage.js";
|
|
11
13
|
const AGENT_ID = "copilot";
|
|
14
|
+
const CREDS_FILE_NAME = "token.json";
|
|
12
15
|
/** Copilot CLI authentication adapter */
|
|
13
16
|
const copilotAdapter = {
|
|
14
17
|
agentId: AGENT_ID,
|
|
@@ -46,6 +49,10 @@ const copilotAdapter = {
|
|
|
46
49
|
};
|
|
47
50
|
},
|
|
48
51
|
installCredentials(creds, options) {
|
|
52
|
+
// Resolve custom directory with validation
|
|
53
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
54
|
+
if (!resolved.ok)
|
|
55
|
+
return resolved.error;
|
|
49
56
|
if (creds.type === "api-key") {
|
|
50
57
|
return {
|
|
51
58
|
ok: false,
|
|
@@ -58,17 +65,18 @@ const copilotAdapter = {
|
|
|
58
65
|
if (!token) {
|
|
59
66
|
return { ok: false, message: "No access token found in credentials" };
|
|
60
67
|
}
|
|
61
|
-
// Custom
|
|
62
|
-
if (
|
|
63
|
-
|
|
68
|
+
// Custom directory forces file storage
|
|
69
|
+
if (resolved.customDir) {
|
|
70
|
+
const targetPath = path.join(resolved.customDir, CREDS_FILE_NAME);
|
|
71
|
+
if (saveTokenToPath(token, targetPath)) {
|
|
64
72
|
return {
|
|
65
73
|
ok: true,
|
|
66
|
-
message: `Installed credentials to ${
|
|
74
|
+
message: `Installed credentials to ${targetPath}`,
|
|
67
75
|
};
|
|
68
76
|
}
|
|
69
77
|
return {
|
|
70
78
|
ok: false,
|
|
71
|
-
message: `Failed to install credentials to ${
|
|
79
|
+
message: `Failed to install credentials to ${targetPath}`,
|
|
72
80
|
};
|
|
73
81
|
}
|
|
74
82
|
// Default location: use storage option or _source marker
|
|
@@ -102,10 +110,15 @@ const copilotAdapter = {
|
|
|
102
110
|
return { ok: false, message: "Failed to install credentials to file" };
|
|
103
111
|
},
|
|
104
112
|
removeCredentials(options) {
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
113
|
+
// Resolve custom directory with validation
|
|
114
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
115
|
+
if (!resolved.ok)
|
|
116
|
+
return resolved.error;
|
|
117
|
+
// Custom directory: only remove that specific file
|
|
118
|
+
if (resolved.customDir) {
|
|
119
|
+
const targetPath = path.join(resolved.customDir, CREDS_FILE_NAME);
|
|
120
|
+
if (deleteTokenFromPath(targetPath)) {
|
|
121
|
+
return { ok: true, message: `Removed ${targetPath}` };
|
|
109
122
|
}
|
|
110
123
|
return {
|
|
111
124
|
ok: true,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gemini CLI authentication checking.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Uses priority-ordered credential discovery: env → keychain → file.
|
|
5
5
|
*/
|
|
6
6
|
/** Credential source for auth method display */
|
|
7
|
-
type CredentialSource = "keychain" | "file" | "api-key" | "vertex-ai"
|
|
7
|
+
type CredentialSource = "keychain" | "file" | "api-key" | "vertex-ai";
|
|
8
8
|
/** Result of finding available credentials */
|
|
9
9
|
interface CredentialResult {
|
|
10
10
|
source: CredentialSource;
|
|
11
11
|
method: string;
|
|
12
12
|
data?: Record<string, unknown>;
|
|
13
13
|
}
|
|
14
|
-
/** Find credentials
|
|
14
|
+
/** Find credentials using priority-ordered discovery: env → keychain → file */
|
|
15
15
|
declare function findCredentials(): CredentialResult | undefined;
|
|
16
16
|
export { findCredentials };
|
|
@@ -1,51 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gemini CLI authentication checking.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Uses priority-ordered credential discovery: env → keychain → file.
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync } from "node:fs";
|
|
7
|
-
import {
|
|
8
|
-
/** Check
|
|
9
|
-
function
|
|
10
|
-
const keychainCreds = loadKeychainCreds();
|
|
11
|
-
if (keychainCreds) {
|
|
12
|
-
return {
|
|
13
|
-
source: "keychain",
|
|
14
|
-
method: "Google OAuth (keychain)",
|
|
15
|
-
data: keychainCreds,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
if (existsSync(getDefaultOAuthPath())) {
|
|
19
|
-
const fileCreds = loadOAuthCreds();
|
|
20
|
-
if (fileCreds) {
|
|
21
|
-
return {
|
|
22
|
-
source: "file",
|
|
23
|
-
method: "Google OAuth (file)",
|
|
24
|
-
data: fileCreds,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
/** Check API key credentials */
|
|
31
|
-
function checkApiKeyCredentials() {
|
|
7
|
+
import { getDefaultOAuthPath, loadKeychainCreds, loadOAuthCreds, } from "./gemini-storage.js";
|
|
8
|
+
/** Check environment variable credentials (API key and Vertex AI) */
|
|
9
|
+
function checkEnvironmentAuth() {
|
|
32
10
|
if (process.env.GEMINI_API_KEY) {
|
|
33
11
|
return {
|
|
34
12
|
source: "api-key",
|
|
35
|
-
method: "API key",
|
|
13
|
+
method: "API key (env)",
|
|
36
14
|
data: { apiKey: process.env.GEMINI_API_KEY },
|
|
37
15
|
};
|
|
38
16
|
}
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
/** Check Vertex AI credentials */
|
|
42
|
-
function checkVertexAiCredentials() {
|
|
43
17
|
const hasVertexEnvironment = (process.env.GOOGLE_CLOUD_PROJECT && process.env.GOOGLE_CLOUD_LOCATION) ||
|
|
44
18
|
process.env.GOOGLE_API_KEY;
|
|
45
19
|
if (hasVertexEnvironment) {
|
|
46
20
|
return {
|
|
47
21
|
source: "vertex-ai",
|
|
48
|
-
method: "Vertex AI",
|
|
22
|
+
method: "Vertex AI (env)",
|
|
49
23
|
data: process.env.GOOGLE_API_KEY
|
|
50
24
|
? { apiKey: process.env.GOOGLE_API_KEY }
|
|
51
25
|
: undefined,
|
|
@@ -53,21 +27,34 @@ function checkVertexAiCredentials() {
|
|
|
53
27
|
}
|
|
54
28
|
return undefined;
|
|
55
29
|
}
|
|
56
|
-
/**
|
|
57
|
-
function
|
|
58
|
-
const
|
|
59
|
-
if (
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (authType === "vertex-ai") {
|
|
66
|
-
return checkVertexAiCredentials();
|
|
30
|
+
/** Check keychain for OAuth credentials */
|
|
31
|
+
function checkKeychainAuth() {
|
|
32
|
+
const keychainCreds = loadKeychainCreds();
|
|
33
|
+
if (keychainCreds) {
|
|
34
|
+
return {
|
|
35
|
+
source: "keychain",
|
|
36
|
+
method: "Google OAuth (keychain)",
|
|
37
|
+
data: keychainCreds,
|
|
38
|
+
};
|
|
67
39
|
}
|
|
68
|
-
|
|
69
|
-
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
/** Check file for OAuth credentials */
|
|
43
|
+
function checkFileAuth() {
|
|
44
|
+
if (existsSync(getDefaultOAuthPath())) {
|
|
45
|
+
const fileCreds = loadOAuthCreds();
|
|
46
|
+
if (fileCreds) {
|
|
47
|
+
return {
|
|
48
|
+
source: "file",
|
|
49
|
+
method: "Google OAuth (file)",
|
|
50
|
+
data: fileCreds,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
70
53
|
}
|
|
71
54
|
return undefined;
|
|
72
55
|
}
|
|
56
|
+
/** Find credentials using priority-ordered discovery: env → keychain → file */
|
|
57
|
+
function findCredentials() {
|
|
58
|
+
return checkEnvironmentAuth() ?? checkKeychainAuth() ?? checkFileAuth();
|
|
59
|
+
}
|
|
73
60
|
export { findCredentials };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini credential installation operations.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from gemini.ts to reduce file complexity.
|
|
5
|
+
*/
|
|
6
|
+
import type { InstallOptions, OperationResult, RemoveOptions } from "../adapter.js";
|
|
7
|
+
/** Install OAuth credentials to storage */
|
|
8
|
+
declare function installOAuthCredentials(oauthData: Record<string, unknown>, source: string | undefined, options?: InstallOptions): OperationResult;
|
|
9
|
+
/** Remove credentials from storage */
|
|
10
|
+
declare function removeGeminiCredentials(options?: RemoveOptions): OperationResult;
|
|
11
|
+
export { installOAuthCredentials, removeGeminiCredentials };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini credential installation operations.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from gemini.ts to reduce file complexity.
|
|
5
|
+
*/
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { ensureDirectory } from "../file-storage.js";
|
|
8
|
+
import { isMacOS } from "../keychain.js";
|
|
9
|
+
import { resolveCustomDirectory } from "../validate-directories.js";
|
|
10
|
+
import { clearAuthTypeFromSettings, deleteKeychainCreds, deleteOAuthCreds, getDefaultOAuthPath, saveKeychainCreds, saveOAuthCreds, setAuthTypeInSettings, } from "./gemini-storage.js";
|
|
11
|
+
const AGENT_ID = "gemini";
|
|
12
|
+
const CREDS_FILE_NAME = "oauth_creds.json";
|
|
13
|
+
/** Install OAuth credentials to storage */
|
|
14
|
+
function installOAuthCredentials(oauthData, source, options) {
|
|
15
|
+
// Resolve custom directory with validation
|
|
16
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
17
|
+
if (!resolved.ok)
|
|
18
|
+
return resolved.error;
|
|
19
|
+
// Custom directory forces file storage
|
|
20
|
+
if (resolved.customDir) {
|
|
21
|
+
return installToCustomDirectory(oauthData, resolved.customDir);
|
|
22
|
+
}
|
|
23
|
+
// Default location: use storage option or _source marker
|
|
24
|
+
const targetStorage = options?.storage ?? (source === "keychain" ? "keychain" : "file");
|
|
25
|
+
if (targetStorage === "keychain") {
|
|
26
|
+
return installToKeychain(oauthData);
|
|
27
|
+
}
|
|
28
|
+
return installToDefaultFile(oauthData);
|
|
29
|
+
}
|
|
30
|
+
/** Install to custom directory */
|
|
31
|
+
function installToCustomDirectory(oauthData, customDirectory) {
|
|
32
|
+
if (!ensureDirectory(customDirectory)) {
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
message: `Failed to create directory ${customDirectory}`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const targetPath = path.join(customDirectory, CREDS_FILE_NAME);
|
|
39
|
+
if (!saveOAuthCreds(oauthData, targetPath)) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
message: `Failed to install credentials to ${targetPath}`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (!setAuthTypeInSettings("oauth-personal", customDirectory)) {
|
|
46
|
+
return { ok: false, message: "Failed to update settings" };
|
|
47
|
+
}
|
|
48
|
+
return { ok: true, message: `Installed credentials to ${targetPath}` };
|
|
49
|
+
}
|
|
50
|
+
/** Install to macOS Keychain */
|
|
51
|
+
function installToKeychain(oauthData) {
|
|
52
|
+
if (!isMacOS()) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
message: "Keychain storage is only available on macOS",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (!saveKeychainCreds(oauthData)) {
|
|
59
|
+
return { ok: false, message: "Failed to save to macOS Keychain" };
|
|
60
|
+
}
|
|
61
|
+
if (!setAuthTypeInSettings("oauth-personal")) {
|
|
62
|
+
return { ok: false, message: "Failed to update settings" };
|
|
63
|
+
}
|
|
64
|
+
return { ok: true, message: "Installed credentials to macOS Keychain" };
|
|
65
|
+
}
|
|
66
|
+
/** Install to default file location */
|
|
67
|
+
function installToDefaultFile(oauthData) {
|
|
68
|
+
const targetPath = getDefaultOAuthPath();
|
|
69
|
+
const targetDirectory = path.dirname(targetPath);
|
|
70
|
+
if (!ensureDirectory(targetDirectory)) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
message: `Failed to create directory ${targetDirectory}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (!saveOAuthCreds(oauthData, targetPath)) {
|
|
77
|
+
return { ok: false, message: "Failed to write OAuth credentials" };
|
|
78
|
+
}
|
|
79
|
+
if (!setAuthTypeInSettings("oauth-personal")) {
|
|
80
|
+
return { ok: false, message: "Failed to update settings" };
|
|
81
|
+
}
|
|
82
|
+
return { ok: true, message: `Installed credentials to ${targetPath}` };
|
|
83
|
+
}
|
|
84
|
+
/** Remove credentials from storage */
|
|
85
|
+
function removeGeminiCredentials(options) {
|
|
86
|
+
// Resolve custom directory with validation
|
|
87
|
+
const resolved = resolveCustomDirectory(AGENT_ID, options?.configDir, options?.dataDir);
|
|
88
|
+
if (!resolved.ok)
|
|
89
|
+
return resolved.error;
|
|
90
|
+
// Custom directory: only remove that specific file
|
|
91
|
+
if (resolved.customDir) {
|
|
92
|
+
const targetPath = path.join(resolved.customDir, CREDS_FILE_NAME);
|
|
93
|
+
if (deleteOAuthCreds(targetPath)) {
|
|
94
|
+
return { ok: true, message: `Removed ${targetPath}` };
|
|
95
|
+
}
|
|
96
|
+
return { ok: true, message: "No credentials file found at specified path" };
|
|
97
|
+
}
|
|
98
|
+
// Default location: remove from keychain, file, and clear settings
|
|
99
|
+
const removedFrom = [];
|
|
100
|
+
if (deleteKeychainCreds()) {
|
|
101
|
+
removedFrom.push("macOS Keychain");
|
|
102
|
+
}
|
|
103
|
+
if (deleteOAuthCreds()) {
|
|
104
|
+
removedFrom.push(getDefaultOAuthPath());
|
|
105
|
+
}
|
|
106
|
+
// Always clear auth type setting to avoid stale configuration
|
|
107
|
+
if (clearAuthTypeFromSettings()) {
|
|
108
|
+
removedFrom.push("auth type from settings");
|
|
109
|
+
}
|
|
110
|
+
if (removedFrom.length === 0) {
|
|
111
|
+
return { ok: true, message: "No credentials found" };
|
|
112
|
+
}
|
|
113
|
+
return { ok: true, message: `Removed from ${removedFrom.join(" and ")}` };
|
|
114
|
+
}
|
|
115
|
+
export { installOAuthCredentials, removeGeminiCredentials };
|
|
@@ -3,12 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/** Get default OAuth credentials file path */
|
|
5
5
|
declare function getDefaultOAuthPath(): string;
|
|
6
|
-
/** Get current auth type from settings */
|
|
7
|
-
declare function getAuthType(): string | undefined;
|
|
8
6
|
/** Clear auth type from settings */
|
|
9
7
|
declare function clearAuthTypeFromSettings(): boolean;
|
|
10
8
|
/** Set auth type in settings */
|
|
11
|
-
declare function setAuthTypeInSettings(authType: string): boolean;
|
|
9
|
+
declare function setAuthTypeInSettings(authType: string, configDirectory?: string): boolean;
|
|
12
10
|
/** Load OAuth credentials from file */
|
|
13
11
|
declare function loadOAuthCreds(): Record<string, unknown> | undefined;
|
|
14
12
|
/** Load OAuth credentials from keychain */
|
|
@@ -21,4 +19,4 @@ declare function deleteKeychainCreds(): boolean;
|
|
|
21
19
|
declare function saveOAuthCreds(data: Record<string, unknown>, filePath?: string): boolean;
|
|
22
20
|
/** Delete OAuth credentials file */
|
|
23
21
|
declare function deleteOAuthCreds(filePath?: string): boolean;
|
|
24
|
-
export { clearAuthTypeFromSettings, deleteKeychainCreds, deleteOAuthCreds,
|
|
22
|
+
export { clearAuthTypeFromSettings, deleteKeychainCreds, deleteOAuthCreds, getDefaultOAuthPath, loadKeychainCreds, loadOAuthCreds, saveKeychainCreds, saveOAuthCreds, setAuthTypeInSettings, };
|
|
@@ -10,28 +10,20 @@ const KEYCHAIN_SERVICE = "gemini-cli-oauth";
|
|
|
10
10
|
const KEYCHAIN_ACCOUNT = "main-account";
|
|
11
11
|
/** Get the Gemini config directory */
|
|
12
12
|
function getConfigDirectory() {
|
|
13
|
-
return getResolvedConfigDirectory(
|
|
13
|
+
return getResolvedConfigDirectory("gemini");
|
|
14
14
|
}
|
|
15
15
|
/** Get default OAuth credentials file path */
|
|
16
16
|
function getDefaultOAuthPath() {
|
|
17
17
|
return path.join(getConfigDirectory(), "oauth_creds.json");
|
|
18
18
|
}
|
|
19
|
-
/** Get current auth type from settings */
|
|
20
|
-
function getAuthType() {
|
|
21
|
-
const result = geminiConfigReader.readRaw(getConfigDirectory(), "security.auth.selectedType");
|
|
22
|
-
if (result.ok && typeof result.value === "string") {
|
|
23
|
-
return result.value;
|
|
24
|
-
}
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
19
|
/** Clear auth type from settings */
|
|
28
20
|
function clearAuthTypeFromSettings() {
|
|
29
21
|
const result = geminiConfigReader.deleteRaw(getConfigDirectory(), "security.auth.selectedType");
|
|
30
22
|
return result.ok && result.deleted;
|
|
31
23
|
}
|
|
32
24
|
/** Set auth type in settings */
|
|
33
|
-
function setAuthTypeInSettings(authType) {
|
|
34
|
-
const result = geminiConfigReader.writeRaw(getConfigDirectory(), "security.auth.selectedType", authType);
|
|
25
|
+
function setAuthTypeInSettings(authType, configDirectory) {
|
|
26
|
+
const result = geminiConfigReader.writeRaw(configDirectory ?? getConfigDirectory(), "security.auth.selectedType", authType);
|
|
35
27
|
return result.ok;
|
|
36
28
|
}
|
|
37
29
|
/** Load OAuth credentials from file */
|
|
@@ -66,4 +58,4 @@ function saveOAuthCreds(data, filePath) {
|
|
|
66
58
|
function deleteOAuthCreds(filePath) {
|
|
67
59
|
return deleteFile(filePath ?? getDefaultOAuthPath());
|
|
68
60
|
}
|
|
69
|
-
export { clearAuthTypeFromSettings, deleteKeychainCreds, deleteOAuthCreds,
|
|
61
|
+
export { clearAuthTypeFromSettings, deleteKeychainCreds, deleteOAuthCreds, getDefaultOAuthPath, loadKeychainCreds, loadOAuthCreds, saveKeychainCreds, saveOAuthCreds, setAuthTypeInSettings, };
|