@salesforce/core 3.30.14 → 3.31.7
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/LICENSE.txt +11 -11
- package/README.md +222 -227
- package/lib/config/aliasesConfig.d.ts +12 -12
- package/lib/config/aliasesConfig.js +27 -27
- package/lib/config/authInfoConfig.d.ts +19 -19
- package/lib/config/authInfoConfig.js +34 -34
- package/lib/config/config.d.ts +311 -311
- package/lib/config/config.js +574 -574
- package/lib/config/configAggregator.d.ts +232 -232
- package/lib/config/configAggregator.js +379 -379
- package/lib/config/configFile.d.ts +199 -199
- package/lib/config/configFile.js +340 -340
- package/lib/config/configGroup.d.ts +141 -141
- package/lib/config/configGroup.js +224 -224
- package/lib/config/configStore.d.ts +241 -241
- package/lib/config/configStore.js +352 -352
- package/lib/config/envVars.d.ts +101 -101
- package/lib/config/envVars.js +456 -456
- package/lib/config/orgUsersConfig.d.ts +31 -31
- package/lib/config/orgUsersConfig.js +41 -41
- package/lib/config/sandboxOrgConfig.d.ts +37 -37
- package/lib/config/sandboxOrgConfig.js +50 -50
- package/lib/config/sandboxProcessCache.d.ts +16 -16
- package/lib/config/sandboxProcessCache.js +37 -37
- package/lib/config/tokensConfig.d.ts +10 -10
- package/lib/config/tokensConfig.js +28 -28
- package/lib/config/ttlConfig.d.ts +34 -34
- package/lib/config/ttlConfig.js +54 -54
- package/lib/crypto/crypto.d.ts +54 -54
- package/lib/crypto/crypto.js +220 -220
- package/lib/crypto/keyChain.d.ts +8 -8
- package/lib/crypto/keyChain.js +61 -61
- package/lib/crypto/keyChainImpl.d.ts +116 -116
- package/lib/crypto/keyChainImpl.js +486 -486
- package/lib/crypto/secureBuffer.d.ts +46 -46
- package/lib/crypto/secureBuffer.js +82 -82
- package/lib/deviceOauthService.d.ts +71 -71
- package/lib/deviceOauthService.js +191 -191
- package/lib/exported.d.ts +38 -38
- package/lib/exported.js +118 -118
- package/lib/global.d.ts +70 -70
- package/lib/global.js +109 -109
- package/lib/lifecycleEvents.d.ts +93 -93
- package/lib/lifecycleEvents.js +188 -188
- package/lib/logger.d.ts +381 -381
- package/lib/logger.js +734 -734
- package/lib/messages.d.ts +291 -291
- package/lib/messages.js +543 -543
- package/lib/org/authInfo.d.ts +344 -344
- package/lib/org/authInfo.js +892 -892
- package/lib/org/authRemover.d.ts +88 -88
- package/lib/org/authRemover.js +182 -182
- package/lib/org/connection.d.ts +197 -197
- package/lib/org/connection.js +395 -395
- package/lib/org/index.d.ts +6 -6
- package/lib/org/index.js +28 -28
- package/lib/org/org.d.ts +558 -558
- package/lib/org/org.js +1267 -1267
- package/lib/org/orgConfigProperties.d.ts +69 -69
- package/lib/org/orgConfigProperties.js +136 -136
- package/lib/org/permissionSetAssignment.d.ts +35 -35
- package/lib/org/permissionSetAssignment.js +125 -125
- package/lib/org/scratchOrgCache.d.ts +20 -20
- package/lib/org/scratchOrgCache.js +32 -32
- package/lib/org/scratchOrgCreate.d.ts +54 -54
- package/lib/org/scratchOrgCreate.js +216 -216
- package/lib/org/scratchOrgErrorCodes.d.ts +10 -10
- package/lib/org/scratchOrgErrorCodes.js +88 -88
- package/lib/org/scratchOrgFeatureDeprecation.d.ts +26 -26
- package/lib/org/scratchOrgFeatureDeprecation.js +109 -109
- package/lib/org/scratchOrgInfoApi.d.ts +68 -68
- package/lib/org/scratchOrgInfoApi.js +413 -413
- package/lib/org/scratchOrgInfoGenerator.d.ts +64 -64
- package/lib/org/scratchOrgInfoGenerator.js +241 -241
- package/lib/org/scratchOrgLifecycleEvents.d.ts +10 -10
- package/lib/org/scratchOrgLifecycleEvents.js +40 -40
- package/lib/org/scratchOrgSettingsGenerator.d.ts +78 -78
- package/lib/org/scratchOrgSettingsGenerator.js +276 -276
- package/lib/org/scratchOrgTypes.d.ts +43 -43
- package/lib/org/scratchOrgTypes.js +8 -8
- package/lib/org/user.d.ts +187 -187
- package/lib/org/user.js +448 -448
- package/lib/schema/printer.d.ts +79 -79
- package/lib/schema/printer.js +260 -260
- package/lib/schema/validator.d.ts +70 -70
- package/lib/schema/validator.js +169 -169
- package/lib/sfError.d.ts +73 -73
- package/lib/sfError.js +136 -136
- package/lib/sfProject.d.ts +357 -357
- package/lib/sfProject.js +671 -671
- package/lib/stateAggregator/accessors/aliasAccessor.d.ts +98 -98
- package/lib/stateAggregator/accessors/aliasAccessor.js +145 -145
- package/lib/stateAggregator/accessors/orgAccessor.d.ts +101 -101
- package/lib/stateAggregator/accessors/orgAccessor.js +240 -240
- package/lib/stateAggregator/accessors/sandboxAccessor.d.ts +8 -8
- package/lib/stateAggregator/accessors/sandboxAccessor.js +27 -27
- package/lib/stateAggregator/accessors/tokenAccessor.d.ts +63 -63
- package/lib/stateAggregator/accessors/tokenAccessor.js +79 -79
- package/lib/stateAggregator/index.d.ts +4 -4
- package/lib/stateAggregator/index.js +26 -26
- package/lib/stateAggregator/stateAggregator.d.ts +25 -25
- package/lib/stateAggregator/stateAggregator.js +45 -45
- package/lib/status/myDomainResolver.d.ts +66 -66
- package/lib/status/myDomainResolver.js +124 -124
- package/lib/status/pollingClient.d.ts +85 -85
- package/lib/status/pollingClient.js +115 -115
- package/lib/status/streamingClient.d.ts +244 -244
- package/lib/status/streamingClient.js +436 -436
- package/lib/status/types.d.ts +89 -89
- package/lib/status/types.js +17 -17
- package/lib/testSetup.d.ts +553 -530
- package/lib/testSetup.js +871 -727
- package/lib/util/cache.d.ts +11 -11
- package/lib/util/cache.js +69 -69
- package/lib/util/checkLightningDomain.d.ts +1 -1
- package/lib/util/checkLightningDomain.js +28 -28
- package/lib/util/directoryWriter.d.ts +12 -12
- package/lib/util/directoryWriter.js +53 -53
- package/lib/util/getJwtAudienceUrl.d.ts +4 -4
- package/lib/util/getJwtAudienceUrl.js +18 -18
- package/lib/util/internal.d.ts +58 -58
- package/lib/util/internal.js +118 -118
- package/lib/util/jsonXmlTools.d.ts +14 -14
- package/lib/util/jsonXmlTools.js +38 -38
- package/lib/util/mapKeys.d.ts +14 -14
- package/lib/util/mapKeys.js +51 -51
- package/lib/util/sfdc.d.ts +52 -52
- package/lib/util/sfdc.js +85 -85
- package/lib/util/sfdcUrl.d.ts +72 -72
- package/lib/util/sfdcUrl.js +215 -215
- package/lib/util/structuredWriter.d.ts +9 -9
- package/lib/util/structuredWriter.js +2 -2
- package/lib/util/zipWriter.d.ts +16 -16
- package/lib/util/zipWriter.js +67 -67
- package/lib/webOAuthServer.d.ts +156 -156
- package/lib/webOAuthServer.js +388 -388
- package/messages/auth.md +37 -37
- package/messages/config.md +156 -156
- package/messages/connection.md +30 -30
- package/messages/core.json +20 -20
- package/messages/core.md +67 -67
- package/messages/encryption.md +85 -85
- package/messages/envVars.md +303 -303
- package/messages/org.md +63 -63
- package/messages/permissionSetAssignment.md +31 -31
- package/messages/scratchOrgCreate.md +23 -23
- package/messages/scratchOrgErrorCodes.md +115 -115
- package/messages/scratchOrgFeatureDeprecation.md +11 -11
- package/messages/scratchOrgInfoApi.md +15 -15
- package/messages/scratchOrgInfoGenerator.md +23 -23
- package/messages/streaming.md +23 -23
- package/messages/user.md +35 -35
- package/package.json +97 -97
package/lib/webOAuthServer.js
CHANGED
|
@@ -1,389 +1,389 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2020, salesforce.com, inc.
|
|
4
|
-
* All rights reserved.
|
|
5
|
-
* Licensed under the BSD 3-Clause license.
|
|
6
|
-
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
-
*/
|
|
8
|
-
/* eslint-disable class-methods-use-this */
|
|
9
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.WebServer = exports.WebOAuthServer = void 0;
|
|
12
|
-
const http = require("http");
|
|
13
|
-
const querystring_1 = require("querystring");
|
|
14
|
-
const url_1 = require("url");
|
|
15
|
-
const net_1 = require("net");
|
|
16
|
-
const jsforce_1 = require("jsforce");
|
|
17
|
-
const kit_1 = require("@salesforce/kit");
|
|
18
|
-
const ts_types_1 = require("@salesforce/ts-types");
|
|
19
|
-
const logger_1 = require("./logger");
|
|
20
|
-
const org_1 = require("./org");
|
|
21
|
-
const sfError_1 = require("./sfError");
|
|
22
|
-
const messages_1 = require("./messages");
|
|
23
|
-
const sfProject_1 = require("./sfProject");
|
|
24
|
-
messages_1.Messages.importMessagesDirectory(__dirname);
|
|
25
|
-
const messages = messages_1.Messages.load('@salesforce/core', 'auth', [
|
|
26
|
-
'invalidRequestUri',
|
|
27
|
-
'invalidRequestMethod',
|
|
28
|
-
'missingAuthCode',
|
|
29
|
-
'serverErrorHTMLResponse',
|
|
30
|
-
'portInUse',
|
|
31
|
-
'portInUse.actions',
|
|
32
|
-
]);
|
|
33
|
-
/**
|
|
34
|
-
* Handles the creation of a web server for web based login flows.
|
|
35
|
-
*
|
|
36
|
-
* Usage:
|
|
37
|
-
* ```
|
|
38
|
-
* const oauthConfig = {
|
|
39
|
-
* loginUrl: this.flags.instanceurl,
|
|
40
|
-
* clientId: this.flags.clientid,
|
|
41
|
-
* };
|
|
42
|
-
*
|
|
43
|
-
* const oauthServer = await WebOAuthServer.create({ oauthConfig });
|
|
44
|
-
* await oauthServer.start();
|
|
45
|
-
* await open(oauthServer.getAuthorizationUrl(), { wait: false });
|
|
46
|
-
* const authInfo = await oauthServer.authorizeAndSave();
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
|
-
class WebOAuthServer extends kit_1.AsyncCreatable {
|
|
50
|
-
constructor(options) {
|
|
51
|
-
super(options);
|
|
52
|
-
this.oauthConfig = options.oauthConfig;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Returns the configured oauthLocalPort or the WebOAuthServer.DEFAULT_PORT
|
|
56
|
-
*
|
|
57
|
-
* @returns {Promise<number>}
|
|
58
|
-
*/
|
|
59
|
-
static async determineOauthPort() {
|
|
60
|
-
try {
|
|
61
|
-
const sfProject = await sfProject_1.SfProjectJson.create();
|
|
62
|
-
return sfProject.get('oauthLocalPort') || WebOAuthServer.DEFAULT_PORT;
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return WebOAuthServer.DEFAULT_PORT;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Returns the authorization url that's used for the login flow
|
|
70
|
-
*
|
|
71
|
-
* @returns {string}
|
|
72
|
-
*/
|
|
73
|
-
getAuthorizationUrl() {
|
|
74
|
-
return this.authUrl;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Executes the oauth request and creates a new AuthInfo when successful
|
|
78
|
-
*
|
|
79
|
-
* @returns {Promise<AuthInfo>}
|
|
80
|
-
*/
|
|
81
|
-
async authorizeAndSave() {
|
|
82
|
-
if (!this.webServer.server)
|
|
83
|
-
await this.start();
|
|
84
|
-
return new Promise((resolve, reject) => {
|
|
85
|
-
const handler = () => {
|
|
86
|
-
this.logger.debug(`OAuth web login service listening on port: ${this.webServer.port}`);
|
|
87
|
-
this.executeOauthRequest()
|
|
88
|
-
.then(async (response) => {
|
|
89
|
-
try {
|
|
90
|
-
const authInfo = await org_1.AuthInfo.create({
|
|
91
|
-
oauth2Options: this.oauthConfig,
|
|
92
|
-
oauth2: this.oauth2,
|
|
93
|
-
});
|
|
94
|
-
await authInfo.save();
|
|
95
|
-
this.webServer.doRedirect(303, authInfo.getOrgFrontDoorUrl(), response);
|
|
96
|
-
response.end();
|
|
97
|
-
resolve(authInfo);
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
this.webServer.reportError(err, response);
|
|
101
|
-
reject(err);
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
.catch((err) => {
|
|
105
|
-
this.logger.debug('error reported, closing server connection and re-throwing');
|
|
106
|
-
reject(err);
|
|
107
|
-
})
|
|
108
|
-
.finally(() => {
|
|
109
|
-
this.logger.debug('closing server connection');
|
|
110
|
-
this.webServer.close();
|
|
111
|
-
});
|
|
112
|
-
};
|
|
113
|
-
// if the server is already listening the listening event won't be fired anymore so execute handler() directly
|
|
114
|
-
if (this.webServer.server.listening) {
|
|
115
|
-
handler();
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
this.webServer.server.once('listening', handler);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Starts the web server
|
|
124
|
-
*/
|
|
125
|
-
async start() {
|
|
126
|
-
await this.webServer.start();
|
|
127
|
-
}
|
|
128
|
-
async init() {
|
|
129
|
-
this.logger = await logger_1.Logger.child(this.constructor.name);
|
|
130
|
-
const port = await WebOAuthServer.determineOauthPort();
|
|
131
|
-
if (!this.oauthConfig.clientId)
|
|
132
|
-
this.oauthConfig.clientId = org_1.DEFAULT_CONNECTED_APP_INFO.clientId;
|
|
133
|
-
if (!this.oauthConfig.loginUrl)
|
|
134
|
-
this.oauthConfig.loginUrl = org_1.AuthInfo.getDefaultInstanceUrl();
|
|
135
|
-
if (!this.oauthConfig.redirectUri)
|
|
136
|
-
this.oauthConfig.redirectUri = `http://localhost:${port}/OauthRedirect`;
|
|
137
|
-
this.webServer = await WebServer.create({ port });
|
|
138
|
-
this.oauth2 = new jsforce_1.OAuth2(this.oauthConfig);
|
|
139
|
-
this.authUrl = org_1.AuthInfo.getAuthorizationUrl(this.oauthConfig, this.oauth2);
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Executes the oauth request
|
|
143
|
-
*
|
|
144
|
-
* @returns {Promise<AuthInfo>}
|
|
145
|
-
*/
|
|
146
|
-
async executeOauthRequest() {
|
|
147
|
-
return new Promise((resolve, reject) => {
|
|
148
|
-
this.logger.debug('Starting web auth flow');
|
|
149
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/no-explicit-any, @typescript-eslint/require-await
|
|
150
|
-
this.webServer.server.on('request', async (request, response) => {
|
|
151
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
152
|
-
const url = (0, url_1.parse)(request.url);
|
|
153
|
-
this.logger.debug(`processing request for uri: ${url.pathname}`);
|
|
154
|
-
if (request.method === 'GET') {
|
|
155
|
-
if (url.pathname?.startsWith('/OauthRedirect')) {
|
|
156
|
-
request.query = (0, querystring_1.parse)(url.query);
|
|
157
|
-
if (request.query.error) {
|
|
158
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
159
|
-
const err = new sfError_1.SfError(request.query.error_description ?? request.query.error, request.query.error);
|
|
160
|
-
this.webServer.reportError(err, response);
|
|
161
|
-
return reject(err);
|
|
162
|
-
}
|
|
163
|
-
this.logger.debug(`request.query.state: ${request.query.state}`);
|
|
164
|
-
try {
|
|
165
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
166
|
-
this.oauthConfig.authCode = (0, ts_types_1.asString)(this.parseAuthCodeFromRequest(response, request));
|
|
167
|
-
resolve(response);
|
|
168
|
-
}
|
|
169
|
-
catch (err) {
|
|
170
|
-
reject(err);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
this.webServer.sendError(404, 'Resource not found', response);
|
|
175
|
-
const errName = 'invalidRequestUri';
|
|
176
|
-
const errMessage = messages.getMessage(errName, [url.pathname]);
|
|
177
|
-
reject(new sfError_1.SfError(errMessage, errName));
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
this.webServer.sendError(405, 'Unsupported http methods', response);
|
|
182
|
-
const errName = 'invalidRequestMethod';
|
|
183
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
184
|
-
const errMessage = messages.getMessage(errName, [request.method]);
|
|
185
|
-
reject(new sfError_1.SfError(errMessage, errName));
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Parses the auth code from the request url
|
|
192
|
-
*
|
|
193
|
-
* @param response the http response
|
|
194
|
-
* @param request the http request
|
|
195
|
-
* @returns {Nullable<string>}
|
|
196
|
-
*/
|
|
197
|
-
parseAuthCodeFromRequest(response, request) {
|
|
198
|
-
if (!this.validateState(request)) {
|
|
199
|
-
const error = new sfError_1.SfError('urlStateMismatch');
|
|
200
|
-
this.webServer.sendError(400, `${error.message}\n`, response);
|
|
201
|
-
this.closeRequest(request);
|
|
202
|
-
this.logger.warn('urlStateMismatchAttempt detected.');
|
|
203
|
-
if (!(0, ts_types_1.get)(this.webServer.server, 'urlStateMismatchAttempt')) {
|
|
204
|
-
this.logger.error(error.message);
|
|
205
|
-
(0, kit_1.set)(this.webServer.server, 'urlStateMismatchAttempt', true);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
const authCode = request.query.code;
|
|
210
|
-
if (authCode && authCode.length > 4) {
|
|
211
|
-
// AuthCodes are generally long strings. For security purposes we will just log the last 4 of the auth code.
|
|
212
|
-
this.logger.debug(`Successfully obtained auth code: ...${authCode.substring(authCode.length - 5)}`);
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
this.logger.debug('Expected an auth code but could not find one.');
|
|
216
|
-
throw messages.createError('missingAuthCode');
|
|
217
|
-
}
|
|
218
|
-
this.logger.debug(`oauthConfig.loginUrl: ${this.oauthConfig.loginUrl}`);
|
|
219
|
-
this.logger.debug(`oauthConfig.clientId: ${this.oauthConfig.clientId}`);
|
|
220
|
-
this.logger.debug(`oauthConfig.redirectUri: ${this.oauthConfig.redirectUri}`);
|
|
221
|
-
return authCode;
|
|
222
|
-
}
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Closes the request
|
|
227
|
-
*
|
|
228
|
-
* @param request the http request
|
|
229
|
-
*/
|
|
230
|
-
closeRequest(request) {
|
|
231
|
-
request.connection.end();
|
|
232
|
-
request.connection.destroy();
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Validates that the state param in the auth url matches the state
|
|
236
|
-
* param in the http request
|
|
237
|
-
*
|
|
238
|
-
* @param request the http request
|
|
239
|
-
*/
|
|
240
|
-
validateState(request) {
|
|
241
|
-
const state = request.query.state;
|
|
242
|
-
const query = (0, url_1.parse)(this.authUrl, true).query;
|
|
243
|
-
return !!(state && state === query.state);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
exports.WebOAuthServer = WebOAuthServer;
|
|
247
|
-
WebOAuthServer.DEFAULT_PORT = 1717;
|
|
248
|
-
/**
|
|
249
|
-
* Handles the actions specific to the http server
|
|
250
|
-
*/
|
|
251
|
-
class WebServer extends kit_1.AsyncCreatable {
|
|
252
|
-
constructor(options) {
|
|
253
|
-
super(options);
|
|
254
|
-
this.port = WebOAuthServer.DEFAULT_PORT;
|
|
255
|
-
this.host = 'localhost';
|
|
256
|
-
this.sockets = [];
|
|
257
|
-
if (options.port)
|
|
258
|
-
this.port = options.port;
|
|
259
|
-
if (options.host)
|
|
260
|
-
this.host = options.host;
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Starts the http server after checking that the port is open
|
|
264
|
-
*/
|
|
265
|
-
async start() {
|
|
266
|
-
try {
|
|
267
|
-
this.logger.debug('Starting web server');
|
|
268
|
-
await this.checkOsPort();
|
|
269
|
-
this.logger.debug(`Nothing listening on host: localhost port: ${this.port} - good!`);
|
|
270
|
-
this.server = http.createServer();
|
|
271
|
-
this.server.on('connection', (socket) => {
|
|
272
|
-
this.logger.debug(`socket connection initialized from ${socket.remoteAddress}`);
|
|
273
|
-
this.sockets.push(socket);
|
|
274
|
-
});
|
|
275
|
-
this.server.listen(this.port, this.host);
|
|
276
|
-
}
|
|
277
|
-
catch (err) {
|
|
278
|
-
if (err.name === 'EADDRINUSE') {
|
|
279
|
-
throw messages.createError('portInUse', [this.port], [this.port]);
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
throw err;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Closes the http server and all open sockets
|
|
288
|
-
*/
|
|
289
|
-
close() {
|
|
290
|
-
this.sockets.forEach((socket) => {
|
|
291
|
-
socket.end();
|
|
292
|
-
socket.destroy();
|
|
293
|
-
});
|
|
294
|
-
this.server.getConnections((_, num) => {
|
|
295
|
-
this.logger.debug(`number of connections open: ${num}`);
|
|
296
|
-
});
|
|
297
|
-
this.server.close();
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* sends a response error.
|
|
301
|
-
*
|
|
302
|
-
* @param statusCode he statusCode for the response.
|
|
303
|
-
* @param message the message for the http body.
|
|
304
|
-
* @param response the response to write the error to.
|
|
305
|
-
*/
|
|
306
|
-
sendError(status, message, response) {
|
|
307
|
-
response.statusMessage = message;
|
|
308
|
-
response.statusCode = status;
|
|
309
|
-
response.end();
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* sends a response redirect.
|
|
313
|
-
*
|
|
314
|
-
* @param statusCode the statusCode for the response.
|
|
315
|
-
* @param url the url to redirect to.
|
|
316
|
-
* @param response the response to write the redirect to.
|
|
317
|
-
*/
|
|
318
|
-
doRedirect(status, url, response) {
|
|
319
|
-
response.setHeader('Content-Type', 'text/plain');
|
|
320
|
-
const body = `${status} - Redirecting to ${url}`;
|
|
321
|
-
response.setHeader('Content-Length', Buffer.byteLength(body));
|
|
322
|
-
response.writeHead(status, { Location: url });
|
|
323
|
-
response.end(body);
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* sends a response to the browser reporting an error.
|
|
327
|
-
*
|
|
328
|
-
* @param error the error
|
|
329
|
-
* @param response the response to write the redirect to.
|
|
330
|
-
*/
|
|
331
|
-
reportError(error, response) {
|
|
332
|
-
response.setHeader('Content-Type', 'text/html');
|
|
333
|
-
const body = messages.getMessage('serverErrorHTMLResponse', [error.message]);
|
|
334
|
-
response.setHeader('Content-Length', Buffer.byteLength(body));
|
|
335
|
-
response.end(body);
|
|
336
|
-
}
|
|
337
|
-
async init() {
|
|
338
|
-
this.logger = await logger_1.Logger.child(this.constructor.name);
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Make sure we can't open a socket on the localhost/host port. It's important because we don't want to send
|
|
342
|
-
* auth tokens to a random strange port listener. We want to make sure we can startup our server first.
|
|
343
|
-
*
|
|
344
|
-
* @private
|
|
345
|
-
*/
|
|
346
|
-
async checkOsPort() {
|
|
347
|
-
return new Promise((resolve, reject) => {
|
|
348
|
-
const clientConfig = { port: this.port, host: this.host };
|
|
349
|
-
const socket = new net_1.Socket();
|
|
350
|
-
socket.setTimeout(this.getSocketTimeout(), () => {
|
|
351
|
-
socket.destroy();
|
|
352
|
-
const error = new sfError_1.SfError('timeout', 'SOCKET_TIMEOUT');
|
|
353
|
-
reject(error);
|
|
354
|
-
});
|
|
355
|
-
// An existing connection, means that the port is occupied
|
|
356
|
-
socket.connect(clientConfig, () => {
|
|
357
|
-
socket.destroy();
|
|
358
|
-
const error = new sfError_1.SfError('Address in use', 'EADDRINUSE');
|
|
359
|
-
error.data = {
|
|
360
|
-
port: clientConfig.port,
|
|
361
|
-
address: clientConfig.host,
|
|
362
|
-
};
|
|
363
|
-
reject(error);
|
|
364
|
-
});
|
|
365
|
-
// An error means that no existing connection exists, which is what we want
|
|
366
|
-
socket.on('error', () => {
|
|
367
|
-
// eslint-disable-next-line no-console
|
|
368
|
-
socket.destroy();
|
|
369
|
-
resolve(this.port);
|
|
370
|
-
});
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* check and get the socket timeout form what was set in process.env.SFDX_HTTP_SOCKET_TIMEOUT
|
|
375
|
-
*
|
|
376
|
-
* @returns {number} - represents the socket timeout in ms
|
|
377
|
-
* @private
|
|
378
|
-
*/
|
|
379
|
-
getSocketTimeout() {
|
|
380
|
-
const env = new kit_1.Env();
|
|
381
|
-
const socketTimeout = (0, kit_1.toNumber)(env.getNumber('SFDX_HTTP_SOCKET_TIMEOUT'));
|
|
382
|
-
return Number.isInteger(socketTimeout) && socketTimeout > 0
|
|
383
|
-
? socketTimeout
|
|
384
|
-
: WebServer.DEFAULT_CLIENT_SOCKET_TIMEOUT;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
exports.WebServer = WebServer;
|
|
388
|
-
WebServer.DEFAULT_CLIENT_SOCKET_TIMEOUT = 20000;
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2020, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
/* eslint-disable class-methods-use-this */
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.WebServer = exports.WebOAuthServer = void 0;
|
|
12
|
+
const http = require("http");
|
|
13
|
+
const querystring_1 = require("querystring");
|
|
14
|
+
const url_1 = require("url");
|
|
15
|
+
const net_1 = require("net");
|
|
16
|
+
const jsforce_1 = require("jsforce");
|
|
17
|
+
const kit_1 = require("@salesforce/kit");
|
|
18
|
+
const ts_types_1 = require("@salesforce/ts-types");
|
|
19
|
+
const logger_1 = require("./logger");
|
|
20
|
+
const org_1 = require("./org");
|
|
21
|
+
const sfError_1 = require("./sfError");
|
|
22
|
+
const messages_1 = require("./messages");
|
|
23
|
+
const sfProject_1 = require("./sfProject");
|
|
24
|
+
messages_1.Messages.importMessagesDirectory(__dirname);
|
|
25
|
+
const messages = messages_1.Messages.load('@salesforce/core', 'auth', [
|
|
26
|
+
'invalidRequestUri',
|
|
27
|
+
'invalidRequestMethod',
|
|
28
|
+
'missingAuthCode',
|
|
29
|
+
'serverErrorHTMLResponse',
|
|
30
|
+
'portInUse',
|
|
31
|
+
'portInUse.actions',
|
|
32
|
+
]);
|
|
33
|
+
/**
|
|
34
|
+
* Handles the creation of a web server for web based login flows.
|
|
35
|
+
*
|
|
36
|
+
* Usage:
|
|
37
|
+
* ```
|
|
38
|
+
* const oauthConfig = {
|
|
39
|
+
* loginUrl: this.flags.instanceurl,
|
|
40
|
+
* clientId: this.flags.clientid,
|
|
41
|
+
* };
|
|
42
|
+
*
|
|
43
|
+
* const oauthServer = await WebOAuthServer.create({ oauthConfig });
|
|
44
|
+
* await oauthServer.start();
|
|
45
|
+
* await open(oauthServer.getAuthorizationUrl(), { wait: false });
|
|
46
|
+
* const authInfo = await oauthServer.authorizeAndSave();
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
class WebOAuthServer extends kit_1.AsyncCreatable {
|
|
50
|
+
constructor(options) {
|
|
51
|
+
super(options);
|
|
52
|
+
this.oauthConfig = options.oauthConfig;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Returns the configured oauthLocalPort or the WebOAuthServer.DEFAULT_PORT
|
|
56
|
+
*
|
|
57
|
+
* @returns {Promise<number>}
|
|
58
|
+
*/
|
|
59
|
+
static async determineOauthPort() {
|
|
60
|
+
try {
|
|
61
|
+
const sfProject = await sfProject_1.SfProjectJson.create();
|
|
62
|
+
return sfProject.get('oauthLocalPort') || WebOAuthServer.DEFAULT_PORT;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return WebOAuthServer.DEFAULT_PORT;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns the authorization url that's used for the login flow
|
|
70
|
+
*
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
getAuthorizationUrl() {
|
|
74
|
+
return this.authUrl;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Executes the oauth request and creates a new AuthInfo when successful
|
|
78
|
+
*
|
|
79
|
+
* @returns {Promise<AuthInfo>}
|
|
80
|
+
*/
|
|
81
|
+
async authorizeAndSave() {
|
|
82
|
+
if (!this.webServer.server)
|
|
83
|
+
await this.start();
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
const handler = () => {
|
|
86
|
+
this.logger.debug(`OAuth web login service listening on port: ${this.webServer.port}`);
|
|
87
|
+
this.executeOauthRequest()
|
|
88
|
+
.then(async (response) => {
|
|
89
|
+
try {
|
|
90
|
+
const authInfo = await org_1.AuthInfo.create({
|
|
91
|
+
oauth2Options: this.oauthConfig,
|
|
92
|
+
oauth2: this.oauth2,
|
|
93
|
+
});
|
|
94
|
+
await authInfo.save();
|
|
95
|
+
this.webServer.doRedirect(303, authInfo.getOrgFrontDoorUrl(), response);
|
|
96
|
+
response.end();
|
|
97
|
+
resolve(authInfo);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
this.webServer.reportError(err, response);
|
|
101
|
+
reject(err);
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
.catch((err) => {
|
|
105
|
+
this.logger.debug('error reported, closing server connection and re-throwing');
|
|
106
|
+
reject(err);
|
|
107
|
+
})
|
|
108
|
+
.finally(() => {
|
|
109
|
+
this.logger.debug('closing server connection');
|
|
110
|
+
this.webServer.close();
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
// if the server is already listening the listening event won't be fired anymore so execute handler() directly
|
|
114
|
+
if (this.webServer.server.listening) {
|
|
115
|
+
handler();
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
this.webServer.server.once('listening', handler);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Starts the web server
|
|
124
|
+
*/
|
|
125
|
+
async start() {
|
|
126
|
+
await this.webServer.start();
|
|
127
|
+
}
|
|
128
|
+
async init() {
|
|
129
|
+
this.logger = await logger_1.Logger.child(this.constructor.name);
|
|
130
|
+
const port = await WebOAuthServer.determineOauthPort();
|
|
131
|
+
if (!this.oauthConfig.clientId)
|
|
132
|
+
this.oauthConfig.clientId = org_1.DEFAULT_CONNECTED_APP_INFO.clientId;
|
|
133
|
+
if (!this.oauthConfig.loginUrl)
|
|
134
|
+
this.oauthConfig.loginUrl = org_1.AuthInfo.getDefaultInstanceUrl();
|
|
135
|
+
if (!this.oauthConfig.redirectUri)
|
|
136
|
+
this.oauthConfig.redirectUri = `http://localhost:${port}/OauthRedirect`;
|
|
137
|
+
this.webServer = await WebServer.create({ port });
|
|
138
|
+
this.oauth2 = new jsforce_1.OAuth2(this.oauthConfig);
|
|
139
|
+
this.authUrl = org_1.AuthInfo.getAuthorizationUrl(this.oauthConfig, this.oauth2);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Executes the oauth request
|
|
143
|
+
*
|
|
144
|
+
* @returns {Promise<AuthInfo>}
|
|
145
|
+
*/
|
|
146
|
+
async executeOauthRequest() {
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
this.logger.debug('Starting web auth flow');
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/no-explicit-any, @typescript-eslint/require-await
|
|
150
|
+
this.webServer.server.on('request', async (request, response) => {
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
152
|
+
const url = (0, url_1.parse)(request.url);
|
|
153
|
+
this.logger.debug(`processing request for uri: ${url.pathname}`);
|
|
154
|
+
if (request.method === 'GET') {
|
|
155
|
+
if (url.pathname?.startsWith('/OauthRedirect')) {
|
|
156
|
+
request.query = (0, querystring_1.parse)(url.query);
|
|
157
|
+
if (request.query.error) {
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
159
|
+
const err = new sfError_1.SfError(request.query.error_description ?? request.query.error, request.query.error);
|
|
160
|
+
this.webServer.reportError(err, response);
|
|
161
|
+
return reject(err);
|
|
162
|
+
}
|
|
163
|
+
this.logger.debug(`request.query.state: ${request.query.state}`);
|
|
164
|
+
try {
|
|
165
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
166
|
+
this.oauthConfig.authCode = (0, ts_types_1.asString)(this.parseAuthCodeFromRequest(response, request));
|
|
167
|
+
resolve(response);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
reject(err);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.webServer.sendError(404, 'Resource not found', response);
|
|
175
|
+
const errName = 'invalidRequestUri';
|
|
176
|
+
const errMessage = messages.getMessage(errName, [url.pathname]);
|
|
177
|
+
reject(new sfError_1.SfError(errMessage, errName));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.webServer.sendError(405, 'Unsupported http methods', response);
|
|
182
|
+
const errName = 'invalidRequestMethod';
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
184
|
+
const errMessage = messages.getMessage(errName, [request.method]);
|
|
185
|
+
reject(new sfError_1.SfError(errMessage, errName));
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Parses the auth code from the request url
|
|
192
|
+
*
|
|
193
|
+
* @param response the http response
|
|
194
|
+
* @param request the http request
|
|
195
|
+
* @returns {Nullable<string>}
|
|
196
|
+
*/
|
|
197
|
+
parseAuthCodeFromRequest(response, request) {
|
|
198
|
+
if (!this.validateState(request)) {
|
|
199
|
+
const error = new sfError_1.SfError('urlStateMismatch');
|
|
200
|
+
this.webServer.sendError(400, `${error.message}\n`, response);
|
|
201
|
+
this.closeRequest(request);
|
|
202
|
+
this.logger.warn('urlStateMismatchAttempt detected.');
|
|
203
|
+
if (!(0, ts_types_1.get)(this.webServer.server, 'urlStateMismatchAttempt')) {
|
|
204
|
+
this.logger.error(error.message);
|
|
205
|
+
(0, kit_1.set)(this.webServer.server, 'urlStateMismatchAttempt', true);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
const authCode = request.query.code;
|
|
210
|
+
if (authCode && authCode.length > 4) {
|
|
211
|
+
// AuthCodes are generally long strings. For security purposes we will just log the last 4 of the auth code.
|
|
212
|
+
this.logger.debug(`Successfully obtained auth code: ...${authCode.substring(authCode.length - 5)}`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
this.logger.debug('Expected an auth code but could not find one.');
|
|
216
|
+
throw messages.createError('missingAuthCode');
|
|
217
|
+
}
|
|
218
|
+
this.logger.debug(`oauthConfig.loginUrl: ${this.oauthConfig.loginUrl}`);
|
|
219
|
+
this.logger.debug(`oauthConfig.clientId: ${this.oauthConfig.clientId}`);
|
|
220
|
+
this.logger.debug(`oauthConfig.redirectUri: ${this.oauthConfig.redirectUri}`);
|
|
221
|
+
return authCode;
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Closes the request
|
|
227
|
+
*
|
|
228
|
+
* @param request the http request
|
|
229
|
+
*/
|
|
230
|
+
closeRequest(request) {
|
|
231
|
+
request.connection.end();
|
|
232
|
+
request.connection.destroy();
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Validates that the state param in the auth url matches the state
|
|
236
|
+
* param in the http request
|
|
237
|
+
*
|
|
238
|
+
* @param request the http request
|
|
239
|
+
*/
|
|
240
|
+
validateState(request) {
|
|
241
|
+
const state = request.query.state;
|
|
242
|
+
const query = (0, url_1.parse)(this.authUrl, true).query;
|
|
243
|
+
return !!(state && state === query.state);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.WebOAuthServer = WebOAuthServer;
|
|
247
|
+
WebOAuthServer.DEFAULT_PORT = 1717;
|
|
248
|
+
/**
|
|
249
|
+
* Handles the actions specific to the http server
|
|
250
|
+
*/
|
|
251
|
+
class WebServer extends kit_1.AsyncCreatable {
|
|
252
|
+
constructor(options) {
|
|
253
|
+
super(options);
|
|
254
|
+
this.port = WebOAuthServer.DEFAULT_PORT;
|
|
255
|
+
this.host = 'localhost';
|
|
256
|
+
this.sockets = [];
|
|
257
|
+
if (options.port)
|
|
258
|
+
this.port = options.port;
|
|
259
|
+
if (options.host)
|
|
260
|
+
this.host = options.host;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Starts the http server after checking that the port is open
|
|
264
|
+
*/
|
|
265
|
+
async start() {
|
|
266
|
+
try {
|
|
267
|
+
this.logger.debug('Starting web server');
|
|
268
|
+
await this.checkOsPort();
|
|
269
|
+
this.logger.debug(`Nothing listening on host: localhost port: ${this.port} - good!`);
|
|
270
|
+
this.server = http.createServer();
|
|
271
|
+
this.server.on('connection', (socket) => {
|
|
272
|
+
this.logger.debug(`socket connection initialized from ${socket.remoteAddress}`);
|
|
273
|
+
this.sockets.push(socket);
|
|
274
|
+
});
|
|
275
|
+
this.server.listen(this.port, this.host);
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
if (err.name === 'EADDRINUSE') {
|
|
279
|
+
throw messages.createError('portInUse', [this.port], [this.port]);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
throw err;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Closes the http server and all open sockets
|
|
288
|
+
*/
|
|
289
|
+
close() {
|
|
290
|
+
this.sockets.forEach((socket) => {
|
|
291
|
+
socket.end();
|
|
292
|
+
socket.destroy();
|
|
293
|
+
});
|
|
294
|
+
this.server.getConnections((_, num) => {
|
|
295
|
+
this.logger.debug(`number of connections open: ${num}`);
|
|
296
|
+
});
|
|
297
|
+
this.server.close();
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* sends a response error.
|
|
301
|
+
*
|
|
302
|
+
* @param statusCode he statusCode for the response.
|
|
303
|
+
* @param message the message for the http body.
|
|
304
|
+
* @param response the response to write the error to.
|
|
305
|
+
*/
|
|
306
|
+
sendError(status, message, response) {
|
|
307
|
+
response.statusMessage = message;
|
|
308
|
+
response.statusCode = status;
|
|
309
|
+
response.end();
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* sends a response redirect.
|
|
313
|
+
*
|
|
314
|
+
* @param statusCode the statusCode for the response.
|
|
315
|
+
* @param url the url to redirect to.
|
|
316
|
+
* @param response the response to write the redirect to.
|
|
317
|
+
*/
|
|
318
|
+
doRedirect(status, url, response) {
|
|
319
|
+
response.setHeader('Content-Type', 'text/plain');
|
|
320
|
+
const body = `${status} - Redirecting to ${url}`;
|
|
321
|
+
response.setHeader('Content-Length', Buffer.byteLength(body));
|
|
322
|
+
response.writeHead(status, { Location: url });
|
|
323
|
+
response.end(body);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* sends a response to the browser reporting an error.
|
|
327
|
+
*
|
|
328
|
+
* @param error the error
|
|
329
|
+
* @param response the response to write the redirect to.
|
|
330
|
+
*/
|
|
331
|
+
reportError(error, response) {
|
|
332
|
+
response.setHeader('Content-Type', 'text/html');
|
|
333
|
+
const body = messages.getMessage('serverErrorHTMLResponse', [error.message]);
|
|
334
|
+
response.setHeader('Content-Length', Buffer.byteLength(body));
|
|
335
|
+
response.end(body);
|
|
336
|
+
}
|
|
337
|
+
async init() {
|
|
338
|
+
this.logger = await logger_1.Logger.child(this.constructor.name);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Make sure we can't open a socket on the localhost/host port. It's important because we don't want to send
|
|
342
|
+
* auth tokens to a random strange port listener. We want to make sure we can startup our server first.
|
|
343
|
+
*
|
|
344
|
+
* @private
|
|
345
|
+
*/
|
|
346
|
+
async checkOsPort() {
|
|
347
|
+
return new Promise((resolve, reject) => {
|
|
348
|
+
const clientConfig = { port: this.port, host: this.host };
|
|
349
|
+
const socket = new net_1.Socket();
|
|
350
|
+
socket.setTimeout(this.getSocketTimeout(), () => {
|
|
351
|
+
socket.destroy();
|
|
352
|
+
const error = new sfError_1.SfError('timeout', 'SOCKET_TIMEOUT');
|
|
353
|
+
reject(error);
|
|
354
|
+
});
|
|
355
|
+
// An existing connection, means that the port is occupied
|
|
356
|
+
socket.connect(clientConfig, () => {
|
|
357
|
+
socket.destroy();
|
|
358
|
+
const error = new sfError_1.SfError('Address in use', 'EADDRINUSE');
|
|
359
|
+
error.data = {
|
|
360
|
+
port: clientConfig.port,
|
|
361
|
+
address: clientConfig.host,
|
|
362
|
+
};
|
|
363
|
+
reject(error);
|
|
364
|
+
});
|
|
365
|
+
// An error means that no existing connection exists, which is what we want
|
|
366
|
+
socket.on('error', () => {
|
|
367
|
+
// eslint-disable-next-line no-console
|
|
368
|
+
socket.destroy();
|
|
369
|
+
resolve(this.port);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* check and get the socket timeout form what was set in process.env.SFDX_HTTP_SOCKET_TIMEOUT
|
|
375
|
+
*
|
|
376
|
+
* @returns {number} - represents the socket timeout in ms
|
|
377
|
+
* @private
|
|
378
|
+
*/
|
|
379
|
+
getSocketTimeout() {
|
|
380
|
+
const env = new kit_1.Env();
|
|
381
|
+
const socketTimeout = (0, kit_1.toNumber)(env.getNumber('SFDX_HTTP_SOCKET_TIMEOUT'));
|
|
382
|
+
return Number.isInteger(socketTimeout) && socketTimeout > 0
|
|
383
|
+
? socketTimeout
|
|
384
|
+
: WebServer.DEFAULT_CLIENT_SOCKET_TIMEOUT;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
exports.WebServer = WebServer;
|
|
388
|
+
WebServer.DEFAULT_CLIENT_SOCKET_TIMEOUT = 20000;
|
|
389
389
|
//# sourceMappingURL=webOAuthServer.js.map
|