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
package/dist/cli/auth.cjs
CHANGED
|
@@ -94,6 +94,65 @@ function toNonEmptyString(value) {
|
|
|
94
94
|
return normalized.length ? normalized : void 0;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
// src/cloud/credential-selection.ts
|
|
98
|
+
function selectCloudCredential(options) {
|
|
99
|
+
const apiKey = normalizeNonEmptyString(options.apiKey);
|
|
100
|
+
const accessToken = normalizeNonEmptyString(options.accessToken);
|
|
101
|
+
if (apiKey) {
|
|
102
|
+
if (options.authScheme === "bearer") {
|
|
103
|
+
return {
|
|
104
|
+
apiKey,
|
|
105
|
+
authScheme: "bearer",
|
|
106
|
+
kind: "access-token",
|
|
107
|
+
token: apiKey,
|
|
108
|
+
compatibilityBearerApiKey: true
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
apiKey,
|
|
113
|
+
authScheme: "api-key",
|
|
114
|
+
kind: "api-key",
|
|
115
|
+
token: apiKey
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (accessToken) {
|
|
119
|
+
return {
|
|
120
|
+
accessToken,
|
|
121
|
+
authScheme: "bearer",
|
|
122
|
+
kind: "access-token",
|
|
123
|
+
token: accessToken
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
function selectCloudCredentialByPrecedence(layers, authScheme) {
|
|
129
|
+
for (const layer of layers) {
|
|
130
|
+
const hasApiKey = layer.hasApiKey ?? Object.prototype.hasOwnProperty.call(layer, "apiKey");
|
|
131
|
+
const hasAccessToken = layer.hasAccessToken ?? Object.prototype.hasOwnProperty.call(layer, "accessToken");
|
|
132
|
+
if (!hasApiKey && !hasAccessToken) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
source: layer.source,
|
|
137
|
+
apiKey: layer.apiKey,
|
|
138
|
+
accessToken: layer.accessToken,
|
|
139
|
+
hasApiKey,
|
|
140
|
+
hasAccessToken,
|
|
141
|
+
credential: selectCloudCredential({
|
|
142
|
+
apiKey: layer.apiKey,
|
|
143
|
+
accessToken: layer.accessToken,
|
|
144
|
+
authScheme: layer.authScheme ?? authScheme
|
|
145
|
+
})
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
function normalizeNonEmptyString(value) {
|
|
151
|
+
if (typeof value !== "string") return void 0;
|
|
152
|
+
const normalized = value.trim();
|
|
153
|
+
return normalized.length ? normalized : void 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
97
156
|
// src/config.ts
|
|
98
157
|
var DEFAULT_CONFIG = {
|
|
99
158
|
browser: {
|
|
@@ -386,11 +445,6 @@ function normalizeCloudOptions(value) {
|
|
|
386
445
|
}
|
|
387
446
|
return value;
|
|
388
447
|
}
|
|
389
|
-
function normalizeNonEmptyString(value) {
|
|
390
|
-
if (typeof value !== "string") return void 0;
|
|
391
|
-
const normalized = value.trim();
|
|
392
|
-
return normalized.length ? normalized : void 0;
|
|
393
|
-
}
|
|
394
448
|
function parseCloudEnabled(value, source) {
|
|
395
449
|
if (value == null) return void 0;
|
|
396
450
|
if (typeof value === "boolean") return value;
|
|
@@ -399,6 +453,18 @@ function parseCloudEnabled(value, source) {
|
|
|
399
453
|
`Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
|
|
400
454
|
);
|
|
401
455
|
}
|
|
456
|
+
function resolveCloudCredentialFields(selectedLayer) {
|
|
457
|
+
const credential = selectedLayer?.credential;
|
|
458
|
+
if (!credential) return {};
|
|
459
|
+
if (credential.kind === "api-key" || credential.compatibilityBearerApiKey === true && selectedLayer?.source !== "env") {
|
|
460
|
+
return {
|
|
461
|
+
apiKey: credential.token
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
accessToken: credential.token
|
|
466
|
+
};
|
|
467
|
+
}
|
|
402
468
|
function resolveCloudSelection(config, env = process.env) {
|
|
403
469
|
const configCloud = parseCloudEnabled(config.cloud, "cloud");
|
|
404
470
|
if (configCloud !== void 0) {
|
|
@@ -435,6 +501,9 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
435
501
|
});
|
|
436
502
|
assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
|
|
437
503
|
assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
|
|
504
|
+
const fileCloudOptions = normalizeCloudOptions(fileConfig.cloud);
|
|
505
|
+
const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
|
|
506
|
+
const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
|
|
438
507
|
const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
|
|
439
508
|
const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
|
|
440
509
|
const env = resolveEnv(envRootDir, {
|
|
@@ -473,13 +542,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
473
542
|
const envAccessTokenRaw = resolveOpensteerAccessToken(env);
|
|
474
543
|
const envBaseUrl = resolveOpensteerBaseUrl(env);
|
|
475
544
|
const envAuthScheme = resolveOpensteerAuthScheme(env);
|
|
476
|
-
if (envApiKey && envAccessTokenRaw) {
|
|
477
|
-
throw new Error(
|
|
478
|
-
"OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
const envAccessToken = envAccessTokenRaw || (envAuthScheme === "bearer" ? envApiKey : void 0);
|
|
482
|
-
const envApiCredential = envAuthScheme === "bearer" && !envAccessTokenRaw ? void 0 : envApiKey;
|
|
483
545
|
const envCloudProfileId = resolveOpensteerCloudProfileId(env);
|
|
484
546
|
const envCloudProfileReuseIfActive = resolveOpensteerCloudProfileReuseIfActive(env);
|
|
485
547
|
const envCloudAnnounce = parseCloudAnnounce(
|
|
@@ -508,11 +570,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
508
570
|
const inputHasCloudBaseUrl = Boolean(
|
|
509
571
|
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
|
|
510
572
|
);
|
|
511
|
-
if (normalizeNonEmptyString(inputCloudOptions?.apiKey) && normalizeNonEmptyString(inputCloudOptions?.accessToken)) {
|
|
512
|
-
throw new Error(
|
|
513
|
-
"cloud.apiKey and cloud.accessToken are mutually exclusive. Set only one."
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
573
|
const cloudSelection = resolveCloudSelection({
|
|
517
574
|
cloud: resolved.cloud
|
|
518
575
|
}, env);
|
|
@@ -523,11 +580,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
523
580
|
accessToken: resolvedCloudAccessTokenRaw,
|
|
524
581
|
...resolvedCloudRest
|
|
525
582
|
} = resolvedCloud;
|
|
526
|
-
if (normalizeNonEmptyString(resolvedCloudApiKeyRaw) && normalizeNonEmptyString(resolvedCloudAccessTokenRaw)) {
|
|
527
|
-
throw new Error(
|
|
528
|
-
"Cloud config cannot include both apiKey and accessToken at the same time."
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
583
|
const resolvedCloudBrowserProfile = normalizeCloudBrowserProfileOptions(
|
|
532
584
|
resolvedCloud.browserProfile,
|
|
533
585
|
"resolved.cloud.browserProfile"
|
|
@@ -539,25 +591,40 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
539
591
|
const browserProfile = inputCloudBrowserProfile ?? envCloudBrowserProfile ?? resolvedCloudBrowserProfile;
|
|
540
592
|
let authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
|
|
541
593
|
const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
594
|
+
const selectedCredentialLayer = selectCloudCredentialByPrecedence(
|
|
595
|
+
[
|
|
596
|
+
{
|
|
597
|
+
source: "input",
|
|
598
|
+
apiKey: inputCloudOptions?.apiKey,
|
|
599
|
+
accessToken: inputCloudOptions?.accessToken,
|
|
600
|
+
hasApiKey: inputHasCloudApiKey,
|
|
601
|
+
hasAccessToken: inputHasCloudAccessToken
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
source: "env",
|
|
605
|
+
apiKey: envApiKey,
|
|
606
|
+
accessToken: envAccessTokenRaw,
|
|
607
|
+
hasApiKey: envApiKey !== void 0,
|
|
608
|
+
hasAccessToken: envAccessTokenRaw !== void 0
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
source: "file",
|
|
612
|
+
apiKey: fileCloudOptions?.apiKey,
|
|
613
|
+
accessToken: fileCloudOptions?.accessToken,
|
|
614
|
+
hasApiKey: fileHasCloudApiKey,
|
|
615
|
+
hasAccessToken: fileHasCloudAccessToken
|
|
616
|
+
}
|
|
617
|
+
],
|
|
618
|
+
authScheme
|
|
619
|
+
);
|
|
620
|
+
const { apiKey, accessToken } = resolveCloudCredentialFields(selectedCredentialLayer);
|
|
554
621
|
if (accessToken) {
|
|
555
622
|
authScheme = "bearer";
|
|
556
623
|
}
|
|
557
624
|
resolved.cloud = {
|
|
558
625
|
...resolvedCloudRest,
|
|
559
|
-
...
|
|
560
|
-
...
|
|
626
|
+
...apiKey ? { apiKey } : selectedCredentialLayer?.hasApiKey && !accessToken ? { apiKey: selectedCredentialLayer.apiKey } : {},
|
|
627
|
+
...accessToken ? { accessToken } : selectedCredentialLayer?.hasAccessToken && !apiKey ? { accessToken: selectedCredentialLayer.accessToken } : {},
|
|
561
628
|
authScheme,
|
|
562
629
|
announce,
|
|
563
630
|
...browserProfile ? { browserProfile } : {}
|
|
@@ -577,59 +644,21 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
577
644
|
|
|
578
645
|
// src/auth/credential-resolver.ts
|
|
579
646
|
function resolveCloudCredential(options) {
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
return {
|
|
587
|
-
kind: "access-token",
|
|
588
|
-
source: "flag",
|
|
589
|
-
token: flagAccessToken,
|
|
590
|
-
authScheme: "bearer"
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
if (flagApiKey) {
|
|
594
|
-
return {
|
|
595
|
-
kind: "api-key",
|
|
596
|
-
source: "flag",
|
|
597
|
-
token: flagApiKey,
|
|
598
|
-
authScheme: "api-key"
|
|
599
|
-
};
|
|
647
|
+
const flagCredential = selectCloudCredential({
|
|
648
|
+
apiKey: options.apiKeyFlag,
|
|
649
|
+
accessToken: options.accessTokenFlag
|
|
650
|
+
});
|
|
651
|
+
if (flagCredential) {
|
|
652
|
+
return toResolvedCloudCredential("flag", flagCredential);
|
|
600
653
|
}
|
|
601
654
|
const envAuthScheme = parseEnvAuthScheme(options.env.OPENSTEER_AUTH_SCHEME);
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
if (envAccessToken) {
|
|
610
|
-
return {
|
|
611
|
-
kind: "access-token",
|
|
612
|
-
source: "env",
|
|
613
|
-
token: envAccessToken,
|
|
614
|
-
authScheme: "bearer"
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
if (envApiKey) {
|
|
618
|
-
if (envAuthScheme === "bearer") {
|
|
619
|
-
return {
|
|
620
|
-
kind: "access-token",
|
|
621
|
-
source: "env",
|
|
622
|
-
token: envApiKey,
|
|
623
|
-
authScheme: "bearer",
|
|
624
|
-
compatibilityBearerApiKey: true
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
return {
|
|
628
|
-
kind: "api-key",
|
|
629
|
-
source: "env",
|
|
630
|
-
token: envApiKey,
|
|
631
|
-
authScheme: envAuthScheme ?? "api-key"
|
|
632
|
-
};
|
|
655
|
+
const envCredential = selectCloudCredential({
|
|
656
|
+
apiKey: options.env.OPENSTEER_API_KEY,
|
|
657
|
+
accessToken: options.env.OPENSTEER_ACCESS_TOKEN,
|
|
658
|
+
authScheme: envAuthScheme
|
|
659
|
+
});
|
|
660
|
+
if (envCredential) {
|
|
661
|
+
return toResolvedCloudCredential("env", envCredential);
|
|
633
662
|
}
|
|
634
663
|
return null;
|
|
635
664
|
}
|
|
@@ -659,6 +688,23 @@ function normalizeToken(value) {
|
|
|
659
688
|
const normalized = value.trim();
|
|
660
689
|
return normalized.length ? normalized : void 0;
|
|
661
690
|
}
|
|
691
|
+
function toResolvedCloudCredential(source, credential) {
|
|
692
|
+
if (credential.compatibilityBearerApiKey) {
|
|
693
|
+
return {
|
|
694
|
+
kind: credential.kind,
|
|
695
|
+
source,
|
|
696
|
+
token: credential.token,
|
|
697
|
+
authScheme: credential.authScheme,
|
|
698
|
+
compatibilityBearerApiKey: true
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
return {
|
|
702
|
+
kind: credential.kind,
|
|
703
|
+
source,
|
|
704
|
+
token: credential.token,
|
|
705
|
+
authScheme: credential.authScheme
|
|
706
|
+
};
|
|
707
|
+
}
|
|
662
708
|
|
|
663
709
|
// src/auth/machine-credential-store.ts
|
|
664
710
|
var import_node_crypto = require("crypto");
|
|
@@ -804,13 +850,10 @@ function createKeychainStore() {
|
|
|
804
850
|
}
|
|
805
851
|
|
|
806
852
|
// src/auth/machine-credential-store.ts
|
|
807
|
-
var METADATA_VERSION =
|
|
808
|
-
var ACTIVE_TARGET_VERSION =
|
|
853
|
+
var METADATA_VERSION = 2;
|
|
854
|
+
var ACTIVE_TARGET_VERSION = 2;
|
|
809
855
|
var KEYCHAIN_SERVICE = "com.opensteer.cli.cloud";
|
|
810
856
|
var KEYCHAIN_ACCOUNT_PREFIX = "machine:";
|
|
811
|
-
var LEGACY_KEYCHAIN_ACCOUNT = "machine";
|
|
812
|
-
var LEGACY_METADATA_FILE_NAME = "cli-login.json";
|
|
813
|
-
var LEGACY_FALLBACK_SECRET_FILE_NAME = "cli-login.secret.json";
|
|
814
857
|
var ACTIVE_TARGET_FILE_NAME = "cli-target.json";
|
|
815
858
|
var MachineCredentialStore = class {
|
|
816
859
|
authDir;
|
|
@@ -825,8 +868,11 @@ var MachineCredentialStore = class {
|
|
|
825
868
|
this.warn = options.warn ?? (() => void 0);
|
|
826
869
|
}
|
|
827
870
|
readCloudCredential(target) {
|
|
828
|
-
const
|
|
829
|
-
return this.readCredentialSlot(
|
|
871
|
+
const normalizedTarget = normalizeCloudCredentialTarget(target);
|
|
872
|
+
return this.readCredentialSlot(
|
|
873
|
+
resolveCredentialSlot(this.authDir, normalizedTarget),
|
|
874
|
+
normalizedTarget
|
|
875
|
+
);
|
|
830
876
|
}
|
|
831
877
|
writeCloudCredential(args) {
|
|
832
878
|
const accessToken = args.accessToken.trim();
|
|
@@ -834,12 +880,8 @@ var MachineCredentialStore = class {
|
|
|
834
880
|
if (!accessToken || !refreshToken2) {
|
|
835
881
|
throw new Error("Cannot persist empty machine credential secrets.");
|
|
836
882
|
}
|
|
837
|
-
const baseUrl = normalizeCredentialUrl(args.baseUrl
|
|
838
|
-
const
|
|
839
|
-
const slot = resolveCredentialSlot(this.authDir, {
|
|
840
|
-
baseUrl,
|
|
841
|
-
siteUrl
|
|
842
|
-
});
|
|
883
|
+
const baseUrl = normalizeCredentialUrl(args.baseUrl);
|
|
884
|
+
const slot = resolveCredentialSlot(this.authDir, { baseUrl });
|
|
843
885
|
ensureDirectory(this.authDir);
|
|
844
886
|
const secretPayload = {
|
|
845
887
|
accessToken,
|
|
@@ -866,7 +908,6 @@ var MachineCredentialStore = class {
|
|
|
866
908
|
version: METADATA_VERSION,
|
|
867
909
|
secretBackend,
|
|
868
910
|
baseUrl,
|
|
869
|
-
siteUrl,
|
|
870
911
|
scope: args.scope,
|
|
871
912
|
obtainedAt: args.obtainedAt,
|
|
872
913
|
expiresAt: args.expiresAt,
|
|
@@ -878,23 +919,18 @@ var MachineCredentialStore = class {
|
|
|
878
919
|
return readActiveCloudTargetMetadata(resolveActiveTargetPath(this.authDir));
|
|
879
920
|
}
|
|
880
921
|
writeActiveCloudTarget(target) {
|
|
881
|
-
const baseUrl = normalizeCredentialUrl(target.baseUrl
|
|
882
|
-
const siteUrl = normalizeCredentialUrl(target.siteUrl, "siteUrl");
|
|
922
|
+
const baseUrl = normalizeCredentialUrl(target.baseUrl);
|
|
883
923
|
ensureDirectory(this.authDir);
|
|
884
924
|
writeJsonFile(resolveActiveTargetPath(this.authDir), {
|
|
885
925
|
version: ACTIVE_TARGET_VERSION,
|
|
886
926
|
baseUrl,
|
|
887
|
-
siteUrl,
|
|
888
927
|
updatedAt: Date.now()
|
|
889
928
|
});
|
|
890
929
|
}
|
|
891
930
|
clearCloudCredential(target) {
|
|
892
|
-
this.clearCredentialSlot(
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
if (legacyMetadata && matchesCredentialTarget(legacyMetadata, target)) {
|
|
896
|
-
this.clearCredentialSlot(legacySlot);
|
|
897
|
-
}
|
|
931
|
+
this.clearCredentialSlot(
|
|
932
|
+
resolveCredentialSlot(this.authDir, normalizeCloudCredentialTarget(target))
|
|
933
|
+
);
|
|
898
934
|
}
|
|
899
935
|
readCredentialSlot(slot, target) {
|
|
900
936
|
const metadata = readMetadata(slot.metadataPath);
|
|
@@ -910,7 +946,6 @@ var MachineCredentialStore = class {
|
|
|
910
946
|
}
|
|
911
947
|
return {
|
|
912
948
|
baseUrl: metadata.baseUrl,
|
|
913
|
-
siteUrl: metadata.siteUrl,
|
|
914
949
|
scope: metadata.scope,
|
|
915
950
|
accessToken: secret.accessToken,
|
|
916
951
|
refreshToken: secret.refreshToken,
|
|
@@ -918,16 +953,6 @@ var MachineCredentialStore = class {
|
|
|
918
953
|
expiresAt: metadata.expiresAt
|
|
919
954
|
};
|
|
920
955
|
}
|
|
921
|
-
readAndMigrateLegacyCredential(target) {
|
|
922
|
-
const legacySlot = resolveLegacyCredentialSlot(this.authDir);
|
|
923
|
-
const legacyCredential = this.readCredentialSlot(legacySlot, target);
|
|
924
|
-
if (!legacyCredential) {
|
|
925
|
-
return null;
|
|
926
|
-
}
|
|
927
|
-
this.writeCloudCredential(legacyCredential);
|
|
928
|
-
this.clearCredentialSlot(legacySlot);
|
|
929
|
-
return legacyCredential;
|
|
930
|
-
}
|
|
931
956
|
readSecret(slot, backend) {
|
|
932
957
|
if (backend === "keychain" && this.keychain) {
|
|
933
958
|
try {
|
|
@@ -968,9 +993,8 @@ function createMachineCredentialStore(options = {}) {
|
|
|
968
993
|
return new MachineCredentialStore(options);
|
|
969
994
|
}
|
|
970
995
|
function resolveCredentialSlot(authDir, target) {
|
|
971
|
-
const normalizedBaseUrl = normalizeCredentialUrl(target.baseUrl
|
|
972
|
-
const
|
|
973
|
-
const storageKey = (0, import_node_crypto.createHash)("sha256").update(`${normalizedBaseUrl}\0${normalizedSiteUrl}`).digest("hex").slice(0, 24);
|
|
996
|
+
const normalizedBaseUrl = normalizeCredentialUrl(target.baseUrl);
|
|
997
|
+
const storageKey = (0, import_node_crypto.createHash)("sha256").update(normalizedBaseUrl).digest("hex").slice(0, 24);
|
|
974
998
|
return {
|
|
975
999
|
keychainAccount: `${KEYCHAIN_ACCOUNT_PREFIX}${storageKey}`,
|
|
976
1000
|
metadataPath: import_node_path.default.join(authDir, `cli-login.${storageKey}.json`),
|
|
@@ -980,26 +1004,24 @@ function resolveCredentialSlot(authDir, target) {
|
|
|
980
1004
|
)
|
|
981
1005
|
};
|
|
982
1006
|
}
|
|
983
|
-
function resolveLegacyCredentialSlot(authDir) {
|
|
984
|
-
return {
|
|
985
|
-
keychainAccount: LEGACY_KEYCHAIN_ACCOUNT,
|
|
986
|
-
metadataPath: import_node_path.default.join(authDir, LEGACY_METADATA_FILE_NAME),
|
|
987
|
-
fallbackSecretPath: import_node_path.default.join(authDir, LEGACY_FALLBACK_SECRET_FILE_NAME)
|
|
988
|
-
};
|
|
989
|
-
}
|
|
990
1007
|
function resolveActiveTargetPath(authDir) {
|
|
991
1008
|
return import_node_path.default.join(authDir, ACTIVE_TARGET_FILE_NAME);
|
|
992
1009
|
}
|
|
993
1010
|
function matchesCredentialTarget(value, target) {
|
|
994
|
-
return normalizeCredentialUrl(value.baseUrl
|
|
1011
|
+
return normalizeCredentialUrl(value.baseUrl) === normalizeCredentialUrl(target.baseUrl);
|
|
995
1012
|
}
|
|
996
|
-
function normalizeCredentialUrl(value
|
|
1013
|
+
function normalizeCredentialUrl(value) {
|
|
997
1014
|
const normalized = stripTrailingSlashes(value.trim());
|
|
998
1015
|
if (!normalized) {
|
|
999
|
-
throw new Error(
|
|
1016
|
+
throw new Error("Cannot persist machine credential without baseUrl.");
|
|
1000
1017
|
}
|
|
1001
1018
|
return normalized;
|
|
1002
1019
|
}
|
|
1020
|
+
function normalizeCloudCredentialTarget(target) {
|
|
1021
|
+
return {
|
|
1022
|
+
baseUrl: normalizeCredentialUrl(target.baseUrl)
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1003
1025
|
function resolveConfigDir(appName, env) {
|
|
1004
1026
|
if (process.platform === "win32") {
|
|
1005
1027
|
const appData = env.APPDATA?.trim() || import_node_path.default.join(import_node_os.default.homedir(), "AppData", "Roaming");
|
|
@@ -1038,7 +1060,6 @@ function readMetadata(filePath) {
|
|
|
1038
1060
|
return null;
|
|
1039
1061
|
}
|
|
1040
1062
|
if (typeof parsed.baseUrl !== "string" || !parsed.baseUrl.trim()) return null;
|
|
1041
|
-
if (typeof parsed.siteUrl !== "string" || !parsed.siteUrl.trim()) return null;
|
|
1042
1063
|
if (!Array.isArray(parsed.scope)) return null;
|
|
1043
1064
|
if (typeof parsed.obtainedAt !== "number") return null;
|
|
1044
1065
|
if (typeof parsed.expiresAt !== "number") return null;
|
|
@@ -1047,7 +1068,6 @@ function readMetadata(filePath) {
|
|
|
1047
1068
|
version: parsed.version,
|
|
1048
1069
|
secretBackend: parsed.secretBackend,
|
|
1049
1070
|
baseUrl: parsed.baseUrl,
|
|
1050
|
-
siteUrl: parsed.siteUrl,
|
|
1051
1071
|
scope: parsed.scope.filter(
|
|
1052
1072
|
(value) => typeof value === "string"
|
|
1053
1073
|
),
|
|
@@ -1072,12 +1092,8 @@ function readActiveCloudTargetMetadata(filePath) {
|
|
|
1072
1092
|
if (typeof parsed.baseUrl !== "string" || !parsed.baseUrl.trim()) {
|
|
1073
1093
|
return null;
|
|
1074
1094
|
}
|
|
1075
|
-
if (typeof parsed.siteUrl !== "string" || !parsed.siteUrl.trim()) {
|
|
1076
|
-
return null;
|
|
1077
|
-
}
|
|
1078
1095
|
return {
|
|
1079
|
-
baseUrl: parsed.baseUrl
|
|
1080
|
-
siteUrl: parsed.siteUrl
|
|
1096
|
+
baseUrl: parsed.baseUrl
|
|
1081
1097
|
};
|
|
1082
1098
|
} catch {
|
|
1083
1099
|
return null;
|
|
@@ -1102,14 +1118,13 @@ function readSecretFile(filePath) {
|
|
|
1102
1118
|
return null;
|
|
1103
1119
|
}
|
|
1104
1120
|
try {
|
|
1105
|
-
|
|
1106
|
-
return parseSecretPayload(raw);
|
|
1121
|
+
return parseSecretPayload(import_node_fs.default.readFileSync(filePath, "utf8"));
|
|
1107
1122
|
} catch {
|
|
1108
1123
|
return null;
|
|
1109
1124
|
}
|
|
1110
1125
|
}
|
|
1111
|
-
function writeJsonFile(filePath,
|
|
1112
|
-
import_node_fs.default.writeFileSync(filePath, JSON.stringify(
|
|
1126
|
+
function writeJsonFile(filePath, value, options = {}) {
|
|
1127
|
+
import_node_fs.default.writeFileSync(filePath, JSON.stringify(value, null, 2), {
|
|
1113
1128
|
encoding: "utf8",
|
|
1114
1129
|
mode: options.mode ?? 384
|
|
1115
1130
|
});
|
|
@@ -1140,11 +1155,12 @@ Commands:
|
|
|
1140
1155
|
|
|
1141
1156
|
Options:
|
|
1142
1157
|
--base-url <url> Cloud API base URL (defaults to env or the last selected host)
|
|
1143
|
-
--site-url <url> Cloud site URL for browser/device auth (defaults to env or the last selected host)
|
|
1144
1158
|
--json JSON output (login prompts go to stderr)
|
|
1145
1159
|
--no-browser Do not auto-open your default browser during login
|
|
1146
1160
|
-h, --help Show this help
|
|
1147
1161
|
`;
|
|
1162
|
+
var DEFAULT_AUTH_SITE_URL = "https://opensteer.com";
|
|
1163
|
+
var INTERNAL_AUTH_SITE_URL_ENV = "OPENSTEER_INTERNAL_AUTH_SITE_URL";
|
|
1148
1164
|
function createDefaultDeps() {
|
|
1149
1165
|
const env = process.env;
|
|
1150
1166
|
return {
|
|
@@ -1196,13 +1212,6 @@ function parseAuthCommonArgs(rawArgs) {
|
|
|
1196
1212
|
i = value.nextIndex;
|
|
1197
1213
|
continue;
|
|
1198
1214
|
}
|
|
1199
|
-
if (arg === "--site-url") {
|
|
1200
|
-
const value = readFlagValue(rawArgs, i, "--site-url");
|
|
1201
|
-
if (!value.ok) return { args, error: value.error };
|
|
1202
|
-
args.siteUrl = value.value;
|
|
1203
|
-
i = value.nextIndex;
|
|
1204
|
-
continue;
|
|
1205
|
-
}
|
|
1206
1215
|
return {
|
|
1207
1216
|
args,
|
|
1208
1217
|
error: `Unsupported option "${arg}".`
|
|
@@ -1272,16 +1281,19 @@ function resolveBaseUrl(provided, env) {
|
|
|
1272
1281
|
assertSecureUrl(baseUrl, "--base-url");
|
|
1273
1282
|
return baseUrl;
|
|
1274
1283
|
}
|
|
1275
|
-
function
|
|
1276
|
-
const
|
|
1277
|
-
(
|
|
1284
|
+
function resolveAuthSiteUrl(env) {
|
|
1285
|
+
const authSiteUrl = normalizeCloudBaseUrl(
|
|
1286
|
+
(env[INTERNAL_AUTH_SITE_URL_ENV] || DEFAULT_AUTH_SITE_URL).trim()
|
|
1278
1287
|
);
|
|
1279
|
-
assertSecureUrl(
|
|
1280
|
-
|
|
1288
|
+
assertSecureUrl(
|
|
1289
|
+
authSiteUrl,
|
|
1290
|
+
`environment variable ${INTERNAL_AUTH_SITE_URL_ENV}`
|
|
1291
|
+
);
|
|
1292
|
+
return authSiteUrl;
|
|
1281
1293
|
}
|
|
1282
|
-
function hasExplicitCloudTargetSelection(providedBaseUrl,
|
|
1294
|
+
function hasExplicitCloudTargetSelection(providedBaseUrl, env) {
|
|
1283
1295
|
return Boolean(
|
|
1284
|
-
providedBaseUrl?.trim() ||
|
|
1296
|
+
providedBaseUrl?.trim() || env.OPENSTEER_BASE_URL?.trim()
|
|
1285
1297
|
);
|
|
1286
1298
|
}
|
|
1287
1299
|
function readRememberedCloudTarget(store) {
|
|
@@ -1291,57 +1303,21 @@ function readRememberedCloudTarget(store) {
|
|
|
1291
1303
|
}
|
|
1292
1304
|
try {
|
|
1293
1305
|
const baseUrl = normalizeCloudBaseUrl(activeTarget.baseUrl);
|
|
1294
|
-
const siteUrl = normalizeCloudBaseUrl(activeTarget.siteUrl);
|
|
1295
1306
|
assertSecureUrl(baseUrl, "--base-url");
|
|
1296
|
-
|
|
1297
|
-
return {
|
|
1298
|
-
baseUrl,
|
|
1299
|
-
siteUrl
|
|
1300
|
-
};
|
|
1307
|
+
return { baseUrl };
|
|
1301
1308
|
} catch {
|
|
1302
1309
|
return null;
|
|
1303
1310
|
}
|
|
1304
1311
|
}
|
|
1305
|
-
function resolveCloudTarget(args, env, store) {
|
|
1306
|
-
if (!hasExplicitCloudTargetSelection(args.baseUrl,
|
|
1312
|
+
function resolveCloudTarget(args, env, store, options = {}) {
|
|
1313
|
+
if (options.allowRememberedTarget !== false && !hasExplicitCloudTargetSelection(args.baseUrl, env)) {
|
|
1307
1314
|
const rememberedTarget = readRememberedCloudTarget(store);
|
|
1308
1315
|
if (rememberedTarget) {
|
|
1309
1316
|
return rememberedTarget;
|
|
1310
1317
|
}
|
|
1311
1318
|
}
|
|
1312
1319
|
const baseUrl = resolveBaseUrl(args.baseUrl, env);
|
|
1313
|
-
|
|
1314
|
-
return {
|
|
1315
|
-
baseUrl,
|
|
1316
|
-
siteUrl
|
|
1317
|
-
};
|
|
1318
|
-
}
|
|
1319
|
-
function deriveSiteUrlFromBaseUrl(baseUrl) {
|
|
1320
|
-
let parsed;
|
|
1321
|
-
try {
|
|
1322
|
-
parsed = new URL(baseUrl);
|
|
1323
|
-
} catch {
|
|
1324
|
-
return "https://opensteer.com";
|
|
1325
|
-
}
|
|
1326
|
-
const hostname = parsed.hostname.toLowerCase();
|
|
1327
|
-
if (hostname.startsWith("api.")) {
|
|
1328
|
-
parsed.hostname = hostname.slice("api.".length);
|
|
1329
|
-
parsed.pathname = "";
|
|
1330
|
-
parsed.search = "";
|
|
1331
|
-
parsed.hash = "";
|
|
1332
|
-
return normalizeCloudBaseUrl(parsed.toString());
|
|
1333
|
-
}
|
|
1334
|
-
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") {
|
|
1335
|
-
parsed.port = "3001";
|
|
1336
|
-
parsed.pathname = "";
|
|
1337
|
-
parsed.search = "";
|
|
1338
|
-
parsed.hash = "";
|
|
1339
|
-
return normalizeCloudBaseUrl(parsed.toString());
|
|
1340
|
-
}
|
|
1341
|
-
parsed.pathname = "";
|
|
1342
|
-
parsed.search = "";
|
|
1343
|
-
parsed.hash = "";
|
|
1344
|
-
return normalizeCloudBaseUrl(parsed.toString());
|
|
1320
|
+
return { baseUrl };
|
|
1345
1321
|
}
|
|
1346
1322
|
function assertSecureUrl(value, flag) {
|
|
1347
1323
|
let parsed;
|
|
@@ -1416,10 +1392,10 @@ function parseCliOauthError(error) {
|
|
|
1416
1392
|
interval: typeof root.interval === "number" ? root.interval : void 0
|
|
1417
1393
|
};
|
|
1418
1394
|
}
|
|
1419
|
-
async function startDeviceAuthorization(
|
|
1395
|
+
async function startDeviceAuthorization(authSiteUrl, fetchFn) {
|
|
1420
1396
|
const response = await postJson(
|
|
1421
1397
|
fetchFn,
|
|
1422
|
-
`${
|
|
1398
|
+
`${authSiteUrl}/api/cli-auth/device/start`,
|
|
1423
1399
|
{
|
|
1424
1400
|
scope: ["cloud:browser"]
|
|
1425
1401
|
}
|
|
@@ -1429,24 +1405,24 @@ async function startDeviceAuthorization(siteUrl, fetchFn) {
|
|
|
1429
1405
|
}
|
|
1430
1406
|
return response;
|
|
1431
1407
|
}
|
|
1432
|
-
async function pollDeviceToken(
|
|
1408
|
+
async function pollDeviceToken(authSiteUrl, deviceCode, fetchFn) {
|
|
1433
1409
|
return await postJson(
|
|
1434
1410
|
fetchFn,
|
|
1435
|
-
`${
|
|
1411
|
+
`${authSiteUrl}/api/cli-auth/device/token`,
|
|
1436
1412
|
{
|
|
1437
1413
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
1438
1414
|
device_code: deviceCode
|
|
1439
1415
|
}
|
|
1440
1416
|
);
|
|
1441
1417
|
}
|
|
1442
|
-
async function refreshToken(
|
|
1443
|
-
return await postJson(fetchFn, `${
|
|
1418
|
+
async function refreshToken(authSiteUrl, refreshTokenValue, fetchFn) {
|
|
1419
|
+
return await postJson(fetchFn, `${authSiteUrl}/api/cli-auth/token`, {
|
|
1444
1420
|
grant_type: "refresh_token",
|
|
1445
1421
|
refresh_token: refreshTokenValue
|
|
1446
1422
|
});
|
|
1447
1423
|
}
|
|
1448
|
-
async function revokeToken(
|
|
1449
|
-
await postJson(fetchFn, `${
|
|
1424
|
+
async function revokeToken(authSiteUrl, refreshTokenValue, fetchFn) {
|
|
1425
|
+
await postJson(fetchFn, `${authSiteUrl}/api/cli-auth/revoke`, {
|
|
1450
1426
|
token: refreshTokenValue
|
|
1451
1427
|
});
|
|
1452
1428
|
}
|
|
@@ -1463,7 +1439,7 @@ async function openDefaultBrowser(url) {
|
|
|
1463
1439
|
}
|
|
1464
1440
|
}
|
|
1465
1441
|
async function runDeviceLoginFlow(args) {
|
|
1466
|
-
const start = await startDeviceAuthorization(args.
|
|
1442
|
+
const start = await startDeviceAuthorization(args.authSiteUrl, args.fetchFn);
|
|
1467
1443
|
if (args.openBrowser) {
|
|
1468
1444
|
args.writeProgress(
|
|
1469
1445
|
"Opening your default browser for Opensteer CLI authentication.\n"
|
|
@@ -1508,7 +1484,7 @@ ${start.verification_uri_complete}
|
|
|
1508
1484
|
await args.sleep(pollIntervalMs);
|
|
1509
1485
|
try {
|
|
1510
1486
|
const tokenPayload = await pollDeviceToken(
|
|
1511
|
-
args.
|
|
1487
|
+
args.authSiteUrl,
|
|
1512
1488
|
start.device_code,
|
|
1513
1489
|
args.fetchFn
|
|
1514
1490
|
);
|
|
@@ -1556,7 +1532,7 @@ ${start.verification_uri_complete}
|
|
|
1556
1532
|
}
|
|
1557
1533
|
async function refreshSavedCredential(saved, deps) {
|
|
1558
1534
|
const tokenPayload = await refreshToken(
|
|
1559
|
-
|
|
1535
|
+
resolveAuthSiteUrl(deps.env),
|
|
1560
1536
|
saved.refreshToken,
|
|
1561
1537
|
deps.fetchFn
|
|
1562
1538
|
);
|
|
@@ -1569,7 +1545,6 @@ async function refreshSavedCredential(saved, deps) {
|
|
|
1569
1545
|
};
|
|
1570
1546
|
deps.store.writeCloudCredential({
|
|
1571
1547
|
baseUrl: saved.baseUrl,
|
|
1572
|
-
siteUrl: saved.siteUrl,
|
|
1573
1548
|
scope: updated.scope,
|
|
1574
1549
|
accessToken: updated.accessToken,
|
|
1575
1550
|
refreshToken: updated.refreshToken,
|
|
@@ -1598,8 +1573,7 @@ async function ensureSavedCredentialIsFresh(saved, deps) {
|
|
|
1598
1573
|
const oauth = parseCliOauthError(error.body);
|
|
1599
1574
|
if (oauth?.error === "invalid_grant" || oauth?.error === "expired_token") {
|
|
1600
1575
|
deps.store.clearCloudCredential({
|
|
1601
|
-
baseUrl: saved.baseUrl
|
|
1602
|
-
siteUrl: saved.siteUrl
|
|
1576
|
+
baseUrl: saved.baseUrl
|
|
1603
1577
|
});
|
|
1604
1578
|
return null;
|
|
1605
1579
|
}
|
|
@@ -1699,7 +1673,7 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1699
1673
|
`);
|
|
1700
1674
|
}
|
|
1701
1675
|
});
|
|
1702
|
-
const { baseUrl
|
|
1676
|
+
const { baseUrl } = resolveCloudTarget(options, env, store);
|
|
1703
1677
|
const initialCredential = resolveCloudCredential({
|
|
1704
1678
|
env,
|
|
1705
1679
|
apiKeyFlag: options.apiKeyFlag,
|
|
@@ -1707,11 +1681,9 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1707
1681
|
});
|
|
1708
1682
|
let credential = initialCredential;
|
|
1709
1683
|
if (!credential) {
|
|
1710
|
-
const saved = store.readCloudCredential({
|
|
1711
|
-
baseUrl,
|
|
1712
|
-
siteUrl
|
|
1713
|
-
});
|
|
1684
|
+
const saved = store.readCloudCredential({ baseUrl });
|
|
1714
1685
|
const freshSaved = saved ? await ensureSavedCredentialIsFresh(saved, {
|
|
1686
|
+
env,
|
|
1715
1687
|
fetchFn,
|
|
1716
1688
|
store,
|
|
1717
1689
|
now,
|
|
@@ -1729,7 +1701,7 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1729
1701
|
if (!credential) {
|
|
1730
1702
|
if (options.autoLoginIfNeeded && (options.interactive ?? false)) {
|
|
1731
1703
|
const loggedIn = await runDeviceLoginFlow({
|
|
1732
|
-
|
|
1704
|
+
authSiteUrl: resolveAuthSiteUrl(env),
|
|
1733
1705
|
fetchFn,
|
|
1734
1706
|
writeProgress,
|
|
1735
1707
|
openExternalUrl,
|
|
@@ -1739,7 +1711,6 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1739
1711
|
});
|
|
1740
1712
|
store.writeCloudCredential({
|
|
1741
1713
|
baseUrl,
|
|
1742
|
-
siteUrl,
|
|
1743
1714
|
scope: loggedIn.scope,
|
|
1744
1715
|
accessToken: loggedIn.accessToken,
|
|
1745
1716
|
refreshToken: loggedIn.refreshToken,
|
|
@@ -1757,28 +1728,25 @@ async function ensureCloudCredentialsForCommand(options) {
|
|
|
1757
1728
|
throw new Error(toAuthMissingMessage(options.commandName));
|
|
1758
1729
|
}
|
|
1759
1730
|
}
|
|
1760
|
-
store.writeActiveCloudTarget({
|
|
1761
|
-
baseUrl,
|
|
1762
|
-
siteUrl
|
|
1763
|
-
});
|
|
1731
|
+
store.writeActiveCloudTarget({ baseUrl });
|
|
1764
1732
|
applyCloudCredentialToEnv(env, credential);
|
|
1765
1733
|
env.OPENSTEER_BASE_URL = baseUrl;
|
|
1766
|
-
env.OPENSTEER_CLOUD_SITE_URL = siteUrl;
|
|
1767
1734
|
return {
|
|
1768
1735
|
token: credential.token,
|
|
1769
1736
|
authScheme: credential.authScheme,
|
|
1770
1737
|
source: credential.source,
|
|
1771
1738
|
kind: credential.kind,
|
|
1772
|
-
baseUrl
|
|
1773
|
-
siteUrl
|
|
1739
|
+
baseUrl
|
|
1774
1740
|
};
|
|
1775
1741
|
}
|
|
1776
1742
|
async function runLogin(args, deps) {
|
|
1777
|
-
const { baseUrl
|
|
1743
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store, {
|
|
1744
|
+
allowRememberedTarget: false
|
|
1745
|
+
});
|
|
1778
1746
|
const writeProgress = args.json ? deps.writeStderr : deps.writeStdout;
|
|
1779
1747
|
const browserOpenMode = describeBrowserOpenMode(args, deps);
|
|
1780
1748
|
const login = await runDeviceLoginFlow({
|
|
1781
|
-
|
|
1749
|
+
authSiteUrl: resolveAuthSiteUrl(deps.env),
|
|
1782
1750
|
fetchFn: deps.fetchFn,
|
|
1783
1751
|
writeProgress,
|
|
1784
1752
|
openExternalUrl: deps.openExternalUrl,
|
|
@@ -1789,22 +1757,17 @@ async function runLogin(args, deps) {
|
|
|
1789
1757
|
});
|
|
1790
1758
|
deps.store.writeCloudCredential({
|
|
1791
1759
|
baseUrl,
|
|
1792
|
-
siteUrl,
|
|
1793
1760
|
scope: login.scope,
|
|
1794
1761
|
accessToken: login.accessToken,
|
|
1795
1762
|
refreshToken: login.refreshToken,
|
|
1796
1763
|
obtainedAt: deps.now(),
|
|
1797
1764
|
expiresAt: login.expiresAt
|
|
1798
1765
|
});
|
|
1799
|
-
deps.store.writeActiveCloudTarget({
|
|
1800
|
-
baseUrl,
|
|
1801
|
-
siteUrl
|
|
1802
|
-
});
|
|
1766
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1803
1767
|
if (args.json) {
|
|
1804
1768
|
writeJsonLine(deps, {
|
|
1805
1769
|
loggedIn: true,
|
|
1806
1770
|
baseUrl,
|
|
1807
|
-
siteUrl,
|
|
1808
1771
|
expiresAt: login.expiresAt,
|
|
1809
1772
|
scope: login.scope,
|
|
1810
1773
|
authSource: "device"
|
|
@@ -1812,33 +1775,20 @@ async function runLogin(args, deps) {
|
|
|
1812
1775
|
return 0;
|
|
1813
1776
|
}
|
|
1814
1777
|
writeHumanLine(deps, "Opensteer CLI login successful.");
|
|
1815
|
-
writeHumanLine(deps, ` Site URL: ${siteUrl}`);
|
|
1816
|
-
writeHumanLine(deps, ` API Base URL: ${baseUrl}`);
|
|
1817
|
-
writeHumanLine(deps, ` Expires At: ${new Date(login.expiresAt).toISOString()}`);
|
|
1818
1778
|
return 0;
|
|
1819
1779
|
}
|
|
1820
1780
|
async function runStatus(args, deps) {
|
|
1821
|
-
const { baseUrl
|
|
1822
|
-
deps.store.writeActiveCloudTarget({
|
|
1823
|
-
|
|
1824
|
-
siteUrl
|
|
1825
|
-
});
|
|
1826
|
-
const saved = deps.store.readCloudCredential({
|
|
1827
|
-
baseUrl,
|
|
1828
|
-
siteUrl
|
|
1829
|
-
});
|
|
1781
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store);
|
|
1782
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1783
|
+
const saved = deps.store.readCloudCredential({ baseUrl });
|
|
1830
1784
|
if (!saved) {
|
|
1831
1785
|
if (args.json) {
|
|
1832
1786
|
writeJsonLine(deps, {
|
|
1833
1787
|
loggedIn: false,
|
|
1834
|
-
baseUrl
|
|
1835
|
-
siteUrl
|
|
1788
|
+
baseUrl
|
|
1836
1789
|
});
|
|
1837
1790
|
} else {
|
|
1838
|
-
writeHumanLine(
|
|
1839
|
-
deps,
|
|
1840
|
-
`Opensteer CLI is not logged in for ${siteUrl}.`
|
|
1841
|
-
);
|
|
1791
|
+
writeHumanLine(deps, `Opensteer CLI is not logged in for ${baseUrl}.`);
|
|
1842
1792
|
}
|
|
1843
1793
|
return 0;
|
|
1844
1794
|
}
|
|
@@ -1849,7 +1799,6 @@ async function runStatus(args, deps) {
|
|
|
1849
1799
|
loggedIn: true,
|
|
1850
1800
|
expired,
|
|
1851
1801
|
baseUrl: saved.baseUrl,
|
|
1852
|
-
siteUrl: saved.siteUrl,
|
|
1853
1802
|
expiresAt: saved.expiresAt,
|
|
1854
1803
|
scope: saved.scope
|
|
1855
1804
|
});
|
|
@@ -1859,43 +1808,33 @@ async function runStatus(args, deps) {
|
|
|
1859
1808
|
deps,
|
|
1860
1809
|
expired ? "Opensteer CLI has a saved login, but the access token is expired." : "Opensteer CLI is logged in."
|
|
1861
1810
|
);
|
|
1862
|
-
writeHumanLine(deps, ` Site URL: ${saved.siteUrl}`);
|
|
1863
1811
|
writeHumanLine(deps, ` API Base URL: ${saved.baseUrl}`);
|
|
1864
1812
|
writeHumanLine(deps, ` Expires At: ${new Date(saved.expiresAt).toISOString()}`);
|
|
1865
1813
|
return 0;
|
|
1866
1814
|
}
|
|
1867
1815
|
async function runLogout(args, deps) {
|
|
1868
|
-
const { baseUrl
|
|
1869
|
-
deps.store.writeActiveCloudTarget({
|
|
1870
|
-
|
|
1871
|
-
siteUrl
|
|
1872
|
-
});
|
|
1873
|
-
const saved = deps.store.readCloudCredential({
|
|
1874
|
-
baseUrl,
|
|
1875
|
-
siteUrl
|
|
1876
|
-
});
|
|
1816
|
+
const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store);
|
|
1817
|
+
deps.store.writeActiveCloudTarget({ baseUrl });
|
|
1818
|
+
const saved = deps.store.readCloudCredential({ baseUrl });
|
|
1877
1819
|
if (saved) {
|
|
1878
1820
|
try {
|
|
1879
|
-
await revokeToken(
|
|
1821
|
+
await revokeToken(
|
|
1822
|
+
resolveAuthSiteUrl(deps.env),
|
|
1823
|
+
saved.refreshToken,
|
|
1824
|
+
deps.fetchFn
|
|
1825
|
+
);
|
|
1880
1826
|
} catch {
|
|
1881
1827
|
}
|
|
1882
1828
|
}
|
|
1883
|
-
deps.store.clearCloudCredential({
|
|
1884
|
-
baseUrl,
|
|
1885
|
-
siteUrl
|
|
1886
|
-
});
|
|
1829
|
+
deps.store.clearCloudCredential({ baseUrl });
|
|
1887
1830
|
if (args.json) {
|
|
1888
1831
|
writeJsonLine(deps, {
|
|
1889
1832
|
loggedOut: true,
|
|
1890
|
-
baseUrl
|
|
1891
|
-
siteUrl
|
|
1833
|
+
baseUrl
|
|
1892
1834
|
});
|
|
1893
1835
|
return 0;
|
|
1894
1836
|
}
|
|
1895
|
-
writeHumanLine(
|
|
1896
|
-
deps,
|
|
1897
|
-
`Opensteer CLI login removed for ${siteUrl}.`
|
|
1898
|
-
);
|
|
1837
|
+
writeHumanLine(deps, `Opensteer CLI login removed for ${baseUrl}.`);
|
|
1899
1838
|
return 0;
|
|
1900
1839
|
}
|
|
1901
1840
|
async function runOpensteerAuthCli(rawArgs, overrideDeps = {}) {
|