@microsoft/vscode-azext-azureauth 5.1.1 → 6.0.0-alpha.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/CHANGELOG.md +8 -0
- package/README.md +9 -79
- package/dist/cjs/src/contracts/AzureAccount.js +7 -0
- package/dist/cjs/src/contracts/AzureSubscriptionProviderRequestOptions.js +48 -0
- package/dist/cjs/src/index.js +13 -10
- package/dist/cjs/src/providers/AzureDevOpsSubscriptionProvider.js +178 -0
- package/dist/cjs/src/providers/AzureSubscriptionProviderBase.js +393 -0
- package/dist/cjs/src/providers/VSCodeAzureSubscriptionProvider.js +269 -0
- package/dist/cjs/src/utils/Limiter.js +41 -0
- package/dist/cjs/src/{NotSignedInError.js → utils/NotSignedInError.js} +3 -2
- package/dist/cjs/src/utils/configuredAzureEnv.js +14 -16
- package/dist/cjs/src/utils/dedupeSubscriptions.js +27 -0
- package/dist/cjs/src/utils/getMetricsForTelemetry.js +47 -0
- package/dist/cjs/src/{getSessionFromVSCode.js → utils/getSessionFromVSCode.js} +5 -2
- package/dist/cjs/src/utils/getSignalForToken.js +29 -0
- package/dist/cjs/src/utils/map/CaselessMap.js +71 -0
- package/dist/cjs/src/utils/map/TwoKeyCaselessMap.js +194 -0
- package/dist/cjs/src/utils/screen.js +62 -0
- package/dist/cjs/src/{signInToTenant.js → utils/signInToTenant.js} +15 -13
- package/dist/cjs/src/utils/tryGetTokenExpiration.js +25 -0
- package/dist/esm/src/contracts/AzureAccount.d.ts +5 -0
- package/dist/esm/src/contracts/AzureAccount.js +6 -0
- package/dist/esm/src/{AzureAuthentication.d.ts → contracts/AzureAuthentication.d.ts} +1 -1
- package/dist/esm/src/{AzureSubscription.d.ts → contracts/AzureSubscription.d.ts} +4 -4
- package/dist/esm/src/contracts/AzureSubscriptionProvider.d.ts +112 -0
- package/dist/esm/src/contracts/AzureSubscriptionProviderRequestOptions.d.ts +103 -0
- package/dist/esm/src/contracts/AzureSubscriptionProviderRequestOptions.js +44 -0
- package/dist/esm/src/contracts/AzureTenant.d.ts +15 -0
- package/dist/esm/src/index.d.ts +13 -10
- package/dist/esm/src/index.js +13 -10
- package/dist/esm/src/providers/AzureDevOpsSubscriptionProvider.d.ts +68 -0
- package/dist/esm/src/providers/AzureDevOpsSubscriptionProvider.js +140 -0
- package/dist/esm/src/providers/AzureSubscriptionProviderBase.d.ts +74 -0
- package/dist/esm/src/providers/AzureSubscriptionProviderBase.js +356 -0
- package/dist/esm/src/providers/VSCodeAzureSubscriptionProvider.d.ts +70 -0
- package/dist/esm/src/providers/VSCodeAzureSubscriptionProvider.js +232 -0
- package/dist/esm/src/utils/Limiter.d.ts +9 -0
- package/dist/esm/src/utils/Limiter.js +37 -0
- package/dist/esm/src/{NotSignedInError.d.ts → utils/NotSignedInError.d.ts} +2 -2
- package/dist/esm/src/{NotSignedInError.js → utils/NotSignedInError.js} +3 -2
- package/dist/esm/src/utils/configuredAzureEnv.d.ts +7 -4
- package/dist/esm/src/utils/configuredAzureEnv.js +14 -16
- package/dist/esm/src/utils/dedupeSubscriptions.d.ts +14 -0
- package/dist/esm/src/utils/dedupeSubscriptions.js +24 -0
- package/dist/esm/src/utils/getMetricsForTelemetry.d.ts +32 -0
- package/dist/esm/src/utils/getMetricsForTelemetry.js +44 -0
- package/dist/esm/src/{getSessionFromVSCode.js → utils/getSessionFromVSCode.js} +5 -2
- package/dist/esm/src/utils/getSignalForToken.d.ts +7 -0
- package/dist/esm/src/utils/getSignalForToken.js +26 -0
- package/dist/esm/src/utils/map/CaselessMap.d.ts +28 -0
- package/dist/esm/src/utils/map/CaselessMap.js +67 -0
- package/dist/esm/src/utils/map/TwoKeyCaselessMap.d.ts +49 -0
- package/dist/esm/src/utils/map/TwoKeyCaselessMap.js +190 -0
- package/dist/esm/src/utils/screen.d.ts +9 -0
- package/dist/esm/src/utils/screen.js +59 -0
- package/dist/esm/src/utils/signInToTenant.d.ts +7 -0
- package/dist/esm/src/{signInToTenant.js → utils/signInToTenant.js} +16 -14
- package/dist/esm/src/utils/tryGetTokenExpiration.d.ts +2 -0
- package/dist/esm/src/utils/tryGetTokenExpiration.js +22 -0
- package/package.json +33 -23
- package/AzureFederatedCredentialsGuide.md +0 -174
- package/dist/cjs/src/AzureDevOpsSubscriptionProvider.js +0 -215
- package/dist/cjs/src/VSCodeAzureSubscriptionProvider.js +0 -395
- package/dist/cjs/src/utils/getUnauthenticatedTenants.js +0 -23
- package/dist/cjs/src/utils/isGetSubscriptionsFilter.js +0 -27
- package/dist/esm/src/AzureDevOpsSubscriptionProvider.d.ts +0 -68
- package/dist/esm/src/AzureDevOpsSubscriptionProvider.js +0 -210
- package/dist/esm/src/AzureSubscriptionProvider.d.ts +0 -82
- package/dist/esm/src/AzureTenant.d.ts +0 -5
- package/dist/esm/src/VSCodeAzureSubscriptionProvider.d.ts +0 -116
- package/dist/esm/src/VSCodeAzureSubscriptionProvider.js +0 -358
- package/dist/esm/src/signInToTenant.d.ts +0 -6
- package/dist/esm/src/utils/getUnauthenticatedTenants.d.ts +0 -9
- package/dist/esm/src/utils/getUnauthenticatedTenants.js +0 -20
- package/dist/esm/src/utils/isGetSubscriptionsFilter.d.ts +0 -14
- package/dist/esm/src/utils/isGetSubscriptionsFilter.js +0 -23
- /package/dist/cjs/src/{AzureAuthentication.js → contracts/AzureAuthentication.js} +0 -0
- /package/dist/cjs/src/{AzureSubscription.js → contracts/AzureSubscription.js} +0 -0
- /package/dist/cjs/src/{AzureSubscriptionProvider.js → contracts/AzureSubscriptionProvider.js} +0 -0
- /package/dist/cjs/src/{AzureTenant.js → contracts/AzureTenant.js} +0 -0
- /package/dist/esm/src/{AzureAuthentication.js → contracts/AzureAuthentication.js} +0 -0
- /package/dist/esm/src/{AzureSubscription.js → contracts/AzureSubscription.js} +0 -0
- /package/dist/esm/src/{AzureSubscriptionProvider.js → contracts/AzureSubscriptionProvider.js} +0 -0
- /package/dist/esm/src/{AzureTenant.js → contracts/AzureTenant.js} +0 -0
- /package/dist/esm/src/{getSessionFromVSCode.d.ts → utils/getSessionFromVSCode.d.ts} +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.Limiter = void 0;
|
|
8
|
+
class Limiter {
|
|
9
|
+
runningPromises;
|
|
10
|
+
maxDegreeOfParalellism;
|
|
11
|
+
outstandingPromises;
|
|
12
|
+
constructor(maxDegreeOfParalellism) {
|
|
13
|
+
this.maxDegreeOfParalellism = maxDegreeOfParalellism;
|
|
14
|
+
this.outstandingPromises = [];
|
|
15
|
+
this.runningPromises = 0;
|
|
16
|
+
}
|
|
17
|
+
queue(factory) {
|
|
18
|
+
return new Promise((c, e) => {
|
|
19
|
+
this.outstandingPromises.push({ factory, c, e });
|
|
20
|
+
this.consume();
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
consume() {
|
|
24
|
+
while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) {
|
|
25
|
+
const iLimitedTask = this.outstandingPromises.shift();
|
|
26
|
+
this.runningPromises++;
|
|
27
|
+
const promise = iLimitedTask.factory();
|
|
28
|
+
promise.then(iLimitedTask.c, iLimitedTask.e);
|
|
29
|
+
promise.then(() => this.consumed(), () => this.consumed());
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
consumed() {
|
|
33
|
+
this.runningPromises--;
|
|
34
|
+
if (this.outstandingPromises.length > 0) {
|
|
35
|
+
this.consume();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.Limiter = Limiter;
|
|
40
|
+
/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
|
|
41
|
+
//# sourceMappingURL=Limiter.js.map
|
|
@@ -51,13 +51,14 @@ class NotSignedInError extends Error {
|
|
|
51
51
|
}
|
|
52
52
|
exports.NotSignedInError = NotSignedInError;
|
|
53
53
|
/**
|
|
54
|
-
* Tests if an object is a
|
|
54
|
+
* Tests if an object is a {@link NotSignedInError}. This should be used instead of `instanceof`.
|
|
55
55
|
*
|
|
56
56
|
* @param error The object to test
|
|
57
57
|
*
|
|
58
|
-
* @returns True if the object is a NotSignedInError, false otherwise
|
|
58
|
+
* @returns True if the object is a {@link NotSignedInError}, false otherwise
|
|
59
59
|
*/
|
|
60
60
|
function isNotSignedInError(error) {
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare, @typescript-eslint/no-unnecessary-condition
|
|
61
62
|
return !!error && typeof error === 'object' && error.isNotSignedInError === true;
|
|
62
63
|
}
|
|
63
64
|
//# sourceMappingURL=NotSignedInError.js.map
|
|
@@ -52,6 +52,16 @@ var CloudEnvironmentSettingValue;
|
|
|
52
52
|
CloudEnvironmentSettingValue["USGovernment"] = "USGovernment";
|
|
53
53
|
CloudEnvironmentSettingValue["Custom"] = "custom";
|
|
54
54
|
})(CloudEnvironmentSettingValue || (CloudEnvironmentSettingValue = {}));
|
|
55
|
+
class ExtendedEnvironment extends azureEnv.Environment {
|
|
56
|
+
isCustomCloud;
|
|
57
|
+
constructor(parameters, isCustomCloud) {
|
|
58
|
+
super(parameters);
|
|
59
|
+
this.isCustomCloud = isCustomCloud;
|
|
60
|
+
// The Environment constructor only copies required properties. Copy all remaining
|
|
61
|
+
// optional properties (e.g. storageEndpointSuffix, keyVaultDnsSuffix) from the source.
|
|
62
|
+
Object.assign(this, parameters);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
55
65
|
/**
|
|
56
66
|
* Gets the configured Azure environment.
|
|
57
67
|
*
|
|
@@ -61,31 +71,19 @@ function getConfiguredAzureEnv() {
|
|
|
61
71
|
const authProviderConfig = vscode.workspace.getConfiguration(CustomCloudConfigurationSection);
|
|
62
72
|
const environmentSettingValue = authProviderConfig.get(CloudEnvironmentSettingName);
|
|
63
73
|
if (environmentSettingValue === CloudEnvironmentSettingValue.ChinaCloud) {
|
|
64
|
-
return
|
|
65
|
-
...azureEnv.Environment.ChinaCloud,
|
|
66
|
-
isCustomCloud: false,
|
|
67
|
-
};
|
|
74
|
+
return new ExtendedEnvironment(azureEnv.Environment.ChinaCloud, false);
|
|
68
75
|
}
|
|
69
76
|
else if (environmentSettingValue === CloudEnvironmentSettingValue.USGovernment) {
|
|
70
|
-
return
|
|
71
|
-
...azureEnv.Environment.USGovernment,
|
|
72
|
-
isCustomCloud: false,
|
|
73
|
-
};
|
|
77
|
+
return new ExtendedEnvironment(azureEnv.Environment.USGovernment, false);
|
|
74
78
|
}
|
|
75
79
|
else if (environmentSettingValue === CloudEnvironmentSettingValue.Custom) {
|
|
76
80
|
const customCloud = authProviderConfig.get(CustomEnvironmentSettingName);
|
|
77
81
|
if (customCloud) {
|
|
78
|
-
return
|
|
79
|
-
...new azureEnv.Environment(customCloud),
|
|
80
|
-
isCustomCloud: true,
|
|
81
|
-
};
|
|
82
|
+
return new ExtendedEnvironment(customCloud, true);
|
|
82
83
|
}
|
|
83
84
|
throw new Error(vscode.l10n.t('The custom cloud choice is not configured. Please configure the setting `{0}.{1}`.', CustomCloudConfigurationSection, CustomEnvironmentSettingName));
|
|
84
85
|
}
|
|
85
|
-
return
|
|
86
|
-
...azureEnv.Environment.get(azureEnv.Environment.AzureCloud.name),
|
|
87
|
-
isCustomCloud: false,
|
|
88
|
-
};
|
|
86
|
+
return new ExtendedEnvironment(azureEnv.Environment.AzureCloud, false);
|
|
89
87
|
}
|
|
90
88
|
/**
|
|
91
89
|
* Sets the configured Azure cloud.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.dedupeSubscriptions = dedupeSubscriptions;
|
|
8
|
+
/**
|
|
9
|
+
* Deduplicates (and sorts) a list of Azure subscriptions.
|
|
10
|
+
* In short, the behavior is that the combination of account + tenant + subscriptionId will be unique.
|
|
11
|
+
* The last appearance of any duplicates will be kept. The resulting list is sorted by subscription name.
|
|
12
|
+
*
|
|
13
|
+
* Please note:
|
|
14
|
+
* - The same tenant may appear under different accounts.
|
|
15
|
+
* - The same subscriptionId may appear under different accounts that share the same tenant.
|
|
16
|
+
* - Rarely, the same subscriptionId may also appear under different accounts + different tenants.
|
|
17
|
+
*
|
|
18
|
+
* @param subscriptions The list of subscriptions to deduplicate
|
|
19
|
+
*/
|
|
20
|
+
function dedupeSubscriptions(subscriptions) {
|
|
21
|
+
const deduped = new Map();
|
|
22
|
+
for (const sub of subscriptions) {
|
|
23
|
+
deduped.set(`${sub.account.id}/${sub.tenantId}/${sub.subscriptionId}`, sub);
|
|
24
|
+
}
|
|
25
|
+
return Array.from(deduped.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=dedupeSubscriptions.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getMetricsForTelemetry = getMetricsForTelemetry;
|
|
8
|
+
/**
|
|
9
|
+
* Gets telemetry metrics about accounts, tenants, and subscriptions.
|
|
10
|
+
* @param subscriptionProvider The subscription provider to use to get the metrics.
|
|
11
|
+
* @throws A NotSignedInError if no accounts are signed in.
|
|
12
|
+
*/
|
|
13
|
+
async function getMetricsForTelemetry(subscriptionProvider) {
|
|
14
|
+
// Get the total number of accounts (requires no web requests)
|
|
15
|
+
// Errors are deliberately not caught here, so if no accounts are signed in, this will throw
|
|
16
|
+
const accounts = await subscriptionProvider.getAccounts();
|
|
17
|
+
const numAccounts = accounts.length;
|
|
18
|
+
// Get the total number of tenants across all accounts (requires one web request per account, which is reasonable)
|
|
19
|
+
let numTenants = 0;
|
|
20
|
+
for (const account of accounts) {
|
|
21
|
+
try {
|
|
22
|
+
const tenants = await subscriptionProvider.getTenantsForAccount(account);
|
|
23
|
+
numTenants += tenants.length;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
continue; // If we can't get tenants for an account, skip it instead of throwing
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Get as many subscriptions as we can (requires one web request per account+tenant)
|
|
30
|
+
// This is limited to the first 10 account+tenants, thus a max of 10 web requests
|
|
31
|
+
// Errors are deliberately not caught here; none are expected since at least one account is signed in
|
|
32
|
+
const subscriptions = await subscriptionProvider.getAvailableSubscriptions();
|
|
33
|
+
const numSubscriptions = subscriptions.length;
|
|
34
|
+
// Get subscription IDs (up to 25)
|
|
35
|
+
const subscriptionSet = new Set();
|
|
36
|
+
subscriptions.slice(0, 25).forEach(sub => {
|
|
37
|
+
subscriptionSet.add(sub.subscriptionId);
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
totalAccounts: numAccounts,
|
|
41
|
+
visibleTenants: numTenants,
|
|
42
|
+
visibleSubscriptions: numSubscriptions,
|
|
43
|
+
subscriptionIdList: JSON.stringify(Array.from(subscriptionSet)),
|
|
44
|
+
subscriptionIdListIsIncomplete: subscriptions.length > 25,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=getMetricsForTelemetry.js.map
|
|
@@ -39,13 +39,16 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.getSessionFromVSCode = getSessionFromVSCode;
|
|
41
41
|
const vscode = __importStar(require("vscode"));
|
|
42
|
-
const configuredAzureEnv_1 = require("./
|
|
43
|
-
const isAuthenticationWwwAuthenticateRequest_1 = require("./
|
|
42
|
+
const configuredAzureEnv_1 = require("./configuredAzureEnv");
|
|
43
|
+
const isAuthenticationWwwAuthenticateRequest_1 = require("./isAuthenticationWwwAuthenticateRequest");
|
|
44
44
|
function ensureEndingSlash(value) {
|
|
45
45
|
return value.endsWith('/') ? value : `${value}/`;
|
|
46
46
|
}
|
|
47
47
|
function getResourceScopes(scopes) {
|
|
48
48
|
if (scopes === undefined || scopes === "" || scopes.length === 0) {
|
|
49
|
+
// For https://github.com/microsoft/vscode-azurefunctions/issues/3913, the default scope was changed from
|
|
50
|
+
// ~'https://management.azure.com/.default' (`AzureEnv.resourceManagerEndpointUrl`) to
|
|
51
|
+
// ~'https://management.core.windows.net/.default' (`AzureEnv.managementEndpointUrl`)
|
|
49
52
|
scopes = ensureEndingSlash((0, configuredAzureEnv_1.getConfiguredAzureEnv)().managementEndpointUrl);
|
|
50
53
|
}
|
|
51
54
|
const arrScopes = (Array.isArray(scopes) ? scopes : [scopes])
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getSignalForToken = getSignalForToken;
|
|
8
|
+
/**
|
|
9
|
+
* Gets an AbortSignal that is tied to the given {@link vscode.CancellationToken}.
|
|
10
|
+
* @param token The token to convert
|
|
11
|
+
* @returns The {@link AbortSignal} or undefined if no token is provided
|
|
12
|
+
*/
|
|
13
|
+
function getSignalForToken(token) {
|
|
14
|
+
if (!token) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
if (token.isCancellationRequested) {
|
|
19
|
+
controller.abort();
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const disposable = token.onCancellationRequested(() => {
|
|
23
|
+
disposable.dispose();
|
|
24
|
+
controller.abort();
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return controller.signal;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=getSignalForToken.js.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.CaselessMap = void 0;
|
|
8
|
+
class CaselessMap {
|
|
9
|
+
#map = new Map();
|
|
10
|
+
clear() {
|
|
11
|
+
this.#map.clear();
|
|
12
|
+
}
|
|
13
|
+
delete(key) {
|
|
14
|
+
return this.#map.delete(this.normalizeKey(key));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* @important Keys returned **match original case**!
|
|
18
|
+
*/
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Must exactly match interface
|
|
20
|
+
forEach(callbackfn, thisArg) {
|
|
21
|
+
this.#map.forEach(entry => {
|
|
22
|
+
callbackfn.call(thisArg, entry.value, entry.originalKey, this);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
get(key) {
|
|
26
|
+
return this.#map.get(this.normalizeKey(key))?.value;
|
|
27
|
+
}
|
|
28
|
+
has(key) {
|
|
29
|
+
return this.#map.has(this.normalizeKey(key));
|
|
30
|
+
}
|
|
31
|
+
set(key, value) {
|
|
32
|
+
this.#map.set(this.normalizeKey(key), { originalKey: key, value });
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
get size() {
|
|
36
|
+
return this.#map.size;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @important Keys returned **match original case**!
|
|
40
|
+
*/
|
|
41
|
+
*entries() {
|
|
42
|
+
for (const [, entry] of this.#map) {
|
|
43
|
+
yield [entry.originalKey, entry.value];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* @important Keys returned **match original case**!
|
|
48
|
+
*/
|
|
49
|
+
*keys() {
|
|
50
|
+
for (const [, entry] of this.#map) {
|
|
51
|
+
yield entry.originalKey;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
*values() {
|
|
55
|
+
for (const [, entry] of this.#map) {
|
|
56
|
+
yield entry.value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* @important Keys returned **match original case**!
|
|
61
|
+
*/
|
|
62
|
+
[Symbol.iterator]() {
|
|
63
|
+
return this.entries();
|
|
64
|
+
}
|
|
65
|
+
[Symbol.toStringTag] = 'CaselessMap';
|
|
66
|
+
normalizeKey(key) {
|
|
67
|
+
return key.toLowerCase();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.CaselessMap = CaselessMap;
|
|
71
|
+
//# sourceMappingURL=CaselessMap.js.map
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.TwoKeyCaselessMap = void 0;
|
|
8
|
+
const CaselessMap_1 = require("./CaselessMap");
|
|
9
|
+
class TwoKeyCaselessMap {
|
|
10
|
+
testMode;
|
|
11
|
+
#map1 = new CaselessMap_1.CaselessMap(); // First map has key1 as the outer key and key2 as the inner key
|
|
12
|
+
#map2 = new CaselessMap_1.CaselessMap(); // Second key map has key2 as the outer key and key1 as the inner key
|
|
13
|
+
#size = 0;
|
|
14
|
+
constructor(testMode = false) {
|
|
15
|
+
this.testMode = testMode;
|
|
16
|
+
}
|
|
17
|
+
clear() {
|
|
18
|
+
this.#map1.clear();
|
|
19
|
+
this.#map2.clear();
|
|
20
|
+
this.#size = 0;
|
|
21
|
+
}
|
|
22
|
+
clearByFirstKey(key1) {
|
|
23
|
+
const innerMap1 = this.#map1.get(key1);
|
|
24
|
+
if (!innerMap1) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Decrement size before any deletions
|
|
28
|
+
this.#size -= innerMap1.size;
|
|
29
|
+
// Remove all entries from #map2 that reference this key1
|
|
30
|
+
innerMap1.forEach((_, key2) => {
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- The existence of innerMap1 ensures this is non-null
|
|
32
|
+
const innerMap2 = this.#map2.get(key2);
|
|
33
|
+
innerMap2.delete(key1);
|
|
34
|
+
if (innerMap2.size === 0) {
|
|
35
|
+
this.#map2.delete(key2);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
// Remove the entire inner map from #map1
|
|
39
|
+
this.#map1.delete(key1);
|
|
40
|
+
}
|
|
41
|
+
clearBySecondKey(key2) {
|
|
42
|
+
const innerMap2 = this.#map2.get(key2);
|
|
43
|
+
if (!innerMap2) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Decrement size before any deletions
|
|
47
|
+
this.#size -= innerMap2.size;
|
|
48
|
+
// Remove all entries from #map1 that reference this key2
|
|
49
|
+
innerMap2.forEach((_, key1) => {
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- The existence of innerMap2 ensures this is non-null
|
|
51
|
+
const innerMap1 = this.#map1.get(key1);
|
|
52
|
+
innerMap1.delete(key2);
|
|
53
|
+
if (innerMap1.size === 0) {
|
|
54
|
+
this.#map1.delete(key1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// Remove the entire inner map from #map2
|
|
58
|
+
this.#map2.delete(key2);
|
|
59
|
+
}
|
|
60
|
+
delete(key1, key2) {
|
|
61
|
+
if (!this.has(key1, key2)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- The has() check above ensures non-null
|
|
65
|
+
const innerMap1 = this.#map1.get(key1);
|
|
66
|
+
innerMap1.delete(key2);
|
|
67
|
+
if (innerMap1.size === 0) {
|
|
68
|
+
this.#map1.delete(key1);
|
|
69
|
+
}
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- The has() check above ensures non-null
|
|
71
|
+
const innerMap2 = this.#map2.get(key2);
|
|
72
|
+
innerMap2.delete(key1);
|
|
73
|
+
if (innerMap2.size === 0) {
|
|
74
|
+
this.#map2.delete(key2);
|
|
75
|
+
}
|
|
76
|
+
this.#size--;
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* @important Keys returned **match original case**!
|
|
81
|
+
*/
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Must exactly match interface
|
|
83
|
+
forEach(callbackfn, thisArg) {
|
|
84
|
+
this.#map1.forEach((innerMap1, key1) => {
|
|
85
|
+
innerMap1.forEach((value, key2) => {
|
|
86
|
+
callbackfn.call(thisArg, value, key1, key2);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
get(key1, key2) {
|
|
91
|
+
return this.#map1.get(key1)?.get(key2);
|
|
92
|
+
}
|
|
93
|
+
has(key1, key2) {
|
|
94
|
+
const result1 = this.#map1.get(key1)?.has(key2);
|
|
95
|
+
if (this.testMode) {
|
|
96
|
+
const result2 = this.#map2.get(key2)?.has(key1);
|
|
97
|
+
if (!!result1 !== !!result2) {
|
|
98
|
+
throw new Error('Inconsistent state in TwoKeyCaselessMap');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return result1 ?? false;
|
|
102
|
+
}
|
|
103
|
+
set(key1, key2, value) {
|
|
104
|
+
const alreadyHadEntry = this.has(key1, key2);
|
|
105
|
+
let innerMap1 = this.#map1.get(key1);
|
|
106
|
+
if (!innerMap1) {
|
|
107
|
+
innerMap1 = new CaselessMap_1.CaselessMap();
|
|
108
|
+
this.#map1.set(key1, innerMap1);
|
|
109
|
+
}
|
|
110
|
+
innerMap1.set(key2, value);
|
|
111
|
+
let innerMap2 = this.#map2.get(key2);
|
|
112
|
+
if (!innerMap2) {
|
|
113
|
+
innerMap2 = new CaselessMap_1.CaselessMap();
|
|
114
|
+
this.#map2.set(key2, innerMap2);
|
|
115
|
+
}
|
|
116
|
+
innerMap2.set(key1, value);
|
|
117
|
+
if (!alreadyHadEntry) {
|
|
118
|
+
this.#size++;
|
|
119
|
+
}
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
get size() {
|
|
123
|
+
return this.#size;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* @important Keys returned **match original case**!
|
|
127
|
+
*/
|
|
128
|
+
entriesByFirstKey(key1) {
|
|
129
|
+
return this.#map1.get(key1)?.entries() ?? emptyIterator();
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* @important Keys returned **match original case**!
|
|
133
|
+
*/
|
|
134
|
+
entriesBySecondKey(key2) {
|
|
135
|
+
return this.#map2.get(key2)?.entries() ?? emptyIterator();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* @important Keys returned **match original case**!
|
|
139
|
+
*/
|
|
140
|
+
*entries() {
|
|
141
|
+
for (const [key1, innerMap1] of this.#map1) {
|
|
142
|
+
for (const [key2, value] of innerMap1) {
|
|
143
|
+
yield [key1, key2, value];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* @important Keys returned **match original case**!
|
|
149
|
+
*/
|
|
150
|
+
keysByFirstKey(key1) {
|
|
151
|
+
return this.#map1.get(key1)?.keys() ?? emptyIterator();
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* @important Keys returned **match original case**!
|
|
155
|
+
*/
|
|
156
|
+
keysBySecondKey(key2) {
|
|
157
|
+
return this.#map2.get(key2)?.keys() ?? emptyIterator();
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* @important Keys returned **match original case**!
|
|
161
|
+
*/
|
|
162
|
+
*keys() {
|
|
163
|
+
for (const [key1, innerMap1] of this.#map1) {
|
|
164
|
+
for (const key2 of innerMap1.keys()) {
|
|
165
|
+
yield [key1, key2];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
valuesByFirstKey(key1) {
|
|
170
|
+
return this.#map1.get(key1)?.values() ?? emptyIterator();
|
|
171
|
+
}
|
|
172
|
+
valuesBySecondKey(key2) {
|
|
173
|
+
return this.#map2.get(key2)?.values() ?? emptyIterator();
|
|
174
|
+
}
|
|
175
|
+
*values() {
|
|
176
|
+
for (const innerMap1 of this.#map1.values()) {
|
|
177
|
+
for (const value of innerMap1.values()) {
|
|
178
|
+
yield value;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* @important Keys returned **match original case**!
|
|
184
|
+
*/
|
|
185
|
+
[Symbol.iterator]() {
|
|
186
|
+
return this.entries();
|
|
187
|
+
}
|
|
188
|
+
[Symbol.toStringTag] = 'TwoKeyCaselessMap';
|
|
189
|
+
}
|
|
190
|
+
exports.TwoKeyCaselessMap = TwoKeyCaselessMap;
|
|
191
|
+
function emptyIterator() {
|
|
192
|
+
return [][Symbol.iterator]();
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=TwoKeyCaselessMap.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.screen = screen;
|
|
8
|
+
// These regexes are not perfect, but should work for common cases
|
|
9
|
+
// If they don't work, we'll just return the account ID, which does not need to be screened
|
|
10
|
+
const accountLabelRegex = /^(?<email>[^@]+)@(?<domain>[\w]+(\.[\w]+)+)$/i;
|
|
11
|
+
const domainRegex = /^(?<domain>[^.]+)(?<safeTld>\.com(\..*)?|\.net|\.org|\.co\..*|\.gov)$/i;
|
|
12
|
+
/**
|
|
13
|
+
* Screens the label or display name of an Azure account or tenant so that it can be logged without exposing PII.
|
|
14
|
+
* This should *NOT* be considered fool-proof nor safe for telemetry, but is acceptable for local logging.
|
|
15
|
+
* @param accountOrTenant The account or tenant to screen the label / display name of
|
|
16
|
+
* @returns The screened label / display name
|
|
17
|
+
*/
|
|
18
|
+
function screen(accountOrTenant) {
|
|
19
|
+
if ('label' in accountOrTenant && !!accountOrTenant.label) {
|
|
20
|
+
const match = accountLabelRegex.exec(accountOrTenant.label);
|
|
21
|
+
if (match?.groups?.email && match.groups.domain) {
|
|
22
|
+
let screenedEmail = match.groups.email;
|
|
23
|
+
if (screenedEmail.length <= 2) {
|
|
24
|
+
screenedEmail = '***';
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
screenedEmail = `${screenedEmail.at(0)}***${screenedEmail.at(-1)}`;
|
|
28
|
+
}
|
|
29
|
+
let screenedDomain = match.groups.domain;
|
|
30
|
+
const domainMatch = domainRegex.exec(match.groups.domain);
|
|
31
|
+
if (domainMatch?.groups?.domain && domainMatch.groups.safeTld) {
|
|
32
|
+
if (domainMatch.groups.domain.length <= 2) {
|
|
33
|
+
screenedDomain = `***${domainMatch.groups.safeTld}`;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
screenedDomain = `${domainMatch.groups.domain.at(0)}***${domainMatch.groups.safeTld}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (screenedDomain.length <= 2) {
|
|
40
|
+
screenedDomain = '***';
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
screenedDomain = `${screenedDomain.at(0)}***${screenedDomain.at(-1)}`;
|
|
44
|
+
}
|
|
45
|
+
return `${screenedEmail}@${screenedDomain}`;
|
|
46
|
+
}
|
|
47
|
+
// If we can't match it with our simple regex, just return the account ID instead
|
|
48
|
+
return accountOrTenant.id;
|
|
49
|
+
}
|
|
50
|
+
else if ('displayName' in accountOrTenant && !!accountOrTenant.displayName) {
|
|
51
|
+
if (accountOrTenant.displayName.length <= 2) {
|
|
52
|
+
// For too-short names, just return the ID
|
|
53
|
+
return accountOrTenant.tenantId;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Return the first character, three stars, and the last character
|
|
57
|
+
return `${accountOrTenant.displayName.at(0)}***${accountOrTenant.displayName.at(-1)}`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return 'unknown';
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=screen.js.map
|
|
@@ -39,27 +39,30 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.signInToTenant = signInToTenant;
|
|
41
41
|
const vscode = __importStar(require("vscode"));
|
|
42
|
-
const getUnauthenticatedTenants_1 = require("./utils/getUnauthenticatedTenants");
|
|
43
42
|
/**
|
|
44
43
|
* Prompts user to select from a list of unauthenticated tenants.
|
|
45
|
-
* Once selected, requests a new session from VS Code
|
|
44
|
+
* Once selected, requests a new session from VS Code specifically for this tenant.
|
|
46
45
|
*/
|
|
47
|
-
async function signInToTenant(subscriptionProvider) {
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
await subscriptionProvider.signIn(
|
|
46
|
+
async function signInToTenant(subscriptionProvider, account) {
|
|
47
|
+
const tenant = await pickTenant(subscriptionProvider, account);
|
|
48
|
+
if (tenant) {
|
|
49
|
+
await subscriptionProvider.signIn(tenant);
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
|
-
async function pickTenant(subscriptionProvider) {
|
|
54
|
-
const pick = await vscode.window.showQuickPick(getPicks(subscriptionProvider), {
|
|
55
|
-
placeHolder: 'Select a Tenant (Directory) to Sign In To',
|
|
52
|
+
async function pickTenant(subscriptionProvider, account) {
|
|
53
|
+
const pick = await vscode.window.showQuickPick(getPicks(subscriptionProvider, account), {
|
|
54
|
+
placeHolder: vscode.l10n.t('Select a Tenant (Directory) to Sign In To'),
|
|
56
55
|
matchOnDescription: true, // allow searching by tenantId
|
|
57
56
|
ignoreFocusOut: true,
|
|
58
57
|
});
|
|
59
|
-
return pick?.tenant
|
|
58
|
+
return pick?.tenant;
|
|
60
59
|
}
|
|
61
|
-
async function getPicks(subscriptionProvider) {
|
|
62
|
-
const unauthenticatedTenants =
|
|
60
|
+
async function getPicks(subscriptionProvider, account) {
|
|
61
|
+
const unauthenticatedTenants = [];
|
|
62
|
+
const accounts = account ? [account] : await subscriptionProvider.getAccounts();
|
|
63
|
+
for (const account of accounts) {
|
|
64
|
+
unauthenticatedTenants.push(...await subscriptionProvider.getUnauthenticatedTenantsForAccount(account));
|
|
65
|
+
}
|
|
63
66
|
const duplicateTenants = new Set(unauthenticatedTenants
|
|
64
67
|
.filter((tenant, index, self) => index !== self.findIndex(t => t.tenantId === tenant.tenantId))
|
|
65
68
|
.map(tenant => tenant.tenantId));
|
|
@@ -69,7 +72,6 @@ async function getPicks(subscriptionProvider) {
|
|
|
69
72
|
.sort((a, b) => (a.displayName).localeCompare(b.displayName))
|
|
70
73
|
.map(tenant => ({
|
|
71
74
|
label: tenant.displayName ?? '',
|
|
72
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
73
75
|
description: `${tenant.tenantId}${isDuplicate(tenant.tenantId) ? ` (${tenant.account.label})` : ''}`,
|
|
74
76
|
detail: tenant.defaultDomain ?? '',
|
|
75
77
|
tenant,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.tryGetTokenExpiration = tryGetTokenExpiration;
|
|
8
|
+
function tryGetTokenExpiration(session) {
|
|
9
|
+
try {
|
|
10
|
+
if (!!session?.idToken) {
|
|
11
|
+
const idTokenParts = session.idToken.split('.');
|
|
12
|
+
if (idTokenParts.length === 3) {
|
|
13
|
+
const payload = JSON.parse(Buffer.from(idTokenParts[1], 'base64').toString());
|
|
14
|
+
if (payload.exp !== undefined && Number.isInteger(payload.exp)) {
|
|
15
|
+
return payload.exp * 1000; // Convert to milliseconds
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Best effort only
|
|
22
|
+
}
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=tryGetTokenExpiration.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=AzureAccount.js.map
|
|
@@ -5,7 +5,7 @@ import type * as vscode from 'vscode';
|
|
|
5
5
|
export interface AzureAuthentication {
|
|
6
6
|
/**
|
|
7
7
|
* Gets a VS Code authentication session for an Azure subscription.
|
|
8
|
-
* Always uses the default scope,
|
|
8
|
+
* Always uses the default scope, ~`https://management.core.windows.net/.default` and respects `microsoft-sovereign-cloud.environment` setting.
|
|
9
9
|
*
|
|
10
10
|
* @returns A VS Code authentication session or undefined, if none could be obtained.
|
|
11
11
|
*/
|