opensteer 0.6.1 → 0.6.3
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 +4 -5
- package/bin/opensteer.mjs +0 -1
- package/dist/{chunk-F2VDVOJO.js → chunk-3OMXCBPD.js} +10 -19
- package/dist/{chunk-WJI7TGBQ.js → chunk-FTKWQ6X3.js} +1 -1
- package/dist/{chunk-WDRMHPWL.js → chunk-KE35RQOJ.js} +106 -36
- package/dist/{chunk-3FNI7JUU.js → chunk-SCNX4NN3.js} +114 -241
- package/dist/cli/auth.cjs +215 -276
- package/dist/cli/auth.d.cts +0 -6
- package/dist/cli/auth.d.ts +0 -6
- package/dist/cli/auth.js +2 -2
- package/dist/cli/profile.cjs +199 -259
- package/dist/cli/profile.d.cts +0 -2
- package/dist/cli/profile.d.ts +0 -2
- package/dist/cli/profile.js +4 -28
- package/dist/cli/server.cjs +110 -53
- package/dist/cli/server.js +2 -2
- package/dist/index.cjs +110 -53
- package/dist/index.js +3 -3
- package/package.json +1 -1
|
@@ -4,67 +4,30 @@ import {
|
|
|
4
4
|
normalizeCloudBaseUrl,
|
|
5
5
|
resolveCloudSelection,
|
|
6
6
|
resolveConfigWithEnv,
|
|
7
|
+
selectCloudCredential,
|
|
7
8
|
stripTrailingSlashes
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KE35RQOJ.js";
|
|
9
10
|
|
|
10
11
|
// src/cli/auth.ts
|
|
11
12
|
import open from "open";
|
|
12
13
|
|
|
13
14
|
// src/auth/credential-resolver.ts
|
|
14
15
|
function resolveCloudCredential(options) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
kind: "access-token",
|
|
23
|
-
source: "flag",
|
|
24
|
-
token: flagAccessToken,
|
|
25
|
-
authScheme: "bearer"
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
if (flagApiKey) {
|
|
29
|
-
return {
|
|
30
|
-
kind: "api-key",
|
|
31
|
-
source: "flag",
|
|
32
|
-
token: flagApiKey,
|
|
33
|
-
authScheme: "api-key"
|
|
34
|
-
};
|
|
16
|
+
const flagCredential = selectCloudCredential({
|
|
17
|
+
apiKey: options.apiKeyFlag,
|
|
18
|
+
accessToken: options.accessTokenFlag
|
|
19
|
+
});
|
|
20
|
+
if (flagCredential) {
|
|
21
|
+
return toResolvedCloudCredential("flag", flagCredential);
|
|
35
22
|
}
|
|
36
23
|
const envAuthScheme = parseEnvAuthScheme(options.env.OPENSTEER_AUTH_SCHEME);
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (envAccessToken) {
|
|
45
|
-
return {
|
|
46
|
-
kind: "access-token",
|
|
47
|
-
source: "env",
|
|
48
|
-
token: envAccessToken,
|
|
49
|
-
authScheme: "bearer"
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
if (envApiKey) {
|
|
53
|
-
if (envAuthScheme === "bearer") {
|
|
54
|
-
return {
|
|
55
|
-
kind: "access-token",
|
|
56
|
-
source: "env",
|
|
57
|
-
token: envApiKey,
|
|
58
|
-
authScheme: "bearer",
|
|
59
|
-
compatibilityBearerApiKey: true
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
kind: "api-key",
|
|
64
|
-
source: "env",
|
|
65
|
-
token: envApiKey,
|
|
66
|
-
authScheme: envAuthScheme ?? "api-key"
|
|
67
|
-
};
|
|
24
|
+
const envCredential = selectCloudCredential({
|
|
25
|
+
apiKey: options.env.OPENSTEER_API_KEY,
|
|
26
|
+
accessToken: options.env.OPENSTEER_ACCESS_TOKEN,
|
|
27
|
+
authScheme: envAuthScheme
|
|
28
|
+
});
|
|
29
|
+
if (envCredential) {
|
|
30
|
+
return toResolvedCloudCredential("env", envCredential);
|
|
68
31
|
}
|
|
69
32
|
return null;
|
|
70
33
|
}
|
|
@@ -94,19 +57,33 @@ function normalizeToken(value) {
|
|
|
94
57
|
const normalized = value.trim();
|
|
95
58
|
return normalized.length ? normalized : void 0;
|
|
96
59
|
}
|
|
60
|
+
function toResolvedCloudCredential(source, credential) {
|
|
61
|
+
if (credential.compatibilityBearerApiKey) {
|
|
62
|
+
return {
|
|
63
|
+
kind: credential.kind,
|
|
64
|
+
source,
|
|
65
|
+
token: credential.token,
|
|
66
|
+
authScheme: credential.authScheme,
|
|
67
|
+
compatibilityBearerApiKey: true
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
kind: credential.kind,
|
|
72
|
+
source,
|
|
73
|
+
token: credential.token,
|
|
74
|
+
authScheme: credential.authScheme
|
|
75
|
+
};
|
|
76
|
+
}
|
|
97
77
|
|
|
98
78
|
// src/auth/machine-credential-store.ts
|
|
99
79
|
import { createHash } from "crypto";
|
|
100
80
|
import fs from "fs";
|
|
101
81
|
import os from "os";
|
|
102
82
|
import path from "path";
|
|
103
|
-
var METADATA_VERSION =
|
|
104
|
-
var ACTIVE_TARGET_VERSION =
|
|
83
|
+
var METADATA_VERSION = 2;
|
|
84
|
+
var ACTIVE_TARGET_VERSION = 2;
|
|
105
85
|
var KEYCHAIN_SERVICE = "com.opensteer.cli.cloud";
|
|
106
86
|
var KEYCHAIN_ACCOUNT_PREFIX = "machine:";
|
|
107
|
-
var LEGACY_KEYCHAIN_ACCOUNT = "machine";
|
|
108
|
-
var LEGACY_METADATA_FILE_NAME = "cli-login.json";
|
|
109
|
-
var LEGACY_FALLBACK_SECRET_FILE_NAME = "cli-login.secret.json";
|
|
110
87
|
var ACTIVE_TARGET_FILE_NAME = "cli-target.json";
|
|
111
88
|
var MachineCredentialStore = class {
|
|
112
89
|
authDir;
|
|
@@ -121,8 +98,11 @@ var MachineCredentialStore = class {
|
|
|
121
98
|
this.warn = options.warn ?? (() => void 0);
|
|
122
99
|
}
|
|
123
100
|
readCloudCredential(target) {
|
|
124
|
-
const
|
|
125
|
-
return this.readCredentialSlot(
|
|
101
|
+
const normalizedTarget = normalizeCloudCredentialTarget(target);
|
|
102
|
+
return this.readCredentialSlot(
|
|
103
|
+
resolveCredentialSlot(this.authDir, normalizedTarget),
|
|
104
|
+
normalizedTarget
|
|
105
|
+
);
|
|
126
106
|
}
|
|
127
107
|
writeCloudCredential(args) {
|
|
128
108
|
const accessToken = args.accessToken.trim();
|
|
@@ -130,12 +110,8 @@ var MachineCredentialStore = class {
|
|
|
130
110
|
if (!accessToken || !refreshToken2) {
|
|
131
111
|
throw new Error("Cannot persist empty machine credential secrets.");
|
|
132
112
|
}
|
|
133
|
-
const baseUrl = normalizeCredentialUrl(args.baseUrl
|
|
134
|
-
const
|
|
135
|
-
const slot = resolveCredentialSlot(this.authDir, {
|
|
136
|
-
baseUrl,
|
|
137
|
-
siteUrl
|
|
138
|
-
});
|
|
113
|
+
const baseUrl = normalizeCredentialUrl(args.baseUrl);
|
|
114
|
+
const slot = resolveCredentialSlot(this.authDir, { baseUrl });
|
|
139
115
|
ensureDirectory(this.authDir);
|
|
140
116
|
const secretPayload = {
|
|
141
117
|
accessToken,
|
|
@@ -162,7 +138,6 @@ var MachineCredentialStore = class {
|
|
|
162
138
|
version: METADATA_VERSION,
|
|
163
139
|
secretBackend,
|
|
164
140
|
baseUrl,
|
|
165
|
-
siteUrl,
|
|
166
141
|
scope: args.scope,
|
|
167
142
|
obtainedAt: args.obtainedAt,
|
|
168
143
|
expiresAt: args.expiresAt,
|
|
@@ -174,23 +149,18 @@ var MachineCredentialStore = class {
|
|
|
174
149
|
return readActiveCloudTargetMetadata(resolveActiveTargetPath(this.authDir));
|
|
175
150
|
}
|
|
176
151
|
writeActiveCloudTarget(target) {
|
|
177
|
-
const baseUrl = normalizeCredentialUrl(target.baseUrl
|
|
178
|
-
const siteUrl = normalizeCredentialUrl(target.siteUrl, "siteUrl");
|
|
152
|
+
const baseUrl = normalizeCredentialUrl(target.baseUrl);
|
|
179
153
|
ensureDirectory(this.authDir);
|
|
180
154
|
writeJsonFile(resolveActiveTargetPath(this.authDir), {
|
|
181
155
|
version: ACTIVE_TARGET_VERSION,
|
|
182
156
|
baseUrl,
|
|
183
|
-
siteUrl,
|
|
184
157
|
updatedAt: Date.now()
|
|
185
158
|
});
|
|
186
159
|
}
|
|
187
160
|
clearCloudCredential(target) {
|
|
188
|
-
this.clearCredentialSlot(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (legacyMetadata && matchesCredentialTarget(legacyMetadata, target)) {
|
|
192
|
-
this.clearCredentialSlot(legacySlot);
|
|
193
|
-
}
|
|
161
|
+
this.clearCredentialSlot(
|
|
162
|
+
resolveCredentialSlot(this.authDir, normalizeCloudCredentialTarget(target))
|
|
163
|
+
);
|
|
194
164
|
}
|
|
195
165
|
readCredentialSlot(slot, target) {
|
|
196
166
|
const metadata = readMetadata(slot.metadataPath);
|
|
@@ -206,7 +176,6 @@ var MachineCredentialStore = class {
|
|
|
206
176
|
}
|
|
207
177
|
return {
|
|
208
178
|
baseUrl: metadata.baseUrl,
|
|
209
|
-
siteUrl: metadata.siteUrl,
|
|
210
179
|
scope: metadata.scope,
|
|
211
180
|
accessToken: secret.accessToken,
|
|
212
181
|
refreshToken: secret.refreshToken,
|
|
@@ -214,16 +183,6 @@ var MachineCredentialStore = class {
|
|
|
214
183
|
expiresAt: metadata.expiresAt
|
|
215
184
|
};
|
|
216
185
|
}
|
|
217
|
-
readAndMigrateLegacyCredential(target) {
|
|
218
|
-
const legacySlot = resolveLegacyCredentialSlot(this.authDir);
|
|
219
|
-
const legacyCredential = this.readCredentialSlot(legacySlot, target);
|
|
220
|
-
if (!legacyCredential) {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
this.writeCloudCredential(legacyCredential);
|
|
224
|
-
this.clearCredentialSlot(legacySlot);
|
|
225
|
-
return legacyCredential;
|
|
226
|
-
}
|
|
227
186
|
readSecret(slot, backend) {
|
|
228
187
|
if (backend === "keychain" && this.keychain) {
|
|
229
188
|
try {
|
|
@@ -264,9 +223,8 @@ function createMachineCredentialStore(options = {}) {
|
|
|
264
223
|
return new MachineCredentialStore(options);
|
|
265
224
|
}
|
|
266
225
|
function resolveCredentialSlot(authDir, target) {
|
|
267
|
-
const normalizedBaseUrl = normalizeCredentialUrl(target.baseUrl
|
|
268
|
-
const
|
|
269
|
-
const storageKey = createHash("sha256").update(`${normalizedBaseUrl}\0${normalizedSiteUrl}`).digest("hex").slice(0, 24);
|
|
226
|
+
const normalizedBaseUrl = normalizeCredentialUrl(target.baseUrl);
|
|
227
|
+
const storageKey = createHash("sha256").update(normalizedBaseUrl).digest("hex").slice(0, 24);
|
|
270
228
|
return {
|
|
271
229
|
keychainAccount: `${KEYCHAIN_ACCOUNT_PREFIX}${storageKey}`,
|
|
272
230
|
metadataPath: path.join(authDir, `cli-login.${storageKey}.json`),
|
|
@@ -276,26 +234,24 @@ function resolveCredentialSlot(authDir, target) {
|
|
|
276
234
|
)
|
|
277
235
|
};
|
|
278
236
|
}
|
|
279
|
-
function resolveLegacyCredentialSlot(authDir) {
|
|
280
|
-
return {
|
|
281
|
-
keychainAccount: LEGACY_KEYCHAIN_ACCOUNT,
|
|
282
|
-
metadataPath: path.join(authDir, LEGACY_METADATA_FILE_NAME),
|
|
283
|
-
fallbackSecretPath: path.join(authDir, LEGACY_FALLBACK_SECRET_FILE_NAME)
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
237
|
function resolveActiveTargetPath(authDir) {
|
|
287
238
|
return path.join(authDir, ACTIVE_TARGET_FILE_NAME);
|
|
288
239
|
}
|
|
289
240
|
function matchesCredentialTarget(value, target) {
|
|
290
|
-
return normalizeCredentialUrl(value.baseUrl
|
|
241
|
+
return normalizeCredentialUrl(value.baseUrl) === normalizeCredentialUrl(target.baseUrl);
|
|
291
242
|
}
|
|
292
|
-
function normalizeCredentialUrl(value
|
|
243
|
+
function normalizeCredentialUrl(value) {
|
|
293
244
|
const normalized = stripTrailingSlashes(value.trim());
|
|
294
245
|
if (!normalized) {
|
|
295
|
-
throw new Error(
|
|
246
|
+
throw new Error("Cannot persist machine credential without baseUrl.");
|
|
296
247
|
}
|
|
297
248
|
return normalized;
|
|
298
249
|
}
|
|
250
|
+
function normalizeCloudCredentialTarget(target) {
|
|
251
|
+
return {
|
|
252
|
+
baseUrl: normalizeCredentialUrl(target.baseUrl)
|
|
253
|
+
};
|
|
254
|
+
}
|
|
299
255
|
function resolveConfigDir(appName, env) {
|
|
300
256
|
if (process.platform === "win32") {
|
|
301
257
|
const appData = env.APPDATA?.trim() || path.join(os.homedir(), "AppData", "Roaming");
|
|
@@ -334,7 +290,6 @@ function readMetadata(filePath) {
|
|
|
334
290
|
return null;
|
|
335
291
|
}
|
|
336
292
|
if (typeof parsed.baseUrl !== "string" || !parsed.baseUrl.trim()) return null;
|
|
337
|
-
if (typeof parsed.siteUrl !== "string" || !parsed.siteUrl.trim()) return null;
|
|
338
293
|
if (!Array.isArray(parsed.scope)) return null;
|
|
339
294
|
if (typeof parsed.obtainedAt !== "number") return null;
|
|
340
295
|
if (typeof parsed.expiresAt !== "number") return null;
|
|
@@ -343,7 +298,6 @@ function readMetadata(filePath) {
|
|
|
343
298
|
version: parsed.version,
|
|
344
299
|
secretBackend: parsed.secretBackend,
|
|
345
300
|
baseUrl: parsed.baseUrl,
|
|
346
|
-
siteUrl: parsed.siteUrl,
|
|
347
301
|
scope: parsed.scope.filter(
|
|
348
302
|
(value) => typeof value === "string"
|
|
349
303
|
),
|
|
@@ -368,12 +322,8 @@ function readActiveCloudTargetMetadata(filePath) {
|
|
|
368
322
|
if (typeof parsed.baseUrl !== "string" || !parsed.baseUrl.trim()) {
|
|
369
323
|
return null;
|
|
370
324
|
}
|
|
371
|
-
if (typeof parsed.siteUrl !== "string" || !parsed.siteUrl.trim()) {
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
325
|
return {
|
|
375
|
-
baseUrl: parsed.baseUrl
|
|
376
|
-
siteUrl: parsed.siteUrl
|
|
326
|
+
baseUrl: parsed.baseUrl
|
|
377
327
|
};
|
|
378
328
|
} catch {
|
|
379
329
|
return null;
|
|
@@ -398,14 +348,13 @@ function readSecretFile(filePath) {
|
|
|
398
348
|
return null;
|
|
399
349
|
}
|
|
400
350
|
try {
|
|
401
|
-
|
|
402
|
-
return parseSecretPayload(raw);
|
|
351
|
+
return parseSecretPayload(fs.readFileSync(filePath, "utf8"));
|
|
403
352
|
} catch {
|
|
404
353
|
return null;
|
|
405
354
|
}
|
|
406
355
|
}
|
|
407
|
-
function writeJsonFile(filePath,
|
|
408
|
-
fs.writeFileSync(filePath, JSON.stringify(
|
|
356
|
+
function writeJsonFile(filePath, value, options = {}) {
|
|
357
|
+
fs.writeFileSync(filePath, JSON.stringify(value, null, 2), {
|
|
409
358
|
encoding: "utf8",
|
|
410
359
|
mode: options.mode ?? 384
|
|
411
360
|
});
|
|
@@ -436,11 +385,12 @@ Commands:
|
|
|
436
385
|
|
|
437
386
|
Options:
|
|
438
387
|
--base-url <url> Cloud API base URL (defaults to env or the last selected host)
|
|
439
|
-
--site-url <url> Cloud site URL for browser/device auth (defaults to env or the last selected host)
|
|
440
388
|
--json JSON output (login prompts go to stderr)
|
|
441
389
|
--no-browser Do not auto-open your default browser during login
|
|
442
390
|
-h, --help Show this help
|
|
443
391
|
`;
|
|
392
|
+
var DEFAULT_AUTH_SITE_URL = "https://opensteer.com";
|
|
393
|
+
var INTERNAL_AUTH_SITE_URL_ENV = "OPENSTEER_INTERNAL_AUTH_SITE_URL";
|
|
444
394
|
function createDefaultDeps() {
|
|
445
395
|
const env = process.env;
|
|
446
396
|
return {
|
|
@@ -492,13 +442,6 @@ function parseAuthCommonArgs(rawArgs) {
|
|
|
492
442
|
i = value.nextIndex;
|
|
493
443
|
continue;
|
|
494
444
|
}
|
|
495
|
-
if (arg === "--site-url") {
|
|
496
|
-
const value = readFlagValue(rawArgs, i, "--site-url");
|
|
497
|
-
if (!value.ok) return { args, error: value.error };
|
|
498
|
-
args.siteUrl = value.value;
|
|
499
|
-
i = value.nextIndex;
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
445
|
return {
|
|
503
446
|
args,
|
|
504
447
|
error: `Unsupported option "${arg}".`
|
|
@@ -568,16 +511,19 @@ function resolveBaseUrl(provided, env) {
|
|
|
568
511
|
assertSecureUrl(baseUrl, "--base-url");
|
|
569
512
|
return baseUrl;
|
|
570
513
|
}
|
|
571
|
-
function
|
|
572
|
-
const
|
|
573
|
-
(
|
|
514
|
+
function resolveAuthSiteUrl(env) {
|
|
515
|
+
const authSiteUrl = normalizeCloudBaseUrl(
|
|
516
|
+
(env[INTERNAL_AUTH_SITE_URL_ENV] || DEFAULT_AUTH_SITE_URL).trim()
|
|
574
517
|
);
|
|
575
|
-
assertSecureUrl(
|
|
576
|
-
|
|
518
|
+
assertSecureUrl(
|
|
519
|
+
authSiteUrl,
|
|
520
|
+
`environment variable ${INTERNAL_AUTH_SITE_URL_ENV}`
|
|
521
|
+
);
|
|
522
|
+
return authSiteUrl;
|
|
577
523
|
}
|
|
578
|
-
function hasExplicitCloudTargetSelection(providedBaseUrl,
|
|
524
|
+
function hasExplicitCloudTargetSelection(providedBaseUrl, env) {
|
|
579
525
|
return Boolean(
|
|
580
|
-
providedBaseUrl?.trim() ||
|
|
526
|
+
providedBaseUrl?.trim() || env.OPENSTEER_BASE_URL?.trim()
|
|
581
527
|
);
|
|
582
528
|
}
|
|
583
529
|
function readRememberedCloudTarget(store) {
|
|
@@ -587,57 +533,21 @@ function readRememberedCloudTarget(store) {
|
|
|
587
533
|
}
|
|
588
534
|
try {
|
|
589
535
|
const baseUrl = normalizeCloudBaseUrl(activeTarget.baseUrl);
|
|
590
|
-
const siteUrl = normalizeCloudBaseUrl(activeTarget.siteUrl);
|
|
591
536
|
assertSecureUrl(baseUrl, "--base-url");
|
|
592
|
-
|
|
593
|
-
return {
|
|
594
|
-
baseUrl,
|
|
595
|
-
siteUrl
|
|
596
|
-
};
|
|
537
|
+
return { baseUrl };
|
|
597
538
|
} catch {
|
|
598
539
|
return null;
|
|
599
540
|
}
|
|
600
541
|
}
|
|
601
|
-
function resolveCloudTarget(args, env, store) {
|
|
602
|
-
if (!hasExplicitCloudTargetSelection(args.baseUrl,
|
|
542
|
+
function resolveCloudTarget(args, env, store, options = {}) {
|
|
543
|
+
if (options.allowRememberedTarget !== false && !hasExplicitCloudTargetSelection(args.baseUrl, env)) {
|
|
603
544
|
const rememberedTarget = readRememberedCloudTarget(store);
|
|
604
545
|
if (rememberedTarget) {
|
|
605
546
|
return rememberedTarget;
|
|
606
547
|
}
|
|
607
548
|
}
|
|
608
549
|
const baseUrl = resolveBaseUrl(args.baseUrl, env);
|
|
609
|
-
|
|
610
|
-
return {
|
|
611
|
-
baseUrl,
|
|
612
|
-
siteUrl
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
function deriveSiteUrlFromBaseUrl(baseUrl) {
|
|
616
|
-
let parsed;
|
|
617
|
-
try {
|
|
618
|
-
parsed = new URL(baseUrl);
|
|
619
|
-
} catch {
|
|
620
|
-
return "https://opensteer.com";
|
|
621
|
-
}
|
|
622
|
-
const hostname = parsed.hostname.toLowerCase();
|
|
623
|
-
if (hostname.startsWith("api.")) {
|
|
624
|
-
parsed.hostname = hostname.slice("api.".length);
|
|
625
|
-
parsed.pathname = "";
|
|
626
|
-
parsed.search = "";
|
|
627
|
-
parsed.hash = "";
|
|
628
|
-
return normalizeCloudBaseUrl(parsed.toString());
|
|
629
|
-
}
|
|
630
|
-
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") {
|
|
631
|
-
parsed.port = "3001";
|
|
632
|
-
parsed.pathname = "";
|
|
633
|
-
parsed.search = "";
|
|
634
|
-
parsed.hash = "";
|
|
635
|
-
return normalizeCloudBaseUrl(parsed.toString());
|
|
636
|
-
}
|
|
637
|
-
parsed.pathname = "";
|
|
638
|
-
parsed.search = "";
|
|
639
|
-
parsed.hash = "";
|
|
640
|
-
return normalizeCloudBaseUrl(parsed.toString());
|
|
550
|
+
return { baseUrl };
|
|
641
551
|
}
|
|
642
552
|
function assertSecureUrl(value, flag) {
|
|
643
553
|
let parsed;
|
|
@@ -712,10 +622,10 @@ function parseCliOauthError(error) {
|
|
|
712
622
|
interval: typeof root.interval === "number" ? root.interval : void 0
|
|
713
623
|
};
|
|
714
624
|
}
|
|
715
|
-
async function startDeviceAuthorization(
|
|
625
|
+
async function startDeviceAuthorization(authSiteUrl, fetchFn) {
|
|
716
626
|
const response = await postJson(
|
|
717
627
|
fetchFn,
|
|
718
|
-
`${
|
|
628
|
+
`${authSiteUrl}/api/cli-auth/device/start`,
|
|
719
629
|
{
|
|
720
630
|
scope: ["cloud:browser"]
|
|
721
631
|
}
|
|
@@ -725,24 +635,24 @@ async function startDeviceAuthorization(siteUrl, fetchFn) {
|
|
|
725
635
|
}
|
|
726
636
|
return response;
|
|
727
637
|
}
|
|
728
|
-
async function pollDeviceToken(
|
|
638
|
+
async function pollDeviceToken(authSiteUrl, deviceCode, fetchFn) {
|
|
729
639
|
return await postJson(
|
|
730
640
|
fetchFn,
|
|
731
|
-
`${
|
|
641
|
+
`${authSiteUrl}/api/cli-auth/device/token`,
|
|
732
642
|
{
|
|
733
643
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
734
644
|
device_code: deviceCode
|
|
735
645
|
}
|
|
736
646
|
);
|
|
737
647
|
}
|
|
738
|
-
async function refreshToken(
|
|
739
|
-
return await postJson(fetchFn, `${
|
|
648
|
+
async function refreshToken(authSiteUrl, refreshTokenValue, fetchFn) {
|
|
649
|
+
return await postJson(fetchFn, `${authSiteUrl}/api/cli-auth/token`, {
|
|
740
650
|
grant_type: "refresh_token",
|
|
741
651
|
refresh_token: refreshTokenValue
|
|
742
652
|
});
|
|
743
653
|
}
|
|
744
|
-
async function revokeToken(
|
|
745
|
-
await postJson(fetchFn, `${
|
|
654
|
+
async function revokeToken(authSiteUrl, refreshTokenValue, fetchFn) {
|
|
655
|
+
await postJson(fetchFn, `${authSiteUrl}/api/cli-auth/revoke`, {
|
|
746
656
|
token: refreshTokenValue
|
|
747
657
|
});
|
|
748
658
|
}
|
|
@@ -759,7 +669,7 @@ async function openDefaultBrowser(url) {
|
|
|
759
669
|
}
|
|
760
670
|
}
|
|
761
671
|
async function runDeviceLoginFlow(args) {
|
|
762
|
-
const start = await startDeviceAuthorization(args.
|
|
672
|
+
const start = await startDeviceAuthorization(args.authSiteUrl, args.fetchFn);
|
|
763
673
|
if (args.openBrowser) {
|
|
764
674
|
args.writeProgress(
|
|
765
675
|
"Opening your default browser for Opensteer CLI authentication.\n"
|
|
@@ -804,7 +714,7 @@ ${start.verification_uri_complete}
|
|
|
804
714
|
await args.sleep(pollIntervalMs);
|
|
805
715
|
try {
|
|
806
716
|
const tokenPayload = await pollDeviceToken(
|
|
807
|
-
args.
|
|
717
|
+
args.authSiteUrl,
|
|
808
718
|
start.device_code,
|
|
809
719
|
args.fetchFn
|
|
810
720
|
);
|
|
@@ -852,7 +762,7 @@ ${start.verification_uri_complete}
|
|
|
852
762
|
}
|
|
853
763
|
async function refreshSavedCredential(saved, deps) {
|
|
854
764
|
const tokenPayload = await refreshToken(
|
|
855
|
-
|
|
765
|
+
resolveAuthSiteUrl(deps.env),
|
|
856
766
|
saved.refreshToken,
|
|
857
767
|
deps.fetchFn
|
|
858
768
|
);
|
|
@@ -865,7 +775,6 @@ async function refreshSavedCredential(saved, deps) {
|
|
|
865
775
|
};
|
|
866
776
|
deps.store.writeCloudCredential({
|
|
867
777
|
baseUrl: saved.baseUrl,
|
|
868
|
-
siteUrl: saved.siteUrl,
|
|
869
778
|
scope: updated.scope,
|
|
870
779
|
accessToken: updated.accessToken,
|
|
871
780
|
refreshToken: updated.refreshToken,
|
|
@@ -894,8 +803,7 @@ async function ensureSavedCredentialIsFresh(saved, deps) {
|
|
|
894
803
|
const oauth = parseCliOauthError(error.body);
|
|
895
804
|
if (oauth?.error === "invalid_grant" || oauth?.error === "expired_token") {
|
|
896
805
|
deps.store.clearCloudCredential({
|
|
897
|
-
baseUrl: saved.baseUrl
|
|
898
|
-
siteUrl: saved.siteUrl
|
|
806
|
+
baseUrl: saved.baseUrl
|
|
899
807
|
});
|
|
900
808
|
return null;
|
|
901
809
|
}
|
|
@@ -995,7 +903,7 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
995
903
|
`);
|
|
996
904
|
}
|
|
997
905
|
});
|
|
998
|
-
const { baseUrl
|
|
906
|
+
const { baseUrl } = resolveCloudTarget(options, env, store);
|
|
999
907
|
const initialCredential = resolveCloudCredential({
|
|
1000
908
|
env,
|
|
1001
909
|
apiKeyFlag: options.apiKeyFlag,
|
|
@@ -1003,11 +911,9 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1003
911
|
});
|
|
1004
912
|
let credential = initialCredential;
|
|
1005
913
|
if (!credential) {
|
|
1006
|
-
const saved = store.readCloudCredential({
|
|
1007
|
-
baseUrl,
|
|
1008
|
-
siteUrl
|
|
1009
|
-
});
|
|
914
|
+
const saved = store.readCloudCredential({ baseUrl });
|
|
1010
915
|
const freshSaved = saved ? await ensureSavedCredentialIsFresh(saved, {
|
|
916
|
+
env,
|
|
1011
917
|
fetchFn,
|
|
1012
918
|
store,
|
|
1013
919
|
now,
|
|
@@ -1025,7 +931,7 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1025
931
|
if (!credential) {
|
|
1026
932
|
if (options.autoLoginIfNeeded && (options.interactive ?? false)) {
|
|
1027
933
|
const loggedIn = await runDeviceLoginFlow({
|
|
1028
|
-
|
|
934
|
+
authSiteUrl: resolveAuthSiteUrl(env),
|
|
1029
935
|
fetchFn,
|
|
1030
936
|
writeProgress,
|
|
1031
937
|
openExternalUrl,
|
|
@@ -1035,7 +941,6 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1035
941
|
});
|
|
1036
942
|
store.writeCloudCredential({
|
|
1037
943
|
baseUrl,
|
|
1038
|
-
siteUrl,
|
|
1039
944
|
scope: loggedIn.scope,
|
|
1040
945
|
accessToken: loggedIn.accessToken,
|
|
1041
946
|
refreshToken: loggedIn.refreshToken,
|
|
@@ -1053,28 +958,25 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1053
958
|
throw new Error(toAuthMissingMessage(options.commandName));
|
|
1054
959
|
}
|
|
1055
960
|
}
|
|
1056
|
-
store.writeActiveCloudTarget({
|
|
1057
|
-
baseUrl,
|
|
1058
|
-
siteUrl
|
|
1059
|
-
});
|
|
961
|
+
store.writeActiveCloudTarget({ baseUrl });
|
|
1060
962
|
applyCloudCredentialToEnv(env, credential);
|
|
1061
963
|
env.OPENSTEER_BASE_URL = baseUrl;
|
|
1062
|
-
env.OPENSTEER_CLOUD_SITE_URL = siteUrl;
|
|
1063
964
|
return {
|
|
1064
965
|
token: credential.token,
|
|
1065
966
|
authScheme: credential.authScheme,
|
|
1066
967
|
source: credential.source,
|
|
1067
968
|
kind: credential.kind,
|
|
1068
|
-
baseUrl
|
|
1069
|
-
siteUrl
|
|
969
|
+
baseUrl
|
|
1070
970
|
};
|
|
1071
971
|
}
|
|
1072
972
|
async function runLogin(args, deps) {
|
|
1073
|
-
const { baseUrl
|
|
973
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store, {
|
|
974
|
+
allowRememberedTarget: false
|
|
975
|
+
});
|
|
1074
976
|
const writeProgress = args.json ? deps.writeStderr : deps.writeStdout;
|
|
1075
977
|
const browserOpenMode = describeBrowserOpenMode(args, deps);
|
|
1076
978
|
const login = await runDeviceLoginFlow({
|
|
1077
|
-
|
|
979
|
+
authSiteUrl: resolveAuthSiteUrl(deps.env),
|
|
1078
980
|
fetchFn: deps.fetchFn,
|
|
1079
981
|
writeProgress,
|
|
1080
982
|
openExternalUrl: deps.openExternalUrl,
|
|
@@ -1085,22 +987,17 @@ async function runLogin(args, deps) {
|
|
|
1085
987
|
});
|
|
1086
988
|
deps.store.writeCloudCredential({
|
|
1087
989
|
baseUrl,
|
|
1088
|
-
siteUrl,
|
|
1089
990
|
scope: login.scope,
|
|
1090
991
|
accessToken: login.accessToken,
|
|
1091
992
|
refreshToken: login.refreshToken,
|
|
1092
993
|
obtainedAt: deps.now(),
|
|
1093
994
|
expiresAt: login.expiresAt
|
|
1094
995
|
});
|
|
1095
|
-
deps.store.writeActiveCloudTarget({
|
|
1096
|
-
baseUrl,
|
|
1097
|
-
siteUrl
|
|
1098
|
-
});
|
|
996
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1099
997
|
if (args.json) {
|
|
1100
998
|
writeJsonLine(deps, {
|
|
1101
999
|
loggedIn: true,
|
|
1102
1000
|
baseUrl,
|
|
1103
|
-
siteUrl,
|
|
1104
1001
|
expiresAt: login.expiresAt,
|
|
1105
1002
|
scope: login.scope,
|
|
1106
1003
|
authSource: "device"
|
|
@@ -1108,33 +1005,20 @@ async function runLogin(args, deps) {
|
|
|
1108
1005
|
return 0;
|
|
1109
1006
|
}
|
|
1110
1007
|
writeHumanLine(deps, "Opensteer CLI login successful.");
|
|
1111
|
-
writeHumanLine(deps, ` Site URL: ${siteUrl}`);
|
|
1112
|
-
writeHumanLine(deps, ` API Base URL: ${baseUrl}`);
|
|
1113
|
-
writeHumanLine(deps, ` Expires At: ${new Date(login.expiresAt).toISOString()}`);
|
|
1114
1008
|
return 0;
|
|
1115
1009
|
}
|
|
1116
1010
|
async function runStatus(args, deps) {
|
|
1117
|
-
const { baseUrl
|
|
1118
|
-
deps.store.writeActiveCloudTarget({
|
|
1119
|
-
|
|
1120
|
-
siteUrl
|
|
1121
|
-
});
|
|
1122
|
-
const saved = deps.store.readCloudCredential({
|
|
1123
|
-
baseUrl,
|
|
1124
|
-
siteUrl
|
|
1125
|
-
});
|
|
1011
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store);
|
|
1012
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1013
|
+
const saved = deps.store.readCloudCredential({ baseUrl });
|
|
1126
1014
|
if (!saved) {
|
|
1127
1015
|
if (args.json) {
|
|
1128
1016
|
writeJsonLine(deps, {
|
|
1129
1017
|
loggedIn: false,
|
|
1130
|
-
baseUrl
|
|
1131
|
-
siteUrl
|
|
1018
|
+
baseUrl
|
|
1132
1019
|
});
|
|
1133
1020
|
} else {
|
|
1134
|
-
writeHumanLine(
|
|
1135
|
-
deps,
|
|
1136
|
-
`Opensteer CLI is not logged in for ${siteUrl}.`
|
|
1137
|
-
);
|
|
1021
|
+
writeHumanLine(deps, `Opensteer CLI is not logged in for ${baseUrl}.`);
|
|
1138
1022
|
}
|
|
1139
1023
|
return 0;
|
|
1140
1024
|
}
|
|
@@ -1145,7 +1029,6 @@ async function runStatus(args, deps) {
|
|
|
1145
1029
|
loggedIn: true,
|
|
1146
1030
|
expired,
|
|
1147
1031
|
baseUrl: saved.baseUrl,
|
|
1148
|
-
siteUrl: saved.siteUrl,
|
|
1149
1032
|
expiresAt: saved.expiresAt,
|
|
1150
1033
|
scope: saved.scope
|
|
1151
1034
|
});
|
|
@@ -1155,43 +1038,33 @@ async function runStatus(args, deps) {
|
|
|
1155
1038
|
deps,
|
|
1156
1039
|
expired ? "Opensteer CLI has a saved login, but the access token is expired." : "Opensteer CLI is logged in."
|
|
1157
1040
|
);
|
|
1158
|
-
writeHumanLine(deps, ` Site URL: ${saved.siteUrl}`);
|
|
1159
1041
|
writeHumanLine(deps, ` API Base URL: ${saved.baseUrl}`);
|
|
1160
1042
|
writeHumanLine(deps, ` Expires At: ${new Date(saved.expiresAt).toISOString()}`);
|
|
1161
1043
|
return 0;
|
|
1162
1044
|
}
|
|
1163
1045
|
async function runLogout(args, deps) {
|
|
1164
|
-
const { baseUrl
|
|
1165
|
-
deps.store.writeActiveCloudTarget({
|
|
1166
|
-
|
|
1167
|
-
siteUrl
|
|
1168
|
-
});
|
|
1169
|
-
const saved = deps.store.readCloudCredential({
|
|
1170
|
-
baseUrl,
|
|
1171
|
-
siteUrl
|
|
1172
|
-
});
|
|
1046
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store);
|
|
1047
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1048
|
+
const saved = deps.store.readCloudCredential({ baseUrl });
|
|
1173
1049
|
if (saved) {
|
|
1174
1050
|
try {
|
|
1175
|
-
await revokeToken(
|
|
1051
|
+
await revokeToken(
|
|
1052
|
+
resolveAuthSiteUrl(deps.env),
|
|
1053
|
+
saved.refreshToken,
|
|
1054
|
+
deps.fetchFn
|
|
1055
|
+
);
|
|
1176
1056
|
} catch {
|
|
1177
1057
|
}
|
|
1178
1058
|
}
|
|
1179
|
-
deps.store.clearCloudCredential({
|
|
1180
|
-
baseUrl,
|
|
1181
|
-
siteUrl
|
|
1182
|
-
});
|
|
1059
|
+
deps.store.clearCloudCredential({ baseUrl });
|
|
1183
1060
|
if (args.json) {
|
|
1184
1061
|
writeJsonLine(deps, {
|
|
1185
1062
|
loggedOut: true,
|
|
1186
|
-
baseUrl
|
|
1187
|
-
siteUrl
|
|
1063
|
+
baseUrl
|
|
1188
1064
|
});
|
|
1189
1065
|
return 0;
|
|
1190
1066
|
}
|
|
1191
|
-
writeHumanLine(
|
|
1192
|
-
deps,
|
|
1193
|
-
`Opensteer CLI login removed for ${siteUrl}.`
|
|
1194
|
-
);
|
|
1067
|
+
writeHumanLine(deps, `Opensteer CLI login removed for ${baseUrl}.`);
|
|
1195
1068
|
return 0;
|
|
1196
1069
|
}
|
|
1197
1070
|
async function runOpensteerAuthCli(rawArgs, overrideDeps = {}) {
|