@adinsure-ops/ops-cli
Version:
Operations CLI for working with AdInsure
218 lines (217 loc) • 8.74 kB
JavaScript
import { __awaiter } from "tslib";
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import fs from 'fs';
import http from 'http';
import open from 'open';
import path from 'path';
import url from 'url';
import { execSync } from 'child_process';
import CommandBase from '../command.base.js';
import NpmRc from '../lib/npmrc.js';
import YarnRc from '../lib/yarnrc.js';
class Login extends CommandBase {
constructor() {
super(...arguments);
this.npmRegistries = [
'https://pkgs.dev.azure.com/adacta-fintech/adinsure/_packaging/feed/npm/registry/',
'https://pkgs.dev.azure.com/adinsure-test/_packaging/TestFeed/npm/registry/',
];
}
/**
* Get NPM token for adinsure npm repositories
*
* @returns [[Promise<string>]]
*/
setNPM() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try {
const npmRc = new NpmRc();
const yarnRc = new YarnRc();
const token = yield this.security.getNPMToken();
for (const registry of this.npmRegistries) {
const registryUrl = new url.URL(registry);
npmRc.set(`//${registryUrl.hostname}${registryUrl.pathname}:_authToken`, token);
yarnRc.set("npmAuthToken", token);
}
npmRc.save();
yarnRc.save();
this.log(`${chalk.green('NPM token generated!')}`);
resolve();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (error) {
reject(error);
}
}));
});
}
/**
* Handle Docker login by:
* 1. Checking if Docker is available.
* 2. Ensuring user is logged in.
* 3. Generating a Docker token for adinsure.azurecr.io.
* 4. Running 'docker login' with the generated token.
*/
handleDockerLogin() {
return __awaiter(this, void 0, void 0, function* () {
// 1. Check if Docker command is available
try {
execSync('docker --version', { stdio: 'ignore' });
}
catch (err) {
this.error('Docker is not installed or not in PATH. Please install Docker first.', { exit: 1 });
}
// 2. Ensure the user is logged in (using your existing token retrieval logic)
try {
yield this.security.getToken();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (err) {
this.error('User is not logged in. Please run "ops login" without --docker first.', { exit: 1 });
}
// 3. generate token from `adinsure.azurecr.io`
this.log(chalk.yellow('Generating Docker authentication token for adinsure.azurecr.io...'));
let acrToken;
try {
acrToken = yield this.security.getACRToken();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (err) {
this.error('Failed to generate Docker token: ' + err.message, { exit: 1 });
}
// 4. call docker login command
this.log(chalk.yellow('Logging in to adinsure.azurecr.io via Docker...'));
try {
execSync(`docker login adinsure.azurecr.io -u 00000000-0000-0000-0000-000000000000 --password "${acrToken}" `);
this.log(chalk.green('Docker login successful!'));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (err) {
this.error('Docker login failed: ' + err.message, { exit: 1 });
}
});
}
run() {
const _super = Object.create(null, {
run: { get: () => super.run }
});
return __awaiter(this, void 0, void 0, function* () {
_super.run.call(this);
const { flags } = yield this.parse(Login);
if (flags.docker) {
yield this.handleDockerLogin();
return;
}
if (flags.force) {
fs.unlink(path.resolve(this.security.getTokenPath()), () => {
this.log(`${chalk.yellow('Note: We have launched a browser for you to login.')}`);
});
}
if (flags.skipCI && process.env[flags.skipCI]) {
if (flags.force)
this.error(new Error('Cannot skip login as the force login flag has been set'));
this.log(`${chalk.yellow('Note: skipping login because variables was set for CI')}`);
return;
}
if (flags.npm) {
try {
yield this.setNPM();
return;
}
catch (_a) {
this.log(`${chalk.yellow('Note: Login is needed to get NPM token!')}`);
}
}
if (flags.deviceFlow) {
try {
yield this.security.acquireTokenDeviceFlow();
this.log(`${chalk.green('Login Successful!')}`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (error) {
this.error(error);
}
}
else {
this.log(`${chalk.yellow('Note: We have launched a browser for you to login.')}`);
const loginUrl = yield this.security.getLoginUrl();
yield open(loginUrl);
const server = http.createServer((req, res) => __awaiter(this, void 0, void 0, function* () {
// First let the user know everything was OK
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write(Login.responsePageContent);
res.end();
this.log(`${chalk.yellow('You have logged in successfully. Acquiring your access token...')}`);
// Then let's acquire an authentication token from AAD
try {
const queryURL = new url.URL(req.url, 'http://localhost:3044').searchParams;
const name = yield this.security.acquireToken(Object.fromEntries(Array.from(queryURL.entries())));
this.log(`Hello ${name}!`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (error) {
this.error(error, { exit: false });
}
if (flags.npm) {
try {
yield this.setNPM();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (error) {
this.error(error, { exit: false });
}
}
server.close();
}));
server.listen(3044);
}
});
}
}
Login.description = 'log in to use ops services with AzureAD';
Login.usage = 'login';
Login.examples = [
`$ ops login`,
`$ ops login --npm`,
`$ ops login --skipCi CI`,
`$ ops login --deviceFlow`,
];
Login.flags = {
deviceFlow: Flags.boolean({
description: 'authenticate using device flow',
default: false,
}),
npm: Flags.boolean({
description: 'register also for npm',
default: false,
}),
skipCI: Flags.string({
description: 'Skip login if environment variables is set',
}),
force: Flags.boolean({
description: 'Force a change of login token',
default: false,
}),
docker: Flags.boolean({
description: 'Authenticate with adinsure.azurecr.io for Docker',
default: false,
}),
};
Login.responsePageContent = `
<!DOCTYPE html>
<html>
<head>
<title>ops-cli authenticate</title>
<link rel='icon' href='data:;base64,iVBORw0KGgo='>
</head>
<body>
<p><strong>Your login was successful!</strong></p>
<p>This page will automatically close after 10 seconds OR you can close it yourself immediately.</p>
<script type='text/javascript'>
setTimeout('self.close()', 10000);
</script>
</body>
</html>`;
export default Login;