better-vsts-npm-auth
Version:
Platform agnostic library which provides a robust solution for maintaining credentials in your npmrc files
105 lines • 5.74 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const npm_1 = require("./lib/npm");
const config_1 = require("./lib/config");
const registry_auth_reducer_1 = require("./lib/registry-auth-reducer");
const vsts_auth_client_1 = require("./lib/vsts-auth-client");
const yarnrcyml_1 = require("./lib/yarnrcyml");
const uuid = require("uuid/v4");
const fs = require("fs");
var vsts_auth_client_2 = require("./lib/vsts-auth-client");
exports.setRefreshToken = vsts_auth_client_2.setRefreshToken;
/**
* Authentication library for maintaining an up-to-date
* authentication token in the user's npmrc for interfacing with
* VSTS feeds
*
* Workflow:
* 1. read into memory the npmrc credentials from the given project
* in order to see which registries we need credentials for
* 2.a if there are credentials in ~/.npmrc, verify that the token
* has more than 1 week until it expires
* 2.b if not, request an access_token and store the
* new credentials in ~/.npmrc
*
* A note on authentication & authorization:
* this program should not prompt the user unless absolutely
* necessary. Authentication should only be needed once, when
* this program is run for the very first time on a device.
* Any subsequent authorization needs (such as for step 2.b
* above) should use the cached refresh_token to gain a fresh
* access_token for authorization.
*/
function isAuthorizationError(e) {
return e instanceof vsts_auth_client_1.AuthorizationError;
}
exports.isAuthorizationError = isAuthorizationError;
function run(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
let configObj;
try {
if (options.configOverride) {
config_1.Config.setConfigPath(options.configOverride);
}
configObj = config_1.Config.get();
// if npmrcPath / yarnrcPath isn't specified, default is the working directory
options.npmrcPath = options.npmrcPath || process.cwd();
options.yarnrcYmlPath = options.yarnrcYmlPath || process.cwd();
const projectYarnrcYml = new yarnrcyml_1.YarnrcYml(options.yarnrcYmlPath);
const isProjectUsingYarnv2 = fs.existsSync(projectYarnrcYml.filePath);
let userRc, projectRc;
if (!isProjectUsingYarnv2) {
[userRc, projectRc] = yield Promise.all([
npm_1.Npmrc.getUserNpmrc().readSettingsFromFile(),
new npm_1.Npmrc(options.npmrcPath).readSettingsFromFile()
]);
}
else {
[userRc, projectRc] = yield Promise.all([
yarnrcyml_1.YarnrcYml.getUserNpmrc().readSettingsFromFile(),
new yarnrcyml_1.YarnrcYml(options.yarnrcYmlPath).readSettingsFromFile()
]);
}
let authenticatedRegistries = yield registry_auth_reducer_1.authenticateRegistries(...userRc.getRegistries(), ...projectRc.getRegistries());
// get the new settings which need to be written to the user npmrc file
console.log("Authenticating the following registries:\n", authenticatedRegistries.map(r => `\t${r.url}\n`).join(""));
let authSettings = authenticatedRegistries.map(r => r.getAuthSettings());
Object.assign(userRc.settings, ...authSettings);
yield userRc.saveSettingsToFile();
}
catch (e) {
// if this is running in a CI environment, reject to signal failure
// otherwise, open the auth page as the error is likely due to
// the user needing to authorize the app and/or configure their
// refresh_token
if (!process.env.BUILD_BUILDID && !process.env.RELEASE_RELEASEID) {
// as of April 2020, appears this endpoint is staying as-is for now even with the branding
// change to "Azure DevOps": https://web.archive.org/web/20200406154934/https://docs.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/oauth?view=azure-devops
let consentUrl = `https://app.vssps.visualstudio.com/oauth2/authorize?client_id=${configObj.clientId}&response_type=Assertion&state=${uuid()}&scope=vso.packaging_write&redirect_uri=${configObj.redirectUri}`;
console.log("\n*****\n" +
"We need user consent before this script can run.\n\n" +
"Follow instructions in the browser window that just opened, or if a browser does not open,\n" +
"manually browse to this url and follow the instructions there:\n\n" +
`${consentUrl}\n\n` +
"Then run better-vsts-npm-auth again after consent has been granted.\n*****\n");
}
// no matter what, we error out here
if (options.stack === true) {
throw e;
}
else {
process.exit(1);
}
}
});
}
exports.run = run;
//# sourceMappingURL=index.js.map