@rushstack/rush-azure-storage-build-cache-plugin
Version:
Rush plugin for Azure storage cloud build cache
173 lines • 8 kB
JavaScript
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.AzureAuthenticationBase = void 0;
const identity_1 = require("@azure/identity");
const AdoCodespacesAuthCredential_1 = require("./AdoCodespacesAuthCredential");
const rush_sdk_1 = require("@rushstack/rush-sdk");
const terminal_1 = require("@rushstack/terminal");
/**
* @public
*/
class AzureAuthenticationBase {
get _credentialCacheId() {
if (!this.__credentialCacheId) {
const cacheIdParts = [
this._credentialNameForCache,
this._azureEnvironment,
...this._getCacheIdParts()
];
this.__credentialCacheId = cacheIdParts.join('|');
}
return this.__credentialCacheId;
}
constructor(options) {
const { azureEnvironment = 'AzurePublicCloud', loginFlow = process.env.CODESPACES === 'true' ? 'AdoCodespacesAuth' : 'VisualStudioCode' } = options;
this._azureEnvironment = azureEnvironment;
this._credentialUpdateCommandForLogging = options.credentialUpdateCommandForLogging;
this._loginFlow = loginFlow;
this._failoverOrder = options.loginFlowFailover || {
AdoCodespacesAuth: 'VisualStudioCode',
VisualStudioCode: 'AzureCli',
AzureCli: 'AzureDeveloperCli',
AzureDeveloperCli: 'AzurePowerShell',
AzurePowerShell: 'InteractiveBrowser',
InteractiveBrowser: 'DeviceCode',
DeviceCode: undefined
};
}
async updateCachedCredentialAsync(terminal, credential) {
await rush_sdk_1.CredentialCache.usingAsync({
supportEditing: true
}, async (credentialsCache) => {
credentialsCache.setCacheEntry(this._credentialCacheId, {
credential
});
await credentialsCache.saveIfModifiedAsync();
});
}
/**
* Launches an interactive flow to renew a cached credential.
*
* @param terminal - The terminal to log output to
* @param onlyIfExistingCredentialExpiresBefore - If specified, and a cached credential exists, action will only
* be taken if the cached credential expires before the specified date.
*/
async updateCachedCredentialInteractiveAsync(terminal, onlyIfExistingCredentialExpiresBefore) {
await rush_sdk_1.CredentialCache.usingAsync({
supportEditing: true
}, async (credentialsCache) => {
var _a;
if (onlyIfExistingCredentialExpiresBefore) {
const existingCredentialExpiration = (_a = credentialsCache.tryGetCacheEntry(this._credentialCacheId)) === null || _a === void 0 ? void 0 : _a.expires;
if (existingCredentialExpiration &&
existingCredentialExpiration > onlyIfExistingCredentialExpiresBefore) {
return;
}
}
const credential = await this._getCredentialAsync(terminal, this._loginFlow, credentialsCache);
credentialsCache.setCacheEntry(this._credentialCacheId, {
credential: credential.credentialString,
expires: credential.expiresOn,
credentialMetadata: credential.credentialMetadata
});
await credentialsCache.saveIfModifiedAsync();
});
}
async deleteCachedCredentialsAsync(terminal) {
await rush_sdk_1.CredentialCache.usingAsync({
supportEditing: true
}, async (credentialsCache) => {
credentialsCache.deleteCacheEntry(this._credentialCacheId);
await credentialsCache.saveIfModifiedAsync();
});
}
async tryGetCachedCredentialAsync({ expiredCredentialBehavior, terminal } = {
expiredCredentialBehavior: 'throwError'
}) {
var _a;
let cacheEntry;
await rush_sdk_1.CredentialCache.usingAsync({
supportEditing: false
}, (credentialsCache) => {
cacheEntry = credentialsCache.tryGetCacheEntry(this._credentialCacheId);
});
const expirationTime = (_a = cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.expires) === null || _a === void 0 ? void 0 : _a.getTime();
if (expirationTime && expirationTime < Date.now()) {
if (expiredCredentialBehavior === 'logWarning' || expiredCredentialBehavior === 'throwError') {
let errorMessage = `Cached Azure ${this._credentialKindForLogging} credentials have expired.`;
if (this._credentialUpdateCommandForLogging) {
errorMessage += ` Update the credentials by running "${this._credentialUpdateCommandForLogging}".`;
}
if (expiredCredentialBehavior === 'logWarning') {
terminal.writeWarningLine(errorMessage);
}
else if (expiredCredentialBehavior === 'throwError') {
throw new Error(errorMessage);
}
}
return undefined;
}
else {
return cacheEntry;
}
}
async _getCredentialAsync(terminal, loginFlow, credentialsCache) {
var _a;
const authorityHost = identity_1.AzureAuthorityHosts[this._azureEnvironment];
if (!authorityHost) {
throw new Error(`Unexpected Azure environment: ${this._azureEnvironment}`);
}
const interactiveCredentialOptions = {
...this._additionalInteractiveCredentialOptions,
authorityHost
};
const deviceCodeCredentialOptions = {
...this._additionalDeviceCodeCredentialOptions,
...interactiveCredentialOptions,
userPromptCallback: (deviceCodeInfo) => {
terminal_1.PrintUtilities.printMessageInBox(deviceCodeInfo.message, terminal);
}
};
const options = { authorityHost };
const priority = new Set([loginFlow]);
for (const credType of priority) {
const next = (_a = this._failoverOrder) === null || _a === void 0 ? void 0 : _a[credType];
if (next) {
priority.add(next);
}
}
const knownCredentialTypes = {
DeviceCode: class extends identity_1.DeviceCodeCredential {
new(credentialOptions) {
return new identity_1.DeviceCodeCredential({
...deviceCodeCredentialOptions,
...credentialOptions
});
}
},
InteractiveBrowser: class extends identity_1.InteractiveBrowserCredential {
new(credentialOptions) {
return new identity_1.InteractiveBrowserCredential({ ...interactiveCredentialOptions, ...credentialOptions });
}
},
AdoCodespacesAuth: AdoCodespacesAuthCredential_1.AdoCodespacesAuthCredential,
VisualStudioCode: identity_1.VisualStudioCodeCredential,
AzureCli: identity_1.AzureCliCredential,
AzureDeveloperCli: identity_1.AzureDeveloperCliCredential,
AzurePowerShell: identity_1.AzurePowerShellCredential
};
const credentials = Array.from(priority, (credType) => new knownCredentialTypes[credType](options));
const tokenCredential = new identity_1.ChainedTokenCredential(...credentials);
try {
return await this._getCredentialFromTokenAsync(terminal, tokenCredential, credentialsCache);
}
catch (error) {
terminal.writeVerbose(`Failed to get credentials with ${loginFlow}: ${error}`);
throw error;
}
}
}
exports.AzureAuthenticationBase = AzureAuthenticationBase;
//# sourceMappingURL=AzureAuthenticationBase.js.map
;