UNPKG

8 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.promptToSignup = exports.promptToLogin = exports.ProSession = exports.BaseSession = void 0;
4const guards_1 = require("../guards");
5const color_1 = require("./color");
6const errors_1 = require("./errors");
7const http_1 = require("./http");
8const open_1 = require("./open");
9class BaseSession {
10 constructor(e) {
11 this.e = e;
12 }
13 async logout() {
14 const activeToken = this.e.config.get('tokens.user');
15 if (activeToken) {
16 // invalidate the token
17 const { req } = await this.e.client.make('POST', '/logout');
18 req.set('Authorization', `Bearer ${activeToken}`)
19 .send({});
20 try {
21 await this.e.client.do(req);
22 }
23 catch (e) { }
24 }
25 this.e.config.unset('org.id');
26 this.e.config.unset('user.id');
27 this.e.config.unset('user.email');
28 this.e.config.unset('tokens.user');
29 this.e.config.unset('tokens.refresh');
30 this.e.config.unset('tokens.expiresInSeconds');
31 this.e.config.unset('tokens.issuedOn');
32 this.e.config.unset('tokens.flowName');
33 this.e.config.set('git.setup', false);
34 }
35 isLoggedIn() {
36 return typeof this.e.config.get('tokens.user') === 'string';
37 }
38 getUser() {
39 const userId = this.e.config.get('user.id');
40 if (!userId) {
41 throw new errors_1.SessionException(`Oops, sorry! You'll need to log in:\n ${color_1.input('ionic login')}\n\n` +
42 `You can create a new account by signing up:\n\n ${color_1.input('ionic signup')}\n`);
43 }
44 return { id: userId };
45 }
46}
47exports.BaseSession = BaseSession;
48class ProSession extends BaseSession {
49 async getUserToken() {
50 let userToken = this.e.config.get('tokens.user');
51 if (!userToken) {
52 throw new errors_1.SessionException(`Oops, sorry! You'll need to log in:\n ${color_1.input('ionic login')}\n\n` +
53 `You can create a new account by signing up:\n\n ${color_1.input('ionic signup')}\n`);
54 }
55 const tokenIssuedOn = this.e.config.get('tokens.issuedOn');
56 const tokenExpirationSeconds = this.e.config.get('tokens.expiresInSeconds');
57 const refreshToken = this.e.config.get('tokens.refresh');
58 const flowName = this.e.config.get('tokens.flowName');
59 // if there is the possibility to refresh the token, try to do it
60 if (tokenIssuedOn && tokenExpirationSeconds && refreshToken && flowName) {
61 if (!this.isTokenValid(tokenIssuedOn, tokenExpirationSeconds)) {
62 userToken = await this.refreshLogin(refreshToken, flowName);
63 }
64 }
65 // otherwise simply return the token
66 return userToken;
67 }
68 isTokenValid(tokenIssuedOn, tokenExpirationSeconds) {
69 const tokenExpirationMilliSeconds = tokenExpirationSeconds * 1000;
70 // 15 minutes in milliseconds of margin
71 const marginExpiration = 15 * 60 * 1000;
72 const tokenValid = new Date() < new Date(new Date(tokenIssuedOn).getTime() + tokenExpirationMilliSeconds - marginExpiration);
73 return tokenValid;
74 }
75 async login(email, password) {
76 const { req } = await this.e.client.make('POST', '/login');
77 req.send({ email, password, source: 'cli' });
78 try {
79 const res = await this.e.client.do(req);
80 if (!guards_1.isLoginResponse(res)) {
81 const data = res.data;
82 if (hasTokenAttribute(data)) {
83 data.token = '*****';
84 }
85 throw new errors_1.FatalException('API request was successful, but the response format was unrecognized.\n' +
86 http_1.formatResponseError(req, res.meta.status, data));
87 }
88 const { token, user } = res.data;
89 if (this.e.config.get('user.id') !== user.id) { // User changed
90 await this.logout();
91 }
92 this.e.config.set('user.id', user.id);
93 this.e.config.set('user.email', email);
94 this.e.config.set('tokens.user', token);
95 }
96 catch (e) {
97 if (guards_1.isSuperAgentError(e) && (e.response.status === 401 || e.response.status === 403)) {
98 throw new errors_1.SessionException('Incorrect email or password.');
99 }
100 throw e;
101 }
102 }
103 async ssoLogin(email) {
104 await this.webLogin();
105 }
106 async tokenLogin(token) {
107 const { UserClient } = await Promise.resolve().then(() => require('./user'));
108 const userClient = new UserClient(token, this.e);
109 try {
110 const user = await userClient.loadSelf();
111 const user_id = user.id;
112 if (this.e.config.get('user.id') !== user_id) { // User changed
113 await this.logout();
114 }
115 this.e.config.set('user.id', user_id);
116 this.e.config.set('user.email', user.email);
117 this.e.config.set('tokens.user', token);
118 }
119 catch (e) {
120 if (guards_1.isSuperAgentError(e) && (e.response.status === 401 || e.response.status === 403)) {
121 throw new errors_1.SessionException('Invalid auth token.');
122 }
123 throw e;
124 }
125 }
126 async webLogin() {
127 const { OpenIDFlow } = await Promise.resolve().then(() => require('./oauth/openid'));
128 const flow = new OpenIDFlow({}, this.e);
129 const token = await flow.run();
130 await this.tokenLogin(token.access_token);
131 this.e.config.set('tokens.refresh', token.refresh_token);
132 this.e.config.set('tokens.expiresInSeconds', token.expires_in);
133 this.e.config.set('tokens.issuedOn', (new Date()).toJSON());
134 this.e.config.set('tokens.flowName', flow.flowName);
135 }
136 async refreshLogin(refreshToken, flowName) {
137 let oauthflow;
138 // having a generic way to access the right refresh token flow
139 switch (flowName) {
140 case 'open_id':
141 const { OpenIDFlow } = await Promise.resolve().then(() => require('./oauth/openid'));
142 oauthflow = new OpenIDFlow({}, this.e);
143 break;
144 default:
145 oauthflow = undefined;
146 }
147 if (!oauthflow) {
148 throw new errors_1.FatalException('Token cannot be refreshed');
149 }
150 const token = await oauthflow.exchangeRefreshToken(refreshToken);
151 await this.tokenLogin(token.access_token);
152 this.e.config.set('tokens.expiresInSeconds', token.expires_in);
153 this.e.config.set('tokens.issuedOn', (new Date()).toJSON());
154 return token.access_token;
155 }
156}
157exports.ProSession = ProSession;
158async function promptToLogin(env) {
159 env.log.nl();
160 env.log.msg(`Log in to your Ionic account!\n` +
161 `If you don't have one yet, create yours by running: ${color_1.input(`ionic signup`)}\n`);
162 const login = await env.prompt({
163 type: 'confirm',
164 name: 'login',
165 message: 'Open the browser to log in to your Ionic account?',
166 default: true,
167 });
168 if (login) {
169 await env.session.webLogin();
170 }
171}
172exports.promptToLogin = promptToLogin;
173async function promptToSignup(env) {
174 env.log.nl();
175 env.log.msg(`Join the Ionic Community! 💙\n` +
176 `Connect with millions of developers on the Ionic Forum and get access to live events, news updates, and more.\n\n`);
177 const create = await env.prompt({
178 type: 'confirm',
179 name: 'create',
180 message: 'Create free Ionic account?',
181 default: false,
182 });
183 if (create) {
184 const dashUrl = env.config.getDashUrl();
185 await open_1.openUrl(`${dashUrl}/signup?source=cli`);
186 }
187}
188exports.promptToSignup = promptToSignup;
189function hasTokenAttribute(r) {
190 return r && typeof r === 'object' && typeof r.token === 'string';
191}