@contentstack/cli-utilities 1.10.0 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,9 +3,7 @@
3
3
  * Auth handler
4
4
  */
5
5
  declare class AuthHandler {
6
- private developerHubUrl;
7
6
  private _host;
8
- private codeVerifier;
9
7
  private OAuthBaseURL;
10
8
  private OAuthAppId;
11
9
  private OAuthClientId;
@@ -24,32 +22,32 @@ declare class AuthHandler {
24
22
  private authorisationTypeAUTHValue;
25
23
  private allAuthConfigItems;
26
24
  private logger;
25
+ private oauthHandler;
26
+ private managementAPIClient;
27
+ private isRefreshingToken;
27
28
  set host(contentStackHost: any);
28
29
  constructor();
29
30
  initLog(): void;
30
31
  setOAuthBaseURL(): Promise<void>;
31
- setDeveloperHubURL(): void;
32
- oauth(): Promise<object>;
33
- createHTTPServer(): Promise<object>;
34
- openOAuthURL(): Promise<object>;
35
- getAccessToken(code: string): Promise<object>;
32
+ initSDK(): Promise<void>;
33
+ oauth(): Promise<void>;
34
+ createHTTPServer(): Promise<void>;
35
+ openOAuthURL(): Promise<void>;
36
+ getAccessToken(code: string): Promise<void>;
36
37
  setConfigData(type: string, userData?: any): Promise<object>;
37
- unsetConfigData(type?: string): Promise<void>;
38
+ setOAuthConfigData(userData: any, type: string): void;
39
+ setBasicAuthConfigData(userData: any): void;
40
+ unsetConfigData(type?: string): void;
38
41
  refreshToken(): Promise<object>;
39
42
  getUserDetails(data: any): Promise<object>;
40
43
  oauthLogout(): Promise<object>;
41
- /**
42
- * Fetches all authorizations for the Oauth App, returns authorizationUid for current user.
43
- * @returns authorizationUid for the current user
44
- */
45
- getOauthAppAuthorization(): Promise<string | undefined>;
46
- revokeOauthAppAuthorization(authorizationId: any): Promise<object>;
47
44
  isAuthenticated(): boolean;
48
45
  getAuthorisationType(): Promise<any>;
49
46
  isAuthorisationTypeBasic(): Promise<boolean>;
50
47
  isAuthorisationTypeOAuth(): Promise<boolean>;
51
48
  checkExpiryAndRefresh: (force?: boolean) => Promise<void | object>;
52
49
  compareOAuthExpiry(force?: boolean): Promise<void | object>;
50
+ restoreOAuthConfig(): void;
53
51
  }
54
52
  declare const _default: AuthHandler;
55
53
  export default _default;
@@ -2,16 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const cli_ux_1 = tslib_1.__importDefault(require("./cli-ux"));
5
- const http_client_1 = tslib_1.__importDefault(require("./http-client"));
6
5
  const config_handler_1 = tslib_1.__importDefault(require("./config-handler"));
7
6
  const dotenv_1 = tslib_1.__importDefault(require("dotenv"));
8
- const ContentstackManagementSDK = tslib_1.__importStar(require("@contentstack/management"));
9
- const message_handler_1 = tslib_1.__importDefault(require("./message-handler"));
10
- const http = require('http');
11
- const url = require('url');
12
7
  const open_1 = tslib_1.__importDefault(require("open"));
8
+ const http_1 = tslib_1.__importDefault(require("http"));
9
+ const url_1 = tslib_1.__importDefault(require("url"));
13
10
  const logger_1 = require("./logger");
14
- const crypto = require('crypto');
11
+ const contentstack_management_sdk_1 = tslib_1.__importDefault(require("./contentstack-management-sdk"));
12
+ const helpers_1 = require("./helpers");
15
13
  dotenv_1.default.config();
16
14
  /**
17
15
  * @class
@@ -22,12 +20,12 @@ class AuthHandler {
22
20
  this._host = contentStackHost;
23
21
  }
24
22
  constructor() {
23
+ this.isRefreshingToken = false; // Flag to track if a refresh operation is in progress
25
24
  this.checkExpiryAndRefresh = (force = false) => this.compareOAuthExpiry(force);
26
- this.codeVerifier = crypto.randomBytes(32).toString('hex');
27
25
  this.OAuthAppId = process.env.OAUTH_APP_ID || '6400aa06db64de001a31c8a9';
28
26
  this.OAuthClientId = process.env.OAUTH_CLIENT_ID || 'Ie0FEfTzlfAHL4xM';
29
27
  this.OAuthRedirectURL = process.env.OAUTH_APP_REDIRECT_URL || 'http://localhost:8184';
30
- this.OAuthScope = '';
28
+ this.OAuthScope = [];
31
29
  this.OAuthResponseType = 'code';
32
30
  this.authTokenKeyName = 'authtoken';
33
31
  this.authEmailKeyName = 'email';
@@ -69,16 +67,16 @@ class AuthHandler {
69
67
  throw new Error('Invalid ui-host URL while authenticating. Please set your region correctly using the command - csdx config:set:region');
70
68
  }
71
69
  }
72
- setDeveloperHubURL() {
73
- if (this.developerHubUrl) {
74
- return; // Return if already set
75
- }
76
- if (config_handler_1.default.get('region')['developerHubUrl']) {
77
- this.developerHubUrl = config_handler_1.default.get('region')['developerHubUrl'] || '';
78
- }
79
- else {
80
- throw new Error('Invalid developerHubUrl URL while authenticating. Please set your region correctly using the command - csdx config:set:region');
81
- }
70
+ async initSDK() {
71
+ this.managementAPIClient = await (0, contentstack_management_sdk_1.default)({ host: this._host });
72
+ this.oauthHandler = this.managementAPIClient.oauth({
73
+ appId: this.OAuthAppId,
74
+ clientId: this.OAuthClientId,
75
+ redirectUri: this.OAuthRedirectURL,
76
+ scope: this.OAuthScope,
77
+ responseType: this.OAuthResponseType,
78
+ });
79
+ this.restoreOAuthConfig();
82
80
  }
83
81
  /*
84
82
  *
@@ -86,355 +84,216 @@ class AuthHandler {
86
84
  * @returns {Promise} Promise object returns {} on success
87
85
  */
88
86
  async oauth() {
89
- return new Promise((resolve, reject) => {
87
+ try {
90
88
  this.initLog();
91
- this.createHTTPServer()
92
- .then(() => {
93
- this.openOAuthURL()
94
- .then(() => {
95
- //set timeout for authorization
96
- resolve({});
97
- })
98
- .catch((error) => {
99
- this.logger.error('OAuth login failed', error.message);
100
- reject(error);
101
- });
102
- })
103
- .catch((error) => {
104
- this.logger.error('OAuth login failed', error.message);
105
- reject(error);
106
- });
107
- });
89
+ await this.initSDK();
90
+ await this.createHTTPServer();
91
+ await this.openOAuthURL();
92
+ }
93
+ catch (error) {
94
+ this.logger.error('OAuth login failed', error.message);
95
+ throw error;
96
+ }
108
97
  }
109
98
  async createHTTPServer() {
110
- return new Promise((resolve, reject) => {
111
- try {
112
- const server = http.createServer((req, res) => {
113
- const reqURL = req.url;
114
- const queryObject = url.parse(reqURL, true).query;
115
- if (queryObject.code) {
116
- cli_ux_1.default.print('Auth code successfully fetched.');
117
- this.getAccessToken(queryObject.code)
118
- .then(async () => {
119
- await this.setOAuthBaseURL();
120
- cli_ux_1.default.print('Access token fetched using auth code successfully.');
121
- cli_ux_1.default.print(`You can review the access permissions on the page - ${this.OAuthBaseURL}/#!/marketplace/authorized-apps`);
122
- res.writeHead(200, { 'Content-Type': 'text/html' });
123
- res.end(`<style>
124
- body {
125
- font-family: Arial, sans-serif;
126
- text-align: center;
127
- margin-top: 100px;
99
+ try {
100
+ const server = http_1.default.createServer(async (req, res) => {
101
+ const queryObject = url_1.default.parse(req.url, true).query;
102
+ if (!queryObject.code) {
103
+ cli_ux_1.default.error('Error occoured while login with OAuth, please login with command - csdx auth:login --oauth');
104
+ return sendErrorResponse(res);
128
105
  }
129
-
130
- p {
131
- color: #475161;
132
- margin-bottom: 20px;
106
+ cli_ux_1.default.print('Auth code successfully fetched.');
107
+ try {
108
+ await this.getAccessToken(queryObject.code);
109
+ await this.setOAuthBaseURL();
110
+ cli_ux_1.default.print('Access token fetched using auth code successfully.');
111
+ cli_ux_1.default.print(`You can review the access permissions on the page - ${this.OAuthBaseURL}/#!/marketplace/authorized-apps`);
112
+ sendSuccessResponse(res);
113
+ stopServer();
133
114
  }
134
- p button {
135
- background-color: #6c5ce7;
136
- color: #fff;
137
- border: 1px solid transparent;
138
- border-radius: 4px;
139
- font-weight: 600;
140
- line-height: 100%;
141
- text-align: center;
142
- min-height: 2rem;
143
- padding: 0.3125rem 1rem;
115
+ catch (error) {
116
+ cli_ux_1.default.error('Error occoured while login with OAuth, please login with command - csdx auth:login --oauth');
117
+ cli_ux_1.default.error(error);
118
+ sendErrorResponse(res);
119
+ stopServer();
144
120
  }
145
- </style>
146
- <h1 style="color: #6c5ce7">Successfully authorized!</h1>
147
- <p style="color: #475161; font-size: 16px; font-weight: 600">You can close this window now.</p>
148
- <p>
149
- You can review the access permissions on the
150
- <a
151
- style="color: #6c5ce7; text-decoration: none"
152
- href="${this.OAuthBaseURL}/#!/marketplace/authorized-apps"
153
- target="_blank"
154
- >Authorized Apps page</a
155
- >.
156
- </p>`);
157
- stopServer();
158
- })
159
- .catch((error) => {
160
- cli_ux_1.default.error('Error occoured while login with OAuth, please login with command - csdx auth:login --oauth');
161
- cli_ux_1.default.error(error);
162
- res.writeHead(200, { 'Content-Type': 'text/html' });
163
- res.end(`<h1>Sorry!</h1><h2>Something went wrong, please login with command - csdx auth:login --oauth(</h2>`);
164
- stopServer();
165
- });
166
- }
167
- else {
168
- cli_ux_1.default.error('Error occoured while login with OAuth, please login with command - csdx auth:login --oauth');
169
- res.writeHead(200, { 'Content-Type': 'text/html' });
170
- res.end(`<h1>Sorry!</h1><h2>Something went wrong, please login with command - csdx auth:login --oauth(</h2>`);
171
- stopServer();
172
- }
173
- });
174
- const stopServer = () => {
175
- server.close();
176
- process.exit();
177
- };
178
- server.listen(8184, () => {
179
- cli_ux_1.default.print('Waiting for the authorization server to respond...');
180
- resolve({ true: true });
181
- });
182
- }
183
- catch (error) {
184
- cli_ux_1.default.error(error);
185
- reject(error);
186
- }
187
- });
121
+ });
122
+ const sendSuccessResponse = (res) => {
123
+ const successHtml = `
124
+ <style>
125
+ body { font-family: Arial, sans-serif; text-align: center; margin-top: 100px; }
126
+ p { color: #475161; margin-bottom: 20px; }
127
+ p button { background-color: #6c5ce7; color: #fff; border: 1px solid transparent; border-radius: 4px; font-weight: 600; line-height: 100%; text-align: center; min-height: 2rem; padding: 0.3125rem 1rem; }
128
+ </style>
129
+ <h1 style="color: #6c5ce7">Successfully authorized!</h1>
130
+ <p style="color: #475161; font-size: 16px; font-weight: 600">You can close this window now.</p>
131
+ <p>
132
+ You can review the access permissions on the
133
+ <a style="color: #6c5ce7; text-decoration: none" href="${this.OAuthBaseURL}/#!/marketplace/authorized-apps" target="_blank">Authorized Apps page</a>.
134
+ </p>`;
135
+ res.writeHead(200, { 'Content-Type': 'text/html' });
136
+ res.end(successHtml);
137
+ };
138
+ const sendErrorResponse = (res) => {
139
+ const errorHtml = `
140
+ <h1>Sorry!</h1><h2>Something went wrong, please login with command.</h2>`;
141
+ res.writeHead(200, { 'Content-Type': 'text/html' });
142
+ res.end(errorHtml);
143
+ };
144
+ const stopServer = () => {
145
+ server.close();
146
+ process.exit();
147
+ };
148
+ server.listen(8184, () => {
149
+ cli_ux_1.default.print('Waiting for the authorization server to respond...');
150
+ return { true: true };
151
+ });
152
+ // Listen for errors
153
+ server.on('error', (err) => {
154
+ cli_ux_1.default.error('Server encountered an error:', (0, helpers_1.formatError)(err));
155
+ });
156
+ }
157
+ catch (error) {
158
+ cli_ux_1.default.error(error);
159
+ throw error;
160
+ }
188
161
  }
189
162
  async openOAuthURL() {
190
- return new Promise(async (resolve, reject) => {
191
- try {
192
- const digest = crypto.createHash('sha256').update(this.codeVerifier).digest();
193
- const codeChallenge = digest.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
194
- await this.setOAuthBaseURL();
195
- let url = `${this.OAuthBaseURL}/#!/apps/${this.OAuthAppId}/authorize?response_type=${this.OAuthResponseType}&client_id=${this.OAuthClientId}&redirect_uri=${this.OAuthRedirectURL}&code_challenge=${codeChallenge}&code_challenge_method=S256`;
196
- if (this.OAuthScope) {
197
- url += `&scope=${encodeURIComponent(this.OAuthScope)}`;
198
- }
199
- cli_ux_1.default.print('This will automatically start the browser and open the below URL, if it does not, you can copy and paste the below URL in the browser without terminating this command.', { color: 'yellow' });
200
- cli_ux_1.default.print(url, { color: 'green' });
201
- resolve((0, open_1.default)(url));
202
- }
203
- catch (error) {
204
- reject(error);
205
- }
206
- });
163
+ try {
164
+ const url = await this.oauthHandler.authorize();
165
+ cli_ux_1.default.print('This will automatically start the browser and open the below URL, if it does not, you can copy and paste the below URL in the browser without terminating this command.', { color: 'yellow' });
166
+ cli_ux_1.default.print(url, { color: 'green' });
167
+ await (0, open_1.default)(url);
168
+ }
169
+ catch (error) {
170
+ throw error;
171
+ }
207
172
  }
208
173
  async getAccessToken(code) {
209
- return new Promise((resolve, reject) => {
210
- const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
211
- const payload = {
212
- grant_type: 'authorization_code',
213
- client_id: this.OAuthClientId,
214
- code_verifier: this.codeVerifier,
215
- redirect_uri: this.OAuthRedirectURL,
216
- code: code,
217
- };
218
- this.setDeveloperHubURL();
219
- const httpClient = new http_client_1.default().headers(headers).asFormParams();
220
- httpClient
221
- .post(`${this.developerHubUrl}/apps/token`, payload)
222
- .then(({ data }) => {
223
- return this.getUserDetails(data);
224
- })
225
- .then((data) => {
226
- if (data['access_token'] && data['refresh_token']) {
227
- return this.setConfigData('oauth', data);
228
- }
229
- else {
230
- reject('Invalid request');
231
- }
232
- })
233
- .then(resolve)
234
- .catch((error) => {
235
- cli_ux_1.default.error('An error occoured while fetching the access token, run the command - csdx auth:login --oauth');
236
- cli_ux_1.default.error(error);
237
- reject(error);
238
- });
239
- });
174
+ try {
175
+ const data = await this.oauthHandler.exchangeCodeForToken(code);
176
+ const userData = await this.getUserDetails(data);
177
+ if (userData['access_token'] && userData['refresh_token']) {
178
+ await this.setConfigData('oauth', userData);
179
+ }
180
+ else {
181
+ throw new Error('Invalid request');
182
+ }
183
+ }
184
+ catch (error) {
185
+ cli_ux_1.default.error('An error occurred while fetching the access token, run the command - csdx auth:login --oauth');
186
+ cli_ux_1.default.error(error);
187
+ throw error;
188
+ }
240
189
  }
241
190
  async setConfigData(type, userData = {}) {
242
- return new Promise(async (resolve, reject) => {
243
- //Delete the old configstore auth data
244
- this.unsetConfigData(type)
245
- .then(() => {
246
- switch (type) {
247
- case 'oauth':
248
- if (userData.access_token && userData.refresh_token) {
249
- //Set the new OAuth tokens info
250
- config_handler_1.default.set(this.oauthAccessTokenKeyName, userData.access_token);
251
- config_handler_1.default.set(this.oauthRefreshTokenKeyName, userData.refresh_token);
252
- config_handler_1.default.set(this.authEmailKeyName, userData.email);
253
- config_handler_1.default.set(this.oauthDateTimeKeyName, new Date());
254
- config_handler_1.default.set(this.oauthUserUidKeyName, userData.user_uid);
255
- config_handler_1.default.set(this.oauthOrgUidKeyName, userData.organization_uid);
256
- config_handler_1.default.set(this.authorisationTypeKeyName, this.authorisationTypeOAUTHValue);
257
- resolve(userData);
258
- }
259
- else {
260
- reject('Invalid request');
261
- }
262
- break;
263
- case 'refreshToken':
264
- if (userData.access_token && userData.refresh_token) {
265
- //Set the new OAuth tokens info
266
- config_handler_1.default.set(this.oauthAccessTokenKeyName, userData.access_token);
267
- config_handler_1.default.set(this.oauthRefreshTokenKeyName, userData.refresh_token);
268
- config_handler_1.default.set(this.oauthDateTimeKeyName, new Date());
269
- resolve(userData);
270
- }
271
- else {
272
- reject('Invalid request');
273
- }
274
- break;
275
- case 'basicAuth':
276
- if (userData.authtoken && userData.email) {
277
- //Set the new auth tokens info
278
- config_handler_1.default.set(this.authTokenKeyName, userData.authtoken);
279
- config_handler_1.default.set(this.authEmailKeyName, userData.email);
280
- config_handler_1.default.set(this.authorisationTypeKeyName, this.authorisationTypeAUTHValue);
281
- resolve(userData);
282
- }
283
- else {
284
- reject('Invalid request');
285
- }
286
- break;
287
- case 'logout':
288
- resolve(userData);
289
- break;
290
- default:
291
- reject('Invalid request');
292
- break;
293
- }
294
- })
295
- .catch((error) => {
296
- reject(error);
297
- });
298
- });
299
- }
300
- async unsetConfigData(type = 'default') {
301
- return new Promise(async (resolve, reject) => {
302
- //Delete the old auth tokens info
303
- let removeItems = this.allAuthConfigItems.default;
304
- if (type === 'refreshToken') {
305
- removeItems = this.allAuthConfigItems.refreshToken;
191
+ try {
192
+ this.unsetConfigData(type);
193
+ switch (type) {
194
+ case 'oauth':
195
+ case 'refreshToken':
196
+ if (userData.access_token && userData.refresh_token) {
197
+ this.setOAuthConfigData(userData, type);
198
+ return userData;
199
+ }
200
+ else {
201
+ throw new Error('Invalid request');
202
+ }
203
+ case 'basicAuth':
204
+ if (userData.authtoken && userData.email) {
205
+ this.setBasicAuthConfigData(userData);
206
+ return userData;
207
+ }
208
+ else {
209
+ throw new Error('Invalid request');
210
+ }
211
+ case 'logout':
212
+ return userData;
213
+ default:
214
+ throw new Error('Invalid request');
306
215
  }
307
- removeItems.forEach((element) => {
308
- config_handler_1.default.delete(element);
309
- });
310
- resolve();
311
- });
216
+ }
217
+ catch (error) {
218
+ throw error;
219
+ }
220
+ }
221
+ setOAuthConfigData(userData, type) {
222
+ config_handler_1.default.set(this.oauthAccessTokenKeyName, userData.access_token);
223
+ config_handler_1.default.set(this.oauthRefreshTokenKeyName, userData.refresh_token);
224
+ config_handler_1.default.set(this.oauthDateTimeKeyName, new Date());
225
+ if (type === 'oauth') {
226
+ config_handler_1.default.set(this.authEmailKeyName, userData.email);
227
+ config_handler_1.default.set(this.oauthUserUidKeyName, userData.user_uid);
228
+ config_handler_1.default.set(this.oauthOrgUidKeyName, userData.organization_uid);
229
+ config_handler_1.default.set(this.authorisationTypeKeyName, this.authorisationTypeOAUTHValue);
230
+ }
231
+ }
232
+ setBasicAuthConfigData(userData) {
233
+ config_handler_1.default.set(this.authTokenKeyName, userData.authtoken);
234
+ config_handler_1.default.set(this.authEmailKeyName, userData.email);
235
+ config_handler_1.default.set(this.authorisationTypeKeyName, this.authorisationTypeAUTHValue);
236
+ }
237
+ unsetConfigData(type = 'default') {
238
+ const removeItems = type === 'refreshToken' ? this.allAuthConfigItems.refreshToken : this.allAuthConfigItems.default;
239
+ removeItems.forEach((element) => config_handler_1.default.delete(element));
312
240
  }
313
241
  async refreshToken() {
314
- return new Promise((resolve, reject) => {
242
+ try {
243
+ if (!this.oauthHandler) {
244
+ await this.initSDK(); // Initialize oauthHandler if not already initialized
245
+ }
315
246
  const configOauthRefreshToken = config_handler_1.default.get(this.oauthRefreshTokenKeyName);
316
247
  const configAuthorisationType = config_handler_1.default.get(this.authorisationTypeKeyName);
317
- if (configAuthorisationType === this.authorisationTypeOAUTHValue && configOauthRefreshToken) {
318
- const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
319
- const payload = {
320
- grant_type: 'refresh_token',
321
- client_id: this.OAuthClientId,
322
- redirect_uri: this.OAuthRedirectURL,
323
- refresh_token: configOauthRefreshToken,
324
- };
325
- this.setDeveloperHubURL();
326
- const httpClient = new http_client_1.default().headers(headers).asFormParams();
327
- httpClient
328
- .post(`${this.developerHubUrl}/apps/token`, payload)
329
- .then(({ data }) => {
330
- if (data.error || (data.statusCode != 200 && data.message)) {
331
- let errorMessage = '';
332
- if (data.message) {
333
- if (data.message[0]) {
334
- errorMessage = data.message[0];
335
- }
336
- else {
337
- errorMessage = data.message;
338
- }
339
- }
340
- else {
341
- errorMessage = data.error;
342
- }
343
- reject(errorMessage);
344
- }
345
- else {
346
- if (data['access_token'] && data['refresh_token']) {
347
- return this.setConfigData('refreshToken', data);
348
- }
349
- else {
350
- reject('Invalid request');
351
- }
352
- }
353
- })
354
- .then(resolve)
355
- .catch((error) => {
356
- cli_ux_1.default.error('An error occoured while refreshing the token');
357
- cli_ux_1.default.error(error);
358
- reject(error);
359
- });
248
+ if (configAuthorisationType !== this.authorisationTypeOAUTHValue || !configOauthRefreshToken) {
249
+ cli_ux_1.default.error('Invalid refresh token, run the command- csdx auth:login --oauth');
250
+ throw new Error('Invalid refresh token');
251
+ }
252
+ const data = await this.oauthHandler.refreshAccessToken(configOauthRefreshToken);
253
+ if (data['access_token'] && data['refresh_token']) {
254
+ await this.setConfigData('refreshToken', data);
255
+ return data; // Returning the data from the refresh token operation
360
256
  }
361
257
  else {
362
- cli_ux_1.default.error('Invalid/Empty refresh token, run the command- csdx auth:login --oauth');
363
- reject('Invalid/Empty refresh token');
258
+ throw new Error('Invalid request');
364
259
  }
365
- });
260
+ }
261
+ catch (error) {
262
+ cli_ux_1.default.error('An error occurred while refreshing the token');
263
+ cli_ux_1.default.error(error);
264
+ throw error; // Throwing the error to be handled by the caller
265
+ }
366
266
  }
367
267
  async getUserDetails(data) {
368
- return new Promise((resolve, reject) => {
369
- const accessToken = data.access_token;
370
- if (accessToken) {
371
- const param = {
372
- host: this._host,
373
- authorization: `Bearer ${accessToken}`,
374
- };
375
- const managementAPIClient = ContentstackManagementSDK.client(param);
376
- managementAPIClient
377
- .getUser()
378
- .then((user) => {
379
- data.email = (user === null || user === void 0 ? void 0 : user.email) || '';
380
- resolve(data);
381
- })
382
- .catch((error) => {
383
- reject(error);
384
- });
268
+ if (data.access_token) {
269
+ try {
270
+ const user = await this.managementAPIClient.getUser();
271
+ data.email = (user === null || user === void 0 ? void 0 : user.email) || '';
272
+ return data;
385
273
  }
386
- else {
387
- cli_ux_1.default.error('Invalid/Empty access token, run the command - csdx auth:login --oauth');
388
- reject('Invalid/Empty access token');
274
+ catch (error) {
275
+ cli_ux_1.default.error('Error fetching user details.');
276
+ cli_ux_1.default.error(error);
277
+ throw error;
389
278
  }
390
- });
279
+ }
280
+ else {
281
+ cli_ux_1.default.error('Invalid/Empty access token.');
282
+ throw new Error('Invalid/Empty access token');
283
+ }
391
284
  }
392
285
  async oauthLogout() {
393
- const authorization = (await this.getOauthAppAuthorization()) || '';
394
- const response = await this.revokeOauthAppAuthorization(authorization);
395
- return response || {};
396
- }
397
- /**
398
- * Fetches all authorizations for the Oauth App, returns authorizationUid for current user.
399
- * @returns authorizationUid for the current user
400
- */
401
- async getOauthAppAuthorization() {
402
- const headers = {
403
- authorization: `Bearer ${config_handler_1.default.get(this.oauthAccessTokenKeyName)}`,
404
- organization_uid: config_handler_1.default.get(this.oauthOrgUidKeyName),
405
- 'Content-type': 'application/json',
406
- };
407
- const httpClient = new http_client_1.default().headers(headers);
408
- this.setDeveloperHubURL();
409
- return httpClient.get(`${this.developerHubUrl}/manifests/${this.OAuthAppId}/authorizations`).then(({ data }) => {
410
- var _a, _b;
411
- if (((_a = data === null || data === void 0 ? void 0 : data.data) === null || _a === void 0 ? void 0 : _a.length) > 0) {
412
- const userUid = config_handler_1.default.get(this.oauthUserUidKeyName);
413
- const currentUserAuthorization = ((_b = data === null || data === void 0 ? void 0 : data.data) === null || _b === void 0 ? void 0 : _b.filter((element) => element.user.uid === userUid)) || [];
414
- if (currentUserAuthorization.length === 0) {
415
- throw new Error(message_handler_1.default.parse('CLI_AUTH_LOGOUT_NO_AUTHORIZATIONS_USER'));
416
- }
417
- return currentUserAuthorization[0].authorization_uid; // filter authorizations by current logged in user
418
- }
419
- else {
420
- throw new Error(message_handler_1.default.parse('CLI_AUTH_LOGOUT_NO_AUTHORIZATIONS'));
286
+ try {
287
+ if (!this.oauthHandler) {
288
+ await this.initSDK();
421
289
  }
422
- });
423
- }
424
- async revokeOauthAppAuthorization(authorizationId) {
425
- if (authorizationId.length > 1) {
426
- const headers = {
427
- authorization: `Bearer ${config_handler_1.default.get(this.oauthAccessTokenKeyName)}`,
428
- organization_uid: config_handler_1.default.get(this.oauthOrgUidKeyName),
429
- 'Content-type': 'application/json',
430
- };
431
- const httpClient = new http_client_1.default().headers(headers);
432
- this.setDeveloperHubURL();
433
- return httpClient
434
- .delete(`${this.developerHubUrl}/manifests/${this.OAuthAppId}/authorizations/${authorizationId}`)
435
- .then(({ data }) => {
436
- return data;
437
- });
290
+ const response = await this.oauthHandler.logout();
291
+ return response || {};
292
+ }
293
+ catch (error) {
294
+ cli_ux_1.default.error('An error occurred while logging out');
295
+ cli_ux_1.default.error(error);
296
+ throw error;
438
297
  }
439
298
  }
440
299
  isAuthenticated() {
@@ -451,6 +310,11 @@ class AuthHandler {
451
310
  return config_handler_1.default.get(this.authorisationTypeKeyName) === this.authorisationTypeOAUTHValue ? true : false;
452
311
  }
453
312
  async compareOAuthExpiry(force = false) {
313
+ // Avoid recursive refresh operations
314
+ if (this.isRefreshingToken) {
315
+ cli_ux_1.default.print('Refresh operation already in progress');
316
+ return Promise.resolve();
317
+ }
454
318
  const oauthDateTime = config_handler_1.default.get(this.oauthDateTimeKeyName);
455
319
  const authorisationType = config_handler_1.default.get(this.authorisationTypeKeyName);
456
320
  if (oauthDateTime && authorisationType === this.authorisationTypeOAUTHValue) {
@@ -468,13 +332,44 @@ class AuthHandler {
468
332
  }
469
333
  else {
470
334
  cli_ux_1.default.print('Token expired, refreshing the token');
471
- return this.refreshToken();
335
+ // Set the flag before refreshing the token
336
+ this.isRefreshingToken = true;
337
+ try {
338
+ await this.refreshToken();
339
+ }
340
+ catch (error) {
341
+ cli_ux_1.default.error('Error refreshing token');
342
+ throw error;
343
+ }
344
+ finally {
345
+ // Reset the flag after refresh operation is completed
346
+ this.isRefreshingToken = false;
347
+ }
348
+ return Promise.resolve();
472
349
  }
473
350
  }
474
351
  }
475
352
  else {
476
353
  cli_ux_1.default.print('No OAuth set');
477
- return this.unsetConfigData();
354
+ this.unsetConfigData();
355
+ }
356
+ }
357
+ restoreOAuthConfig() {
358
+ const oauthAccessToken = config_handler_1.default.get(this.oauthAccessTokenKeyName);
359
+ const oauthRefreshToken = config_handler_1.default.get(this.oauthRefreshTokenKeyName);
360
+ const oauthDateTime = config_handler_1.default.get(this.oauthDateTimeKeyName);
361
+ const oauthUserUid = config_handler_1.default.get(this.oauthUserUidKeyName);
362
+ const oauthOrgUid = config_handler_1.default.get(this.oauthOrgUidKeyName);
363
+ if (oauthAccessToken && !this.oauthHandler.getAccessToken())
364
+ this.oauthHandler.setAccessToken(oauthAccessToken);
365
+ if (oauthRefreshToken && !this.oauthHandler.getRefreshToken())
366
+ this.oauthHandler.setRefreshToken(oauthRefreshToken);
367
+ if (oauthUserUid && !this.oauthHandler.getUserUID())
368
+ this.oauthHandler.setUserUID(oauthUserUid);
369
+ if (oauthOrgUid && !this.oauthHandler.getOrganizationUID())
370
+ this.oauthHandler.setOrganizationUID(oauthOrgUid);
371
+ if (oauthDateTime && !this.oauthHandler.getTokenExpiryTime()) {
372
+ this.oauthHandler.setTokenExpiryTime(oauthDateTime);
478
373
  }
479
374
  }
480
375
  }
@@ -5,6 +5,8 @@ declare class Config {
5
5
  init(): Conf<Record<string, unknown>>;
6
6
  importOldConfig(): void;
7
7
  setOldConfigStoreData(data: any, _path?: string): void;
8
+ isConfigFileValid(configPath: string): boolean;
9
+ safeDeleteConfigIfInvalid(configFilePath: string): void;
8
10
  removeOldConfigStoreFile(): void;
9
11
  private getOldConfig;
10
12
  private fallbackInit;
@@ -56,6 +56,22 @@ class Config {
56
56
  }
57
57
  }
58
58
  }
59
+ isConfigFileValid(configPath) {
60
+ try {
61
+ const content = (0, fs_1.readFileSync)(configPath, 'utf8');
62
+ JSON.parse(content);
63
+ return true;
64
+ }
65
+ catch (e) {
66
+ return false;
67
+ }
68
+ }
69
+ safeDeleteConfigIfInvalid(configFilePath) {
70
+ if ((0, fs_1.existsSync)(configFilePath) && !this.isConfigFileValid(configFilePath)) {
71
+ console.warn(chalk_1.default.yellow(`Warning: Detected corrupted config at ${configFilePath}. Removing...`));
72
+ (0, fs_1.unlinkSync)(configFilePath);
73
+ }
74
+ }
59
75
  removeOldConfigStoreFile() {
60
76
  if ((0, fs_1.existsSync)(oldConfigPath)) {
61
77
  (0, fs_1.unlinkSync)(oldConfigPath); // NOTE remove old configstore file
@@ -98,6 +114,7 @@ class Config {
98
114
  try {
99
115
  // NOTE reading current code base encrypted file if exist
100
116
  const encryptionKey = this.getObfuscationKey();
117
+ this.safeDeleteConfigIfInvalid(oldConfigPath);
101
118
  this.config = new conf_1.default({ configName: CONFIG_NAME, encryptionKey, cwd });
102
119
  if ((_a = Object.keys(configData || {})) === null || _a === void 0 ? void 0 : _a.length) {
103
120
  this.config.set(configData); // NOTE set config data if passed any
@@ -119,6 +136,7 @@ class Config {
119
136
  };
120
137
  try {
121
138
  if (skip === false) {
139
+ this.safeDeleteConfigIfInvalid(oldConfigPath);
122
140
  const config = new conf_1.default({ configName: CONFIG_NAME });
123
141
  const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config);
124
142
  this.getEncryptedConfig(oldConfigData, true);
@@ -137,6 +155,7 @@ class Config {
137
155
  getDecryptedConfig(configData) {
138
156
  var _a;
139
157
  try {
158
+ this.safeDeleteConfigIfInvalid(oldConfigPath);
140
159
  this.config = new conf_1.default({ configName: CONFIG_NAME, cwd });
141
160
  if ((_a = Object.keys(configData || {})) === null || _a === void 0 ? void 0 : _a.length) {
142
161
  this.config.set(configData); // NOTE set config data if passed any
@@ -146,6 +165,7 @@ class Config {
146
165
  // console.trace(error.message)
147
166
  try {
148
167
  const encryptionKey = this.getObfuscationKey();
168
+ this.safeDeleteConfigIfInvalid(oldConfigPath);
149
169
  let config = new conf_1.default({ configName: CONFIG_NAME, encryptionKey, cwd });
150
170
  const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config);
151
171
  this.getDecryptedConfig(oldConfigData); // NOTE NOTE reinitialize the config with old data and new decrypted file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentstack/cli-utilities",
3
- "version": "1.10.0",
3
+ "version": "1.11.1",
4
4
  "description": "Utilities for contentstack projects",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  "author": "contentstack",
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@contentstack/management": "~1.18.4",
35
+ "@contentstack/management": "~1.20.2",
36
36
  "@contentstack/marketplace-sdk": "^1.2.5",
37
37
  "@oclif/core": "^4.2.7",
38
38
  "axios": "^1.8.2",