1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.promptToSignup = exports.promptToLogin = exports.ProSession = exports.BaseSession = void 0;
|
4 | const guards_1 = require("../guards");
|
5 | const color_1 = require("./color");
|
6 | const errors_1 = require("./errors");
|
7 | const http_1 = require("./http");
|
8 | const open_1 = require("./open");
|
9 | class 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 |
|
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 | }
|
47 | exports.BaseSession = BaseSession;
|
48 | class 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 |
|
60 | if (tokenIssuedOn && tokenExpirationSeconds && refreshToken && flowName) {
|
61 | if (!this.isTokenValid(tokenIssuedOn, tokenExpirationSeconds)) {
|
62 | userToken = await this.refreshLogin(refreshToken, flowName);
|
63 | }
|
64 | }
|
65 |
|
66 | return userToken;
|
67 | }
|
68 | isTokenValid(tokenIssuedOn, tokenExpirationSeconds) {
|
69 | const tokenExpirationMilliSeconds = tokenExpirationSeconds * 1000;
|
70 |
|
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) {
|
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) {
|
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 |
|
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 | }
|
157 | exports.ProSession = ProSession;
|
158 | async 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 | }
|
172 | exports.promptToLogin = promptToLogin;
|
173 | async 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 | }
|
188 | exports.promptToSignup = promptToSignup;
|
189 | function hasTokenAttribute(r) {
|
190 | return r && typeof r === 'object' && typeof r.token === 'string';
|
191 | }
|