@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.
- package/lib/auth-handler.d.ts +12 -14
- package/lib/auth-handler.js +237 -342
- package/lib/config-handler.d.ts +2 -0
- package/lib/config-handler.js +20 -0
- package/package.json +2 -2
package/lib/auth-handler.d.ts
CHANGED
|
@@ -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
|
-
|
|
32
|
-
oauth(): Promise<
|
|
33
|
-
createHTTPServer(): Promise<
|
|
34
|
-
openOAuthURL(): Promise<
|
|
35
|
-
getAccessToken(code: string): Promise<
|
|
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
|
-
|
|
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;
|
package/lib/auth-handler.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
87
|
+
try {
|
|
90
88
|
this.initLog();
|
|
91
|
-
this.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
210
|
-
const
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
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
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
|
|
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
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
|
|
387
|
-
cli_ux_1.default.error('
|
|
388
|
-
|
|
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
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/lib/config-handler.d.ts
CHANGED
|
@@ -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;
|
package/lib/config-handler.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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",
|