opensteer 0.6.1 → 0.6.2
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-3FNI7JUU.js → chunk-7RMY26CM.js} +82 -187
- package/dist/cli/auth.cjs +82 -187
- package/dist/cli/auth.d.cts +0 -6
- package/dist/cli/auth.d.ts +0 -6
- package/dist/cli/auth.js +1 -1
- package/dist/cli/profile.cjs +59 -155
- package/dist/cli/profile.d.cts +0 -2
- package/dist/cli/profile.d.ts +0 -2
- package/dist/cli/profile.js +1 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -182,11 +182,10 @@ opensteer auth logout
|
|
|
182
182
|
`--no-browser` on remote shells, containers, or CI and paste the printed URL
|
|
183
183
|
into a browser manually. In `--json` mode, login prompts go to stderr and the
|
|
184
184
|
final JSON result stays on stdout.
|
|
185
|
-
- Saved machine logins remain scoped per resolved cloud host (`baseUrl`
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
different host.
|
|
185
|
+
- Saved machine logins remain scoped per resolved cloud API host (`baseUrl`).
|
|
186
|
+
The CLI also remembers the last selected cloud host, so `opensteer auth
|
|
187
|
+
status`, `opensteer auth logout`, and other cloud commands reuse it by
|
|
188
|
+
default unless `--base-url` or env vars select a different host.
|
|
190
189
|
|
|
191
190
|
- `OPENSTEER_BASE_URL` overrides the default cloud host
|
|
192
191
|
- `OPENSTEER_ACCESS_TOKEN` provides bearer auth for cloud commands
|
package/bin/opensteer.mjs
CHANGED
|
@@ -1149,7 +1149,6 @@ Environment:
|
|
|
1149
1149
|
OPENSTEER_API_KEY Cloud API key credential
|
|
1150
1150
|
OPENSTEER_ACCESS_TOKEN Cloud bearer access token credential
|
|
1151
1151
|
OPENSTEER_BASE_URL Override cloud control-plane base URL
|
|
1152
|
-
OPENSTEER_CLOUD_SITE_URL Override cloud site URL for device login endpoints
|
|
1153
1152
|
OPENSTEER_AUTH_SCHEME Cloud auth scheme: api-key (default) or bearer
|
|
1154
1153
|
OPENSTEER_REMOTE_ANNOUNCE Cloud session announcement policy: always (default), off, tty
|
|
1155
1154
|
`)
|
|
@@ -100,13 +100,10 @@ import { createHash } from "crypto";
|
|
|
100
100
|
import fs from "fs";
|
|
101
101
|
import os from "os";
|
|
102
102
|
import path from "path";
|
|
103
|
-
var METADATA_VERSION =
|
|
104
|
-
var ACTIVE_TARGET_VERSION =
|
|
103
|
+
var METADATA_VERSION = 2;
|
|
104
|
+
var ACTIVE_TARGET_VERSION = 2;
|
|
105
105
|
var KEYCHAIN_SERVICE = "com.opensteer.cli.cloud";
|
|
106
106
|
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
107
|
var ACTIVE_TARGET_FILE_NAME = "cli-target.json";
|
|
111
108
|
var MachineCredentialStore = class {
|
|
112
109
|
authDir;
|
|
@@ -121,8 +118,11 @@ var MachineCredentialStore = class {
|
|
|
121
118
|
this.warn = options.warn ?? (() => void 0);
|
|
122
119
|
}
|
|
123
120
|
readCloudCredential(target) {
|
|
124
|
-
const
|
|
125
|
-
return this.readCredentialSlot(
|
|
121
|
+
const normalizedTarget = normalizeCloudCredentialTarget(target);
|
|
122
|
+
return this.readCredentialSlot(
|
|
123
|
+
resolveCredentialSlot(this.authDir, normalizedTarget),
|
|
124
|
+
normalizedTarget
|
|
125
|
+
);
|
|
126
126
|
}
|
|
127
127
|
writeCloudCredential(args) {
|
|
128
128
|
const accessToken = args.accessToken.trim();
|
|
@@ -130,12 +130,8 @@ var MachineCredentialStore = class {
|
|
|
130
130
|
if (!accessToken || !refreshToken2) {
|
|
131
131
|
throw new Error("Cannot persist empty machine credential secrets.");
|
|
132
132
|
}
|
|
133
|
-
const baseUrl = normalizeCredentialUrl(args.baseUrl
|
|
134
|
-
const
|
|
135
|
-
const slot = resolveCredentialSlot(this.authDir, {
|
|
136
|
-
baseUrl,
|
|
137
|
-
siteUrl
|
|
138
|
-
});
|
|
133
|
+
const baseUrl = normalizeCredentialUrl(args.baseUrl);
|
|
134
|
+
const slot = resolveCredentialSlot(this.authDir, { baseUrl });
|
|
139
135
|
ensureDirectory(this.authDir);
|
|
140
136
|
const secretPayload = {
|
|
141
137
|
accessToken,
|
|
@@ -162,7 +158,6 @@ var MachineCredentialStore = class {
|
|
|
162
158
|
version: METADATA_VERSION,
|
|
163
159
|
secretBackend,
|
|
164
160
|
baseUrl,
|
|
165
|
-
siteUrl,
|
|
166
161
|
scope: args.scope,
|
|
167
162
|
obtainedAt: args.obtainedAt,
|
|
168
163
|
expiresAt: args.expiresAt,
|
|
@@ -174,23 +169,18 @@ var MachineCredentialStore = class {
|
|
|
174
169
|
return readActiveCloudTargetMetadata(resolveActiveTargetPath(this.authDir));
|
|
175
170
|
}
|
|
176
171
|
writeActiveCloudTarget(target) {
|
|
177
|
-
const baseUrl = normalizeCredentialUrl(target.baseUrl
|
|
178
|
-
const siteUrl = normalizeCredentialUrl(target.siteUrl, "siteUrl");
|
|
172
|
+
const baseUrl = normalizeCredentialUrl(target.baseUrl);
|
|
179
173
|
ensureDirectory(this.authDir);
|
|
180
174
|
writeJsonFile(resolveActiveTargetPath(this.authDir), {
|
|
181
175
|
version: ACTIVE_TARGET_VERSION,
|
|
182
176
|
baseUrl,
|
|
183
|
-
siteUrl,
|
|
184
177
|
updatedAt: Date.now()
|
|
185
178
|
});
|
|
186
179
|
}
|
|
187
180
|
clearCloudCredential(target) {
|
|
188
|
-
this.clearCredentialSlot(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (legacyMetadata && matchesCredentialTarget(legacyMetadata, target)) {
|
|
192
|
-
this.clearCredentialSlot(legacySlot);
|
|
193
|
-
}
|
|
181
|
+
this.clearCredentialSlot(
|
|
182
|
+
resolveCredentialSlot(this.authDir, normalizeCloudCredentialTarget(target))
|
|
183
|
+
);
|
|
194
184
|
}
|
|
195
185
|
readCredentialSlot(slot, target) {
|
|
196
186
|
const metadata = readMetadata(slot.metadataPath);
|
|
@@ -206,7 +196,6 @@ var MachineCredentialStore = class {
|
|
|
206
196
|
}
|
|
207
197
|
return {
|
|
208
198
|
baseUrl: metadata.baseUrl,
|
|
209
|
-
siteUrl: metadata.siteUrl,
|
|
210
199
|
scope: metadata.scope,
|
|
211
200
|
accessToken: secret.accessToken,
|
|
212
201
|
refreshToken: secret.refreshToken,
|
|
@@ -214,16 +203,6 @@ var MachineCredentialStore = class {
|
|
|
214
203
|
expiresAt: metadata.expiresAt
|
|
215
204
|
};
|
|
216
205
|
}
|
|
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
206
|
readSecret(slot, backend) {
|
|
228
207
|
if (backend === "keychain" && this.keychain) {
|
|
229
208
|
try {
|
|
@@ -264,9 +243,8 @@ function createMachineCredentialStore(options = {}) {
|
|
|
264
243
|
return new MachineCredentialStore(options);
|
|
265
244
|
}
|
|
266
245
|
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);
|
|
246
|
+
const normalizedBaseUrl = normalizeCredentialUrl(target.baseUrl);
|
|
247
|
+
const storageKey = createHash("sha256").update(normalizedBaseUrl).digest("hex").slice(0, 24);
|
|
270
248
|
return {
|
|
271
249
|
keychainAccount: `${KEYCHAIN_ACCOUNT_PREFIX}${storageKey}`,
|
|
272
250
|
metadataPath: path.join(authDir, `cli-login.${storageKey}.json`),
|
|
@@ -276,26 +254,24 @@ function resolveCredentialSlot(authDir, target) {
|
|
|
276
254
|
)
|
|
277
255
|
};
|
|
278
256
|
}
|
|
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
257
|
function resolveActiveTargetPath(authDir) {
|
|
287
258
|
return path.join(authDir, ACTIVE_TARGET_FILE_NAME);
|
|
288
259
|
}
|
|
289
260
|
function matchesCredentialTarget(value, target) {
|
|
290
|
-
return normalizeCredentialUrl(value.baseUrl
|
|
261
|
+
return normalizeCredentialUrl(value.baseUrl) === normalizeCredentialUrl(target.baseUrl);
|
|
291
262
|
}
|
|
292
|
-
function normalizeCredentialUrl(value
|
|
263
|
+
function normalizeCredentialUrl(value) {
|
|
293
264
|
const normalized = stripTrailingSlashes(value.trim());
|
|
294
265
|
if (!normalized) {
|
|
295
|
-
throw new Error(
|
|
266
|
+
throw new Error("Cannot persist machine credential without baseUrl.");
|
|
296
267
|
}
|
|
297
268
|
return normalized;
|
|
298
269
|
}
|
|
270
|
+
function normalizeCloudCredentialTarget(target) {
|
|
271
|
+
return {
|
|
272
|
+
baseUrl: normalizeCredentialUrl(target.baseUrl)
|
|
273
|
+
};
|
|
274
|
+
}
|
|
299
275
|
function resolveConfigDir(appName, env) {
|
|
300
276
|
if (process.platform === "win32") {
|
|
301
277
|
const appData = env.APPDATA?.trim() || path.join(os.homedir(), "AppData", "Roaming");
|
|
@@ -334,7 +310,6 @@ function readMetadata(filePath) {
|
|
|
334
310
|
return null;
|
|
335
311
|
}
|
|
336
312
|
if (typeof parsed.baseUrl !== "string" || !parsed.baseUrl.trim()) return null;
|
|
337
|
-
if (typeof parsed.siteUrl !== "string" || !parsed.siteUrl.trim()) return null;
|
|
338
313
|
if (!Array.isArray(parsed.scope)) return null;
|
|
339
314
|
if (typeof parsed.obtainedAt !== "number") return null;
|
|
340
315
|
if (typeof parsed.expiresAt !== "number") return null;
|
|
@@ -343,7 +318,6 @@ function readMetadata(filePath) {
|
|
|
343
318
|
version: parsed.version,
|
|
344
319
|
secretBackend: parsed.secretBackend,
|
|
345
320
|
baseUrl: parsed.baseUrl,
|
|
346
|
-
siteUrl: parsed.siteUrl,
|
|
347
321
|
scope: parsed.scope.filter(
|
|
348
322
|
(value) => typeof value === "string"
|
|
349
323
|
),
|
|
@@ -368,12 +342,8 @@ function readActiveCloudTargetMetadata(filePath) {
|
|
|
368
342
|
if (typeof parsed.baseUrl !== "string" || !parsed.baseUrl.trim()) {
|
|
369
343
|
return null;
|
|
370
344
|
}
|
|
371
|
-
if (typeof parsed.siteUrl !== "string" || !parsed.siteUrl.trim()) {
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
345
|
return {
|
|
375
|
-
baseUrl: parsed.baseUrl
|
|
376
|
-
siteUrl: parsed.siteUrl
|
|
346
|
+
baseUrl: parsed.baseUrl
|
|
377
347
|
};
|
|
378
348
|
} catch {
|
|
379
349
|
return null;
|
|
@@ -398,14 +368,13 @@ function readSecretFile(filePath) {
|
|
|
398
368
|
return null;
|
|
399
369
|
}
|
|
400
370
|
try {
|
|
401
|
-
|
|
402
|
-
return parseSecretPayload(raw);
|
|
371
|
+
return parseSecretPayload(fs.readFileSync(filePath, "utf8"));
|
|
403
372
|
} catch {
|
|
404
373
|
return null;
|
|
405
374
|
}
|
|
406
375
|
}
|
|
407
|
-
function writeJsonFile(filePath,
|
|
408
|
-
fs.writeFileSync(filePath, JSON.stringify(
|
|
376
|
+
function writeJsonFile(filePath, value, options = {}) {
|
|
377
|
+
fs.writeFileSync(filePath, JSON.stringify(value, null, 2), {
|
|
409
378
|
encoding: "utf8",
|
|
410
379
|
mode: options.mode ?? 384
|
|
411
380
|
});
|
|
@@ -436,11 +405,12 @@ Commands:
|
|
|
436
405
|
|
|
437
406
|
Options:
|
|
438
407
|
--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
408
|
--json JSON output (login prompts go to stderr)
|
|
441
409
|
--no-browser Do not auto-open your default browser during login
|
|
442
410
|
-h, --help Show this help
|
|
443
411
|
`;
|
|
412
|
+
var DEFAULT_AUTH_SITE_URL = "https://opensteer.com";
|
|
413
|
+
var INTERNAL_AUTH_SITE_URL_ENV = "OPENSTEER_INTERNAL_AUTH_SITE_URL";
|
|
444
414
|
function createDefaultDeps() {
|
|
445
415
|
const env = process.env;
|
|
446
416
|
return {
|
|
@@ -492,13 +462,6 @@ function parseAuthCommonArgs(rawArgs) {
|
|
|
492
462
|
i = value.nextIndex;
|
|
493
463
|
continue;
|
|
494
464
|
}
|
|
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
465
|
return {
|
|
503
466
|
args,
|
|
504
467
|
error: `Unsupported option "${arg}".`
|
|
@@ -568,16 +531,19 @@ function resolveBaseUrl(provided, env) {
|
|
|
568
531
|
assertSecureUrl(baseUrl, "--base-url");
|
|
569
532
|
return baseUrl;
|
|
570
533
|
}
|
|
571
|
-
function
|
|
572
|
-
const
|
|
573
|
-
(
|
|
534
|
+
function resolveAuthSiteUrl(env) {
|
|
535
|
+
const authSiteUrl = normalizeCloudBaseUrl(
|
|
536
|
+
(env[INTERNAL_AUTH_SITE_URL_ENV] || DEFAULT_AUTH_SITE_URL).trim()
|
|
537
|
+
);
|
|
538
|
+
assertSecureUrl(
|
|
539
|
+
authSiteUrl,
|
|
540
|
+
`environment variable ${INTERNAL_AUTH_SITE_URL_ENV}`
|
|
574
541
|
);
|
|
575
|
-
|
|
576
|
-
return siteUrl;
|
|
542
|
+
return authSiteUrl;
|
|
577
543
|
}
|
|
578
|
-
function hasExplicitCloudTargetSelection(providedBaseUrl,
|
|
544
|
+
function hasExplicitCloudTargetSelection(providedBaseUrl, env) {
|
|
579
545
|
return Boolean(
|
|
580
|
-
providedBaseUrl?.trim() ||
|
|
546
|
+
providedBaseUrl?.trim() || env.OPENSTEER_BASE_URL?.trim()
|
|
581
547
|
);
|
|
582
548
|
}
|
|
583
549
|
function readRememberedCloudTarget(store) {
|
|
@@ -587,57 +553,21 @@ function readRememberedCloudTarget(store) {
|
|
|
587
553
|
}
|
|
588
554
|
try {
|
|
589
555
|
const baseUrl = normalizeCloudBaseUrl(activeTarget.baseUrl);
|
|
590
|
-
const siteUrl = normalizeCloudBaseUrl(activeTarget.siteUrl);
|
|
591
556
|
assertSecureUrl(baseUrl, "--base-url");
|
|
592
|
-
|
|
593
|
-
return {
|
|
594
|
-
baseUrl,
|
|
595
|
-
siteUrl
|
|
596
|
-
};
|
|
557
|
+
return { baseUrl };
|
|
597
558
|
} catch {
|
|
598
559
|
return null;
|
|
599
560
|
}
|
|
600
561
|
}
|
|
601
|
-
function resolveCloudTarget(args, env, store) {
|
|
602
|
-
if (!hasExplicitCloudTargetSelection(args.baseUrl,
|
|
562
|
+
function resolveCloudTarget(args, env, store, options = {}) {
|
|
563
|
+
if (options.allowRememberedTarget !== false && !hasExplicitCloudTargetSelection(args.baseUrl, env)) {
|
|
603
564
|
const rememberedTarget = readRememberedCloudTarget(store);
|
|
604
565
|
if (rememberedTarget) {
|
|
605
566
|
return rememberedTarget;
|
|
606
567
|
}
|
|
607
568
|
}
|
|
608
569
|
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());
|
|
570
|
+
return { baseUrl };
|
|
641
571
|
}
|
|
642
572
|
function assertSecureUrl(value, flag) {
|
|
643
573
|
let parsed;
|
|
@@ -712,10 +642,10 @@ function parseCliOauthError(error) {
|
|
|
712
642
|
interval: typeof root.interval === "number" ? root.interval : void 0
|
|
713
643
|
};
|
|
714
644
|
}
|
|
715
|
-
async function startDeviceAuthorization(
|
|
645
|
+
async function startDeviceAuthorization(authSiteUrl, fetchFn) {
|
|
716
646
|
const response = await postJson(
|
|
717
647
|
fetchFn,
|
|
718
|
-
`${
|
|
648
|
+
`${authSiteUrl}/api/cli-auth/device/start`,
|
|
719
649
|
{
|
|
720
650
|
scope: ["cloud:browser"]
|
|
721
651
|
}
|
|
@@ -725,24 +655,24 @@ async function startDeviceAuthorization(siteUrl, fetchFn) {
|
|
|
725
655
|
}
|
|
726
656
|
return response;
|
|
727
657
|
}
|
|
728
|
-
async function pollDeviceToken(
|
|
658
|
+
async function pollDeviceToken(authSiteUrl, deviceCode, fetchFn) {
|
|
729
659
|
return await postJson(
|
|
730
660
|
fetchFn,
|
|
731
|
-
`${
|
|
661
|
+
`${authSiteUrl}/api/cli-auth/device/token`,
|
|
732
662
|
{
|
|
733
663
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
734
664
|
device_code: deviceCode
|
|
735
665
|
}
|
|
736
666
|
);
|
|
737
667
|
}
|
|
738
|
-
async function refreshToken(
|
|
739
|
-
return await postJson(fetchFn, `${
|
|
668
|
+
async function refreshToken(authSiteUrl, refreshTokenValue, fetchFn) {
|
|
669
|
+
return await postJson(fetchFn, `${authSiteUrl}/api/cli-auth/token`, {
|
|
740
670
|
grant_type: "refresh_token",
|
|
741
671
|
refresh_token: refreshTokenValue
|
|
742
672
|
});
|
|
743
673
|
}
|
|
744
|
-
async function revokeToken(
|
|
745
|
-
await postJson(fetchFn, `${
|
|
674
|
+
async function revokeToken(authSiteUrl, refreshTokenValue, fetchFn) {
|
|
675
|
+
await postJson(fetchFn, `${authSiteUrl}/api/cli-auth/revoke`, {
|
|
746
676
|
token: refreshTokenValue
|
|
747
677
|
});
|
|
748
678
|
}
|
|
@@ -759,7 +689,7 @@ async function openDefaultBrowser(url) {
|
|
|
759
689
|
}
|
|
760
690
|
}
|
|
761
691
|
async function runDeviceLoginFlow(args) {
|
|
762
|
-
const start = await startDeviceAuthorization(args.
|
|
692
|
+
const start = await startDeviceAuthorization(args.authSiteUrl, args.fetchFn);
|
|
763
693
|
if (args.openBrowser) {
|
|
764
694
|
args.writeProgress(
|
|
765
695
|
"Opening your default browser for Opensteer CLI authentication.\n"
|
|
@@ -804,7 +734,7 @@ ${start.verification_uri_complete}
|
|
|
804
734
|
await args.sleep(pollIntervalMs);
|
|
805
735
|
try {
|
|
806
736
|
const tokenPayload = await pollDeviceToken(
|
|
807
|
-
args.
|
|
737
|
+
args.authSiteUrl,
|
|
808
738
|
start.device_code,
|
|
809
739
|
args.fetchFn
|
|
810
740
|
);
|
|
@@ -852,7 +782,7 @@ ${start.verification_uri_complete}
|
|
|
852
782
|
}
|
|
853
783
|
async function refreshSavedCredential(saved, deps) {
|
|
854
784
|
const tokenPayload = await refreshToken(
|
|
855
|
-
|
|
785
|
+
resolveAuthSiteUrl(deps.env),
|
|
856
786
|
saved.refreshToken,
|
|
857
787
|
deps.fetchFn
|
|
858
788
|
);
|
|
@@ -865,7 +795,6 @@ async function refreshSavedCredential(saved, deps) {
|
|
|
865
795
|
};
|
|
866
796
|
deps.store.writeCloudCredential({
|
|
867
797
|
baseUrl: saved.baseUrl,
|
|
868
|
-
siteUrl: saved.siteUrl,
|
|
869
798
|
scope: updated.scope,
|
|
870
799
|
accessToken: updated.accessToken,
|
|
871
800
|
refreshToken: updated.refreshToken,
|
|
@@ -894,8 +823,7 @@ async function ensureSavedCredentialIsFresh(saved, deps) {
|
|
|
894
823
|
const oauth = parseCliOauthError(error.body);
|
|
895
824
|
if (oauth?.error === "invalid_grant" || oauth?.error === "expired_token") {
|
|
896
825
|
deps.store.clearCloudCredential({
|
|
897
|
-
baseUrl: saved.baseUrl
|
|
898
|
-
siteUrl: saved.siteUrl
|
|
826
|
+
baseUrl: saved.baseUrl
|
|
899
827
|
});
|
|
900
828
|
return null;
|
|
901
829
|
}
|
|
@@ -995,7 +923,7 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
995
923
|
`);
|
|
996
924
|
}
|
|
997
925
|
});
|
|
998
|
-
const { baseUrl
|
|
926
|
+
const { baseUrl } = resolveCloudTarget(options, env, store);
|
|
999
927
|
const initialCredential = resolveCloudCredential({
|
|
1000
928
|
env,
|
|
1001
929
|
apiKeyFlag: options.apiKeyFlag,
|
|
@@ -1003,11 +931,9 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1003
931
|
});
|
|
1004
932
|
let credential = initialCredential;
|
|
1005
933
|
if (!credential) {
|
|
1006
|
-
const saved = store.readCloudCredential({
|
|
1007
|
-
baseUrl,
|
|
1008
|
-
siteUrl
|
|
1009
|
-
});
|
|
934
|
+
const saved = store.readCloudCredential({ baseUrl });
|
|
1010
935
|
const freshSaved = saved ? await ensureSavedCredentialIsFresh(saved, {
|
|
936
|
+
env,
|
|
1011
937
|
fetchFn,
|
|
1012
938
|
store,
|
|
1013
939
|
now,
|
|
@@ -1025,7 +951,7 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1025
951
|
if (!credential) {
|
|
1026
952
|
if (options.autoLoginIfNeeded && (options.interactive ?? false)) {
|
|
1027
953
|
const loggedIn = await runDeviceLoginFlow({
|
|
1028
|
-
|
|
954
|
+
authSiteUrl: resolveAuthSiteUrl(env),
|
|
1029
955
|
fetchFn,
|
|
1030
956
|
writeProgress,
|
|
1031
957
|
openExternalUrl,
|
|
@@ -1035,7 +961,6 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1035
961
|
});
|
|
1036
962
|
store.writeCloudCredential({
|
|
1037
963
|
baseUrl,
|
|
1038
|
-
siteUrl,
|
|
1039
964
|
scope: loggedIn.scope,
|
|
1040
965
|
accessToken: loggedIn.accessToken,
|
|
1041
966
|
refreshToken: loggedIn.refreshToken,
|
|
@@ -1053,28 +978,25 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1053
978
|
throw new Error(toAuthMissingMessage(options.commandName));
|
|
1054
979
|
}
|
|
1055
980
|
}
|
|
1056
|
-
store.writeActiveCloudTarget({
|
|
1057
|
-
baseUrl,
|
|
1058
|
-
siteUrl
|
|
1059
|
-
});
|
|
981
|
+
store.writeActiveCloudTarget({ baseUrl });
|
|
1060
982
|
applyCloudCredentialToEnv(env, credential);
|
|
1061
983
|
env.OPENSTEER_BASE_URL = baseUrl;
|
|
1062
|
-
env.OPENSTEER_CLOUD_SITE_URL = siteUrl;
|
|
1063
984
|
return {
|
|
1064
985
|
token: credential.token,
|
|
1065
986
|
authScheme: credential.authScheme,
|
|
1066
987
|
source: credential.source,
|
|
1067
988
|
kind: credential.kind,
|
|
1068
|
-
baseUrl
|
|
1069
|
-
siteUrl
|
|
989
|
+
baseUrl
|
|
1070
990
|
};
|
|
1071
991
|
}
|
|
1072
992
|
async function runLogin(args, deps) {
|
|
1073
|
-
const { baseUrl
|
|
993
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store, {
|
|
994
|
+
allowRememberedTarget: false
|
|
995
|
+
});
|
|
1074
996
|
const writeProgress = args.json ? deps.writeStderr : deps.writeStdout;
|
|
1075
997
|
const browserOpenMode = describeBrowserOpenMode(args, deps);
|
|
1076
998
|
const login = await runDeviceLoginFlow({
|
|
1077
|
-
|
|
999
|
+
authSiteUrl: resolveAuthSiteUrl(deps.env),
|
|
1078
1000
|
fetchFn: deps.fetchFn,
|
|
1079
1001
|
writeProgress,
|
|
1080
1002
|
openExternalUrl: deps.openExternalUrl,
|
|
@@ -1085,22 +1007,17 @@ async function runLogin(args, deps) {
|
|
|
1085
1007
|
});
|
|
1086
1008
|
deps.store.writeCloudCredential({
|
|
1087
1009
|
baseUrl,
|
|
1088
|
-
siteUrl,
|
|
1089
1010
|
scope: login.scope,
|
|
1090
1011
|
accessToken: login.accessToken,
|
|
1091
1012
|
refreshToken: login.refreshToken,
|
|
1092
1013
|
obtainedAt: deps.now(),
|
|
1093
1014
|
expiresAt: login.expiresAt
|
|
1094
1015
|
});
|
|
1095
|
-
deps.store.writeActiveCloudTarget({
|
|
1096
|
-
baseUrl,
|
|
1097
|
-
siteUrl
|
|
1098
|
-
});
|
|
1016
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1099
1017
|
if (args.json) {
|
|
1100
1018
|
writeJsonLine(deps, {
|
|
1101
1019
|
loggedIn: true,
|
|
1102
1020
|
baseUrl,
|
|
1103
|
-
siteUrl,
|
|
1104
1021
|
expiresAt: login.expiresAt,
|
|
1105
1022
|
scope: login.scope,
|
|
1106
1023
|
authSource: "device"
|
|
@@ -1108,33 +1025,22 @@ async function runLogin(args, deps) {
|
|
|
1108
1025
|
return 0;
|
|
1109
1026
|
}
|
|
1110
1027
|
writeHumanLine(deps, "Opensteer CLI login successful.");
|
|
1111
|
-
writeHumanLine(deps, ` Site URL: ${siteUrl}`);
|
|
1112
1028
|
writeHumanLine(deps, ` API Base URL: ${baseUrl}`);
|
|
1113
1029
|
writeHumanLine(deps, ` Expires At: ${new Date(login.expiresAt).toISOString()}`);
|
|
1114
1030
|
return 0;
|
|
1115
1031
|
}
|
|
1116
1032
|
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
|
-
});
|
|
1033
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store);
|
|
1034
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1035
|
+
const saved = deps.store.readCloudCredential({ baseUrl });
|
|
1126
1036
|
if (!saved) {
|
|
1127
1037
|
if (args.json) {
|
|
1128
1038
|
writeJsonLine(deps, {
|
|
1129
1039
|
loggedIn: false,
|
|
1130
|
-
baseUrl
|
|
1131
|
-
siteUrl
|
|
1040
|
+
baseUrl
|
|
1132
1041
|
});
|
|
1133
1042
|
} else {
|
|
1134
|
-
writeHumanLine(
|
|
1135
|
-
deps,
|
|
1136
|
-
`Opensteer CLI is not logged in for ${siteUrl}.`
|
|
1137
|
-
);
|
|
1043
|
+
writeHumanLine(deps, `Opensteer CLI is not logged in for ${baseUrl}.`);
|
|
1138
1044
|
}
|
|
1139
1045
|
return 0;
|
|
1140
1046
|
}
|
|
@@ -1145,7 +1051,6 @@ async function runStatus(args, deps) {
|
|
|
1145
1051
|
loggedIn: true,
|
|
1146
1052
|
expired,
|
|
1147
1053
|
baseUrl: saved.baseUrl,
|
|
1148
|
-
siteUrl: saved.siteUrl,
|
|
1149
1054
|
expiresAt: saved.expiresAt,
|
|
1150
1055
|
scope: saved.scope
|
|
1151
1056
|
});
|
|
@@ -1155,43 +1060,33 @@ async function runStatus(args, deps) {
|
|
|
1155
1060
|
deps,
|
|
1156
1061
|
expired ? "Opensteer CLI has a saved login, but the access token is expired." : "Opensteer CLI is logged in."
|
|
1157
1062
|
);
|
|
1158
|
-
writeHumanLine(deps, ` Site URL: ${saved.siteUrl}`);
|
|
1159
1063
|
writeHumanLine(deps, ` API Base URL: ${saved.baseUrl}`);
|
|
1160
1064
|
writeHumanLine(deps, ` Expires At: ${new Date(saved.expiresAt).toISOString()}`);
|
|
1161
1065
|
return 0;
|
|
1162
1066
|
}
|
|
1163
1067
|
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
|
-
});
|
|
1068
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store);
|
|
1069
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1070
|
+
const saved = deps.store.readCloudCredential({ baseUrl });
|
|
1173
1071
|
if (saved) {
|
|
1174
1072
|
try {
|
|
1175
|
-
await revokeToken(
|
|
1073
|
+
await revokeToken(
|
|
1074
|
+
resolveAuthSiteUrl(deps.env),
|
|
1075
|
+
saved.refreshToken,
|
|
1076
|
+
deps.fetchFn
|
|
1077
|
+
);
|
|
1176
1078
|
} catch {
|
|
1177
1079
|
}
|
|
1178
1080
|
}
|
|
1179
|
-
deps.store.clearCloudCredential({
|
|
1180
|
-
baseUrl,
|
|
1181
|
-
siteUrl
|
|
1182
|
-
});
|
|
1081
|
+
deps.store.clearCloudCredential({ baseUrl });
|
|
1183
1082
|
if (args.json) {
|
|
1184
1083
|
writeJsonLine(deps, {
|
|
1185
1084
|
loggedOut: true,
|
|
1186
|
-
baseUrl
|
|
1187
|
-
siteUrl
|
|
1085
|
+
baseUrl
|
|
1188
1086
|
});
|
|
1189
1087
|
return 0;
|
|
1190
1088
|
}
|
|
1191
|
-
writeHumanLine(
|
|
1192
|
-
deps,
|
|
1193
|
-
`Opensteer CLI login removed for ${siteUrl}.`
|
|
1194
|
-
);
|
|
1089
|
+
writeHumanLine(deps, `Opensteer CLI login removed for ${baseUrl}.`);
|
|
1195
1090
|
return 0;
|
|
1196
1091
|
}
|
|
1197
1092
|
async function runOpensteerAuthCli(rawArgs, overrideDeps = {}) {
|