UNPKG

6.08 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const get_port_1 = require("get-port");
4const http = require("http");
5const axios_1 = require("axios");
6// @ts-ignore
7const opn = require("open");
8const crypto = require("crypto");
9const base_command_1 = require("../base-command");
10const helpers_1 = require("../utils/helpers");
11const constants_1 = require("../utils/constants");
12class Login extends base_command_1.default {
13 constructor() {
14 super(...arguments);
15 this.on = (event, callback) => {
16 this._listerners[event] = [...this._listerners[event], callback];
17 };
18 this.stopServer = () => {
19 this.debug('stopping server');
20 if (this._server) {
21 this._server.close(() => {
22 this.debug('server stopped');
23 this._listerners['shutdown'].map(cb => cb());
24 });
25 }
26 this.ux.action.stop();
27 };
28 this.startServer = async () => {
29 const port = await get_port_1.default({ port: constants_1.BEARER_LOGIN_PORT });
30 return new Promise((resolve, reject) => {
31 if (port !== constants_1.BEARER_LOGIN_PORT) {
32 this.error(`bearer login requires port ${constants_1.BEARER_LOGIN_PORT} to be available`);
33 reject();
34 }
35 this.debug('starting server');
36 const server = http
37 .createServer((request, response) => {
38 let body = '';
39 request.on('data', chunk => {
40 body += chunk;
41 });
42 request.on('end', () => {
43 try {
44 const data = JSON.parse(body);
45 this.debug(data);
46 response.setHeader('Access-Control-Allow-Origin', process.env.LOGIN_ALLOWED_ORIGIN || this.constants.DeveloperPortalUrl);
47 response.setHeader('Connection', 'close');
48 response.write('OK');
49 response.end();
50 this.stopServer();
51 this.getToken(data.code);
52 }
53 catch (e) {
54 this.debug(e);
55 }
56 });
57 })
58 .listen(constants_1.BEARER_LOGIN_PORT, () => resolve(server));
59 });
60 };
61 this.getToken = async (code) => {
62 try {
63 const { data: token } = await axios_1.default.post(`${this.constants.LoginDomain}/oauth/token`, {
64 code,
65 grant_type: 'authorization_code',
66 client_id: `${constants_1.LOGIN_CLIENT_ID}`,
67 code_verifier: `${this._verifier}`,
68 redirect_uri: this.callbackUrl
69 });
70 this.debug(token);
71 await this.bearerConfig.storeToken(token);
72 this.success('Successfully logged in!! 🐻');
73 this._listerners['success'].map(cb => cb());
74 }
75 catch (e) {
76 this.error(e);
77 }
78 };
79 }
80 async run() {
81 this._listerners = {
82 success: [],
83 error: [],
84 shutdown: []
85 };
86 this._server = await this.startServer();
87 this._verifier = base64URLEncode(crypto.randomBytes(32));
88 this._challenge = base64URLEncode(sha256(this._verifier));
89 this.ux.action.start('Logging you in');
90 const scopes = 'offline_access email openid';
91 const audience = `cli-${constants_1.BEARER_ENV}`;
92 const params = {
93 audience,
94 scope: scopes,
95 response_type: 'code',
96 client_id: constants_1.LOGIN_CLIENT_ID,
97 code_challenge: this._challenge,
98 code_challenge_method: 'S256',
99 redirect_uri: this.callbackUrl
100 };
101 this.debug('authoriwe params %j', params);
102 const url = `${this.constants.LoginDomain}/authorize?${helpers_1.toParams(params)}`;
103 const spawned = await opn(url);
104 await Promise.race([
105 new Promise((resolve, reject) => {
106 spawned.on('close', async (code, signal) => {
107 if (code !== 0) {
108 this.stopServer();
109 this.warn(this.colors.yellow(`Unable to open a browser. If you want to retrieve a token please follow these steps\n`));
110 this.log(this.colors.bold('1/ access the url below and follow the login process:\n\n'), url);
111 this.log();
112 this.log(this.colors.bold(`2/ when you access the success page copy the token and paste it here`));
113 const token = await this.askForString('Token');
114 await this.getToken(token);
115 }
116 });
117 }),
118 Promise.all([
119 new Promise((resolve, reject) => {
120 this.on('success', resolve);
121 this.on('error', reject);
122 }),
123 new Promise((resolve, reject) => {
124 this.on('shutdown', resolve);
125 this.on('error', reject);
126 })
127 ])
128 ]);
129 }
130 get callbackUrl() {
131 return process.env.BEARER_LOGIN_CALLBACK_URL || `${this.constants.DeveloperPortalUrl}cli-login-callback`;
132 }
133}
134Login.description = 'login using Bearer credentials';
135Login.flags = Object.assign({}, base_command_1.default.flags);
136Login.args = [];
137exports.default = Login;
138function base64URLEncode(str) {
139 return str
140 .toString('base64')
141 .replace(/\+/g, '-')
142 .replace(/\//g, '_')
143 .replace(/=/g, '');
144}
145function sha256(str) {
146 return crypto
147 .createHash('sha256')
148 .update(str)
149 .digest();
150}