UNPKG

@ionic/cli

Version:

A tool for creating and developing Ionic Framework mobile apps.

228 lines (227 loc) 9.84 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.promptToSignup = exports.promptToLogin = exports.ProSession = exports.BaseSession = void 0; const guards_1 = require("../guards"); const color_1 = require("./color"); const errors_1 = require("./errors"); const http_1 = require("./http"); const open_1 = require("./open"); class BaseSession { constructor(e) { this.e = e; } async logout() { const activeToken = this.e.config.get('tokens.user'); if (activeToken) { // invalidate the token const { req } = await this.e.client.make('POST', '/logout'); req.set('Authorization', `Bearer ${activeToken}`) .send({}); try { await this.e.client.do(req); } catch (e) { } } this.e.config.unset('org.id'); this.e.config.unset('user.id'); this.e.config.unset('user.email'); this.e.config.unset('tokens.user'); this.e.config.unset('tokens.refresh'); this.e.config.unset('tokens.expiresInSeconds'); this.e.config.unset('tokens.issuedOn'); this.e.config.unset('tokens.flowName'); this.e.config.set('git.setup', false); } isLoggedIn() { return typeof this.e.config.get('tokens.user') === 'string'; } getUser() { const userId = this.e.config.get('user.id'); if (!userId) { throw new errors_1.SessionException(`Oops, sorry! You'll need to log in:\n ${(0, color_1.input)('ionic login')}\n\n` + `You can create a new account by signing up:\n\n ${(0, color_1.input)('ionic signup')}\n`); } return { id: userId }; } } exports.BaseSession = BaseSession; class ProSession extends BaseSession { async getUserToken() { let userToken = this.e.config.get('tokens.user'); if (!userToken) { throw new errors_1.SessionException(`Oops, sorry! You'll need to log in:\n ${(0, color_1.input)('ionic login')}\n\n` + `You can create a new account by signing up:\n\n ${(0, color_1.input)('ionic signup')}\n`); } const tokenIssuedOn = this.e.config.get('tokens.issuedOn'); const tokenExpirationSeconds = this.e.config.get('tokens.expiresInSeconds'); const refreshToken = this.e.config.get('tokens.refresh'); const flowName = this.e.config.get('tokens.flowName'); // if there is the possibility to refresh the token, try to do it if (tokenIssuedOn && tokenExpirationSeconds && refreshToken && flowName) { if (!this.isTokenValid(tokenIssuedOn, tokenExpirationSeconds)) { userToken = await this.refreshLogin(refreshToken, flowName); } } // otherwise simply return the token return userToken; } isTokenValid(tokenIssuedOn, tokenExpirationSeconds) { const tokenExpirationMilliSeconds = tokenExpirationSeconds * 1000; // 15 minutes in milliseconds of margin const marginExpiration = 15 * 60 * 1000; const tokenValid = new Date() < new Date(new Date(tokenIssuedOn).getTime() + tokenExpirationMilliSeconds - marginExpiration); return tokenValid; } async login(email, password) { const { req } = await this.e.client.make('POST', '/login'); req.send({ email, password, source: 'cli' }); try { const res = await this.e.client.do(req); if (!(0, guards_1.isLoginResponse)(res)) { const data = res.data; if (hasTokenAttribute(data)) { data.token = '*****'; } throw new errors_1.FatalException('API request was successful, but the response format was unrecognized.\n' + (0, http_1.formatResponseError)(req, res.meta.status, data)); } const { token, user } = res.data; if (this.e.config.get('user.id') !== user.id) { // User changed await this.logout(); } this.e.config.set('user.id', user.id); this.e.config.set('user.email', email); this.e.config.set('tokens.user', token); } catch (e) { if ((0, guards_1.isSuperAgentError)(e) && (e.response.status === 401 || e.response.status === 403)) { throw new errors_1.SessionException('Incorrect email or password.'); } throw e; } } async ssoLogin(email) { await this.webLogin(); } async tokenLogin(token) { const { UserClient } = await Promise.resolve().then(() => __importStar(require('./user'))); const userClient = new UserClient(token, this.e); try { const user = await userClient.loadSelf(); const user_id = user.id; if (this.e.config.get('user.id') !== user_id) { // User changed await this.logout(); } this.e.config.set('user.id', user_id); this.e.config.set('user.email', user.email); this.e.config.set('tokens.user', token); } catch (e) { if ((0, guards_1.isSuperAgentError)(e) && (e.response.status === 401 || e.response.status === 403)) { throw new errors_1.SessionException('Invalid auth token.'); } throw e; } } async wizardLogin() { const { OpenIDFlow } = await Promise.resolve().then(() => __importStar(require('./oauth/openid'))); const wizardUrl = new URL(this.e.config.getOpenIDOAuthConfig().authorizationUrl); wizardUrl.pathname = 'start'; const flow = new OpenIDFlow({}, this.e, wizardUrl.href); const token = await flow.run(); await this.tokenLogin(token.access_token); this.e.config.set('tokens.refresh', token.refresh_token); this.e.config.set('tokens.expiresInSeconds', token.expires_in); this.e.config.set('tokens.issuedOn', (new Date()).toJSON()); this.e.config.set('tokens.flowName', flow.flowName); return token.state; } async webLogin() { const { OpenIDFlow } = await Promise.resolve().then(() => __importStar(require('./oauth/openid'))); const flow = new OpenIDFlow({}, this.e); const token = await flow.run(); await this.tokenLogin(token.access_token); this.e.config.set('tokens.refresh', token.refresh_token); this.e.config.set('tokens.expiresInSeconds', token.expires_in); this.e.config.set('tokens.issuedOn', (new Date()).toJSON()); this.e.config.set('tokens.flowName', flow.flowName); } async refreshLogin(refreshToken, flowName) { let oauthflow; // having a generic way to access the right refresh token flow switch (flowName) { case 'open_id': const { OpenIDFlow } = await Promise.resolve().then(() => __importStar(require('./oauth/openid'))); oauthflow = new OpenIDFlow({}, this.e); break; default: oauthflow = undefined; } if (!oauthflow) { throw new errors_1.FatalException('Token cannot be refreshed'); } const token = await oauthflow.exchangeRefreshToken(refreshToken); await this.tokenLogin(token.access_token); this.e.config.set('tokens.expiresInSeconds', token.expires_in); this.e.config.set('tokens.issuedOn', (new Date()).toJSON()); return token.access_token; } } exports.ProSession = ProSession; async function promptToLogin(env) { env.log.nl(); env.log.msg(`Log in to your Ionic account!\n` + `If you don't have one yet, create yours by running: ${(0, color_1.input)(`ionic signup`)}\n`); const login = await env.prompt({ type: 'confirm', name: 'login', message: 'Open the browser to log in to your Ionic account?', default: true, }); if (login) { await env.session.webLogin(); } } exports.promptToLogin = promptToLogin; async function promptToSignup(env) { env.log.nl(); env.log.msg(`Join the Ionic Community! 💙\n` + `Connect with millions of developers on the Ionic Forum and get access to live events, news updates, and more.\n\n`); const create = await env.prompt({ type: 'confirm', name: 'create', message: 'Create free Ionic account?', default: false, }); if (create) { const dashUrl = env.config.getDashUrl(); await (0, open_1.openUrl)(`${dashUrl}/signup?source=cli`); } } exports.promptToSignup = promptToSignup; function hasTokenAttribute(r) { return r && typeof r === 'object' && typeof r.token === 'string'; }