1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | Object.defineProperty(exports, "__esModule", { value: true });
|
9 | const kit_1 = require("@salesforce/kit");
|
10 | const ts_types_1 = require("@salesforce/ts-types");
|
11 | const crypto_1 = require("crypto");
|
12 | const dns = require("dns");
|
13 | const jsforce_1 = require("jsforce");
|
14 |
|
15 | const Transport = require("jsforce/lib/transport");
|
16 | const jwt = require("jsonwebtoken");
|
17 | const path_1 = require("path");
|
18 | const url_1 = require("url");
|
19 | const authInfoConfig_1 = require("./config/authInfoConfig");
|
20 | const configAggregator_1 = require("./config/configAggregator");
|
21 | const connection_1 = require("./connection");
|
22 | const crypto_2 = require("./crypto");
|
23 | const global_1 = require("./global");
|
24 | const logger_1 = require("./logger");
|
25 | const sfdxError_1 = require("./sfdxError");
|
26 | const fs_1 = require("./util/fs");
|
27 |
|
28 | class JwtOAuth2 extends jsforce_1.OAuth2 {
|
29 | constructor(options) {
|
30 | super(options);
|
31 | }
|
32 | async jwtAuthorize(innerToken, callback) {
|
33 |
|
34 |
|
35 | return super._postParams({
|
36 | grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
37 | assertion: innerToken
|
38 | }, callback);
|
39 | }
|
40 | }
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | class OAuth2WithVerifier extends jsforce_1.OAuth2 {
|
56 | constructor(options) {
|
57 | super(options);
|
58 |
|
59 | this.codeVerifier = base64UrlEscape(crypto_1.randomBytes(Math.ceil(128)).toString('base64'));
|
60 | }
|
61 | |
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 | getAuthorizationUrl(params) {
|
68 |
|
69 |
|
70 | const codeChallenge = base64UrlEscape(crypto_1.createHash('sha256')
|
71 | .update(this.codeVerifier)
|
72 | .digest('base64'));
|
73 | kit_1.set(params, 'code_challenge', codeChallenge);
|
74 | return super.getAuthorizationUrl(params);
|
75 | }
|
76 | async requestToken(code, callback) {
|
77 | return super.requestToken(code, callback);
|
78 | }
|
79 | |
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 | async _postParams(params, callback) {
|
88 | kit_1.set(params, 'code_verifier', this.codeVerifier);
|
89 |
|
90 | return super._postParams(params, callback);
|
91 | }
|
92 | }
|
93 | exports.OAuth2WithVerifier = OAuth2WithVerifier;
|
94 |
|
95 |
|
96 |
|
97 | var SfdcUrl;
|
98 | (function (SfdcUrl) {
|
99 | SfdcUrl["SANDBOX"] = "https://test.salesforce.com";
|
100 | SfdcUrl["PRODUCTION"] = "https://login.salesforce.com";
|
101 | })(SfdcUrl = exports.SfdcUrl || (exports.SfdcUrl = {}));
|
102 | const INTERNAL_URL_PARTS = [
|
103 | '.internal.',
|
104 | '.vpod.',
|
105 | 'stm.salesforce.com',
|
106 | '.blitz.salesforce.com',
|
107 | 'mobile1.t.salesforce.com'
|
108 | ];
|
109 | function isInternalUrl(loginUrl = '') {
|
110 | return loginUrl.startsWith('https://gs1.') || INTERNAL_URL_PARTS.some(part => loginUrl.includes(part));
|
111 | }
|
112 | function getJwtAudienceUrl(options) {
|
113 |
|
114 | let audienceUrl = SfdcUrl.PRODUCTION;
|
115 | const loginUrl = ts_types_1.getString(options, 'loginUrl', '');
|
116 | const createdOrgInstance = ts_types_1.getString(options, 'createdOrgInstance', '')
|
117 | .trim()
|
118 | .toLowerCase();
|
119 | if (process.env.SFDX_AUDIENCE_URL) {
|
120 | audienceUrl = process.env.SFDX_AUDIENCE_URL;
|
121 | }
|
122 | else if (isInternalUrl(loginUrl)) {
|
123 |
|
124 | audienceUrl = loginUrl;
|
125 | }
|
126 | else if (createdOrgInstance.startsWith('cs') || url_1.parse(loginUrl).hostname === 'test.salesforce.com') {
|
127 | audienceUrl = SfdcUrl.SANDBOX;
|
128 | }
|
129 | else if (createdOrgInstance.startsWith('gs1')) {
|
130 | audienceUrl = 'https://gs1.salesforce.com';
|
131 | }
|
132 | return audienceUrl;
|
133 | }
|
134 |
|
135 |
|
136 | function _parseIdUrl(idUrl) {
|
137 | const idUrls = idUrl.split('/');
|
138 | const userId = idUrls.pop();
|
139 | const orgId = idUrls.pop();
|
140 | return {
|
141 | userId,
|
142 | orgId,
|
143 | url: idUrl
|
144 | };
|
145 | }
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | const DEFAULT_CONNECTED_APP_INFO = {
|
154 | legacyClientId: 'SalesforceDevelopmentExperience',
|
155 | legacyClientSecret: '1384510088588713504'
|
156 | };
|
157 | class AuthInfoCrypto extends crypto_2.Crypto {
|
158 | decryptFields(fields) {
|
159 | return this._crypt(fields, 'decrypt');
|
160 | }
|
161 | encryptFields(fields) {
|
162 | return this._crypt(fields, 'encrypt');
|
163 | }
|
164 | _crypt(fields, method) {
|
165 | const copy = {};
|
166 | for (const key of ts_types_1.keysOf(fields)) {
|
167 | const rawValue = fields[key];
|
168 | if (rawValue !== undefined) {
|
169 | if (ts_types_1.isString(rawValue) && AuthInfoCrypto.encryptedFields.includes(key)) {
|
170 | copy[key] = this[method](ts_types_1.asString(rawValue));
|
171 | }
|
172 | else {
|
173 | copy[key] = rawValue;
|
174 | }
|
175 | }
|
176 | }
|
177 | return copy;
|
178 | }
|
179 | }
|
180 | AuthInfoCrypto.encryptedFields = [
|
181 | 'accessToken',
|
182 | 'refreshToken',
|
183 | 'password',
|
184 | 'clientSecret'
|
185 | ];
|
186 |
|
187 |
|
188 | function base64UrlEscape(base64Encoded) {
|
189 |
|
190 |
|
191 | return base64Encoded
|
192 | .replace(/\+/g, '-')
|
193 | .replace(/\//g, '_')
|
194 | .replace(/=/g, '');
|
195 | }
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 | class AuthInfo extends kit_1.AsyncCreatable {
|
231 | |
232 |
|
233 |
|
234 |
|
235 |
|
236 | constructor(options) {
|
237 | super(options);
|
238 |
|
239 | this.fields = {};
|
240 |
|
241 | this.usingAccessToken = false;
|
242 | this.options = options;
|
243 | }
|
244 | |
245 |
|
246 |
|
247 |
|
248 | static async listAllAuthFiles() {
|
249 | const globalFiles = await fs_1.fs.readdir(global_1.Global.DIR);
|
250 | const authFiles = globalFiles.filter(file => file.match(AuthInfo.authFilenameFilterRegEx));
|
251 |
|
252 | if (kit_1.isEmpty(authFiles)) {
|
253 | const errConfig = new sfdxError_1.SfdxErrorConfig('@salesforce/core', 'core', 'NoAuthInfoFound');
|
254 | throw sfdxError_1.SfdxError.create(errConfig);
|
255 | }
|
256 |
|
257 | return authFiles;
|
258 | }
|
259 | |
260 |
|
261 |
|
262 | static async hasAuthentications() {
|
263 | try {
|
264 | const authFiles = await this.listAllAuthFiles();
|
265 | return !kit_1.isEmpty(authFiles);
|
266 | }
|
267 | catch (err) {
|
268 | if (err.name === 'OrgDataNotAvailableError' || err.code === 'ENOENT') {
|
269 | return false;
|
270 | }
|
271 | throw err;
|
272 | }
|
273 | }
|
274 | |
275 |
|
276 |
|
277 |
|
278 | static getAuthorizationUrl(options) {
|
279 | const oauth2 = new OAuth2WithVerifier(options);
|
280 |
|
281 |
|
282 | const params = {
|
283 | state: crypto_1.randomBytes(Math.ceil(6)).toString('hex'),
|
284 | prompt: 'login',
|
285 | scope: 'refresh_token api web'
|
286 | };
|
287 | return oauth2.getAuthorizationUrl(params);
|
288 | }
|
289 | |
290 |
|
291 |
|
292 |
|
293 | static clearCache(username) {
|
294 | if (username) {
|
295 | return AuthInfo.cache.delete(username);
|
296 | }
|
297 | return false;
|
298 | }
|
299 | |
300 |
|
301 |
|
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 |
|
308 | static parseSfdxAuthUrl(sfdxAuthUrl) {
|
309 | const match = sfdxAuthUrl.match(/^force:\/\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]*):([a-zA-Z0-9._-]+)@([a-zA-Z0-9._-]+)/);
|
310 | if (!match) {
|
311 | throw new sfdxError_1.SfdxError('Invalid sfdx auth url. Must be in the format `force://<clientId>:<clientSecret>:<refreshToken>@<loginUrl>`. The instanceUrl must not have the protocol set.', 'INVALID_SFDX_AUTH_URL');
|
312 | }
|
313 | const [, clientId, clientSecret, refreshToken, loginUrl] = match;
|
314 | return {
|
315 | clientId,
|
316 | clientSecret,
|
317 | refreshToken,
|
318 | loginUrl: `https://${loginUrl}`
|
319 | };
|
320 | }
|
321 | |
322 |
|
323 |
|
324 | getUsername() {
|
325 | return this.fields.username;
|
326 | }
|
327 | |
328 |
|
329 |
|
330 | isJwt() {
|
331 | const { refreshToken, privateKey } = this.fields;
|
332 | return !refreshToken && !!privateKey;
|
333 | }
|
334 | |
335 |
|
336 |
|
337 | isAccessTokenFlow() {
|
338 | const { refreshToken, privateKey } = this.fields;
|
339 | return !refreshToken && !privateKey;
|
340 | }
|
341 | |
342 |
|
343 |
|
344 | isOauth() {
|
345 | return !this.isAccessTokenFlow() && !this.isJwt();
|
346 | }
|
347 | |
348 |
|
349 |
|
350 | isRefreshTokenFlow() {
|
351 | const { refreshToken, authCode } = this.fields;
|
352 | return !authCode && !!refreshToken;
|
353 | }
|
354 | |
355 |
|
356 |
|
357 |
|
358 | async save(authData) {
|
359 | this.update(authData);
|
360 | const username = ts_types_1.ensure(this.getUsername());
|
361 | AuthInfo.cache.set(username, this.fields);
|
362 | const dataToSave = kit_1.cloneJson(this.fields);
|
363 | this.logger.debug(dataToSave);
|
364 | const config = await authInfoConfig_1.AuthInfoConfig.create(Object.assign({}, authInfoConfig_1.AuthInfoConfig.getOptions(username), { throwOnNotFound: false }));
|
365 | config.setContentsFromObject(dataToSave);
|
366 | await config.write();
|
367 | this.logger.info(`Saved auth info for username: ${this.getUsername()}`);
|
368 | return this;
|
369 | }
|
370 | |
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 |
|
377 | update(authData, encrypt = true) {
|
378 | if (authData && ts_types_1.isPlainObject(authData)) {
|
379 | let copy = kit_1.cloneJson(authData);
|
380 | if (encrypt) {
|
381 | copy = this.authInfoCrypto.encryptFields(copy);
|
382 | }
|
383 | Object.assign(this.fields, copy);
|
384 | this.logger.info(`Updated auth info for username: ${this.getUsername()}`);
|
385 | }
|
386 | return this;
|
387 | }
|
388 | |
389 |
|
390 |
|
391 | getConnectionOptions() {
|
392 | let opts;
|
393 | const { accessToken, instanceUrl } = this.fields;
|
394 | if (this.isAccessTokenFlow()) {
|
395 | this.logger.info('Returning fields for a connection using access token.');
|
396 |
|
397 | opts = { accessToken, instanceUrl };
|
398 | }
|
399 | else if (this.isJwt()) {
|
400 | this.logger.info('Returning fields for a connection using JWT config.');
|
401 | opts = {
|
402 | accessToken,
|
403 | instanceUrl,
|
404 | refreshFn: this.refreshFn.bind(this)
|
405 | };
|
406 | }
|
407 | else {
|
408 |
|
409 |
|
410 |
|
411 |
|
412 | this.logger.info('Returning fields for a connection using OAuth config.');
|
413 |
|
414 | opts = {
|
415 | oauth2: {
|
416 | loginUrl: instanceUrl || 'https://login.salesforce.com',
|
417 | clientId: this.fields.clientId || DEFAULT_CONNECTED_APP_INFO.legacyClientId,
|
418 | redirectUri: 'http://localhost:1717/OauthRedirect'
|
419 | },
|
420 | accessToken,
|
421 | instanceUrl,
|
422 | refreshFn: this.refreshFn.bind(this)
|
423 | };
|
424 | }
|
425 |
|
426 | return this.authInfoCrypto.decryptFields(opts);
|
427 | }
|
428 | |
429 |
|
430 |
|
431 | getFields() {
|
432 | return this.fields;
|
433 | }
|
434 | |
435 |
|
436 |
|
437 | isUsingAccessToken() {
|
438 | return this.usingAccessToken;
|
439 | }
|
440 | |
441 |
|
442 |
|
443 |
|
444 |
|
445 | getSfdxAuthUrl() {
|
446 | const decryptedFields = this.authInfoCrypto.decryptFields(this.fields);
|
447 | const instanceUrl = ts_types_1.ensure(decryptedFields.instanceUrl).replace(/^https?:\/\//, '');
|
448 | let sfdxAuthUrl = 'force://';
|
449 | if (decryptedFields.clientId) {
|
450 | sfdxAuthUrl += `${decryptedFields.clientId}:${decryptedFields.clientSecret || ''}:`;
|
451 | }
|
452 | sfdxAuthUrl += `${decryptedFields.refreshToken}@${instanceUrl}`;
|
453 | return sfdxAuthUrl;
|
454 | }
|
455 | |
456 |
|
457 |
|
458 | async init() {
|
459 |
|
460 | const options = this.options.oauth2Options || this.options.accessTokenOptions;
|
461 | if (!this.options.username && !(this.options.oauth2Options || this.options.accessTokenOptions)) {
|
462 | throw sfdxError_1.SfdxError.create('@salesforce/core', 'core', 'AuthInfoCreationError');
|
463 | }
|
464 |
|
465 |
|
466 | if (this.options.username && this.options.oauth2Options) {
|
467 | const authInfoConfig = await authInfoConfig_1.AuthInfoConfig.create(Object.assign({}, authInfoConfig_1.AuthInfoConfig.getOptions(this.options.username), { throwOnNotFound: false }));
|
468 | if (await authInfoConfig.exists()) {
|
469 | throw sfdxError_1.SfdxError.create(new sfdxError_1.SfdxErrorConfig('@salesforce/core', 'core', 'AuthInfoOverwriteError', undefined, 'AuthInfoOverwriteErrorAction'));
|
470 | }
|
471 | }
|
472 | this.fields.username = this.options.username || ts_types_1.getString(options, 'username') || undefined;
|
473 |
|
474 | const accessTokenMatch = ts_types_1.isString(this.fields.username) && this.fields.username.match(/^(00D\w{12,15})![\.\w]*$/);
|
475 | if (accessTokenMatch) {
|
476 |
|
477 | this.logger = await logger_1.Logger.child('AuthInfo');
|
478 | this.authInfoCrypto = await AuthInfoCrypto.create({
|
479 | noResetOnClose: true
|
480 | });
|
481 | const aggregator = await configAggregator_1.ConfigAggregator.create();
|
482 | const instanceUrl = aggregator.getPropertyValue('instanceUrl') || SfdcUrl.PRODUCTION;
|
483 | this.update({
|
484 | accessToken: this.options.username,
|
485 | instanceUrl,
|
486 | orgId: accessTokenMatch[1]
|
487 | });
|
488 | this.usingAccessToken = true;
|
489 | }
|
490 | else {
|
491 | await this.initAuthOptions(options);
|
492 | }
|
493 | }
|
494 | |
495 |
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 | async initAuthOptions(options) {
|
503 | this.logger = await logger_1.Logger.child('AuthInfo');
|
504 | this.authInfoCrypto = await AuthInfoCrypto.create();
|
505 |
|
506 | let authConfig;
|
507 | if (options) {
|
508 | options = kit_1.cloneJson(options);
|
509 | if (this.isTokenOptions(options)) {
|
510 | authConfig = options;
|
511 | }
|
512 | else {
|
513 | if (this.options.parentUsername) {
|
514 | const parentUserFields = await this.loadAuthFromConfig(this.options.parentUsername);
|
515 | const parentFields = this.authInfoCrypto.decryptFields(parentUserFields);
|
516 | options.clientId = parentFields.clientId;
|
517 | if (process.env.SFDX_CLIENT_SECRET) {
|
518 | options.clientSecret = process.env.SFDX_CLIENT_SECRET;
|
519 | }
|
520 | else {
|
521 |
|
522 | Object.assign(options, {
|
523 | clientSecret: parentFields.clientSecret,
|
524 | privateKey: parentFields.privateKey ? path_1.resolve(parentFields.privateKey) : parentFields.privateKey
|
525 | });
|
526 | }
|
527 | }
|
528 |
|
529 |
|
530 | if (!options.privateKey && options.privateKeyFile) {
|
531 | options.privateKey = path_1.resolve(options.privateKeyFile);
|
532 | }
|
533 | if (options.privateKey) {
|
534 | authConfig = await this.buildJwtConfig(options);
|
535 | }
|
536 | else if (!options.authCode && options.refreshToken) {
|
537 |
|
538 | authConfig = await this.buildRefreshTokenConfig(options);
|
539 | }
|
540 | else {
|
541 | if (this.options.oauth2 instanceof OAuth2WithVerifier) {
|
542 |
|
543 | authConfig = await this.exchangeToken(options, this.options.oauth2);
|
544 | }
|
545 | else {
|
546 | authConfig = await this.exchangeToken(options);
|
547 | }
|
548 | }
|
549 | }
|
550 |
|
551 | this.update(authConfig);
|
552 | }
|
553 | else {
|
554 | authConfig = await this.loadAuthFromConfig(ts_types_1.ensure(this.getUsername()));
|
555 |
|
556 | this.update(authConfig, false);
|
557 | }
|
558 | const username = this.getUsername();
|
559 | if (username) {
|
560 |
|
561 | AuthInfo.cache.set(username, this.fields);
|
562 | }
|
563 | return this;
|
564 | }
|
565 | async loadAuthFromConfig(username) {
|
566 | if (AuthInfo.cache.has(username)) {
|
567 | return ts_types_1.ensure(AuthInfo.cache.get(username));
|
568 | }
|
569 | else {
|
570 |
|
571 | try {
|
572 | const config = await authInfoConfig_1.AuthInfoConfig.create(Object.assign({}, authInfoConfig_1.AuthInfoConfig.getOptions(username), { throwOnNotFound: true }));
|
573 | return config.toObject();
|
574 | }
|
575 | catch (e) {
|
576 | if (e.code === 'ENOENT') {
|
577 | throw sfdxError_1.SfdxError.create('@salesforce/core', 'core', 'NamedOrgNotFound', [username]);
|
578 | }
|
579 | else {
|
580 | throw e;
|
581 | }
|
582 | }
|
583 | }
|
584 | }
|
585 | isTokenOptions(options) {
|
586 |
|
587 |
|
588 | return ('accessToken' in options &&
|
589 | !('refreshToken' in options) &&
|
590 | !('privateKey' in options) &&
|
591 | !('privateKeyFile' in options) &&
|
592 | !('authCode' in options));
|
593 | }
|
594 |
|
595 |
|
596 | async refreshFn(conn, callback) {
|
597 | this.logger.info('Access token has expired. Updating...');
|
598 | try {
|
599 | const fields = this.authInfoCrypto.decryptFields(this.fields);
|
600 | await this.initAuthOptions(fields);
|
601 | await this.save();
|
602 | return await callback(null, fields.accessToken);
|
603 | }
|
604 | catch (err) {
|
605 | if (err.message && err.message.includes('Data Not Available')) {
|
606 | const errConfig = new sfdxError_1.SfdxErrorConfig('@salesforce/core', 'core', 'OrgDataNotAvailableError', [
|
607 | this.getUsername()
|
608 | ]);
|
609 | for (let i = 1; i < 5; i++) {
|
610 | errConfig.addAction(`OrgDataNotAvailableErrorAction${i}`);
|
611 | }
|
612 | return await callback(sfdxError_1.SfdxError.create(errConfig));
|
613 | }
|
614 | return await callback(err);
|
615 | }
|
616 | }
|
617 |
|
618 | async buildJwtConfig(options) {
|
619 | const privateKeyContents = await fs_1.fs.readFile(ts_types_1.ensure(options.privateKey), 'utf8');
|
620 | const audienceUrl = getJwtAudienceUrl(options);
|
621 | const jwtToken = await jwt.sign({
|
622 | iss: options.clientId,
|
623 | sub: this.getUsername(),
|
624 | aud: audienceUrl,
|
625 | exp: Date.now() + 300
|
626 | }, privateKeyContents, {
|
627 | algorithm: 'RS256'
|
628 | });
|
629 | const oauth2 = new JwtOAuth2({ loginUrl: options.loginUrl });
|
630 | let _authFields;
|
631 | try {
|
632 | _authFields = ts_types_1.ensureJsonMap(await oauth2.jwtAuthorize(jwtToken));
|
633 | }
|
634 | catch (err) {
|
635 | throw sfdxError_1.SfdxError.create('@salesforce/core', 'core', 'JWTAuthError', [err.message]);
|
636 | }
|
637 | const authFields = {
|
638 | accessToken: ts_types_1.asString(_authFields.access_token),
|
639 | orgId: _parseIdUrl(ts_types_1.ensureString(_authFields.id)).orgId,
|
640 | loginUrl: options.loginUrl,
|
641 | privateKey: options.privateKey,
|
642 | clientId: options.clientId
|
643 | };
|
644 | const instanceUrl = ts_types_1.ensureString(_authFields.instance_url);
|
645 | const parsedUrl = url_1.parse(instanceUrl);
|
646 | try {
|
647 |
|
648 | await this.lookup(ts_types_1.ensure(parsedUrl.hostname));
|
649 | authFields.instanceUrl = instanceUrl;
|
650 | }
|
651 | catch (err) {
|
652 | this.logger.debug(`Instance URL [${_authFields.instance_url}] is not available. DNS lookup failed. Using loginUrl [${options.loginUrl}] instead. This may result in a "Destination URL not reset" error.`);
|
653 | authFields.instanceUrl = options.loginUrl;
|
654 | }
|
655 | return authFields;
|
656 | }
|
657 |
|
658 | async buildRefreshTokenConfig(options) {
|
659 |
|
660 |
|
661 | if (!options.clientId) {
|
662 | options.clientId = DEFAULT_CONNECTED_APP_INFO.legacyClientId;
|
663 | options.clientSecret = DEFAULT_CONNECTED_APP_INFO.legacyClientSecret;
|
664 | }
|
665 | const oauth2 = new jsforce_1.OAuth2(options);
|
666 | let _authFields;
|
667 | try {
|
668 | _authFields = await oauth2.refreshToken(ts_types_1.ensure(options.refreshToken));
|
669 | }
|
670 | catch (err) {
|
671 | throw sfdxError_1.SfdxError.create('@salesforce/core', 'core', 'RefreshTokenAuthError', [err.message]);
|
672 | }
|
673 | return {
|
674 | accessToken: _authFields.access_token,
|
675 |
|
676 | instanceUrl: _authFields.instance_url,
|
677 |
|
678 | orgId: _parseIdUrl(_authFields.id).orgId,
|
679 |
|
680 | loginUrl: options.loginUrl || _authFields.instance_url,
|
681 | refreshToken: options.refreshToken,
|
682 | clientId: options.clientId,
|
683 | clientSecret: options.clientSecret
|
684 | };
|
685 | }
|
686 | |
687 |
|
688 |
|
689 |
|
690 |
|
691 | async exchangeToken(options, oauth2 = new jsforce_1.OAuth2(options)) {
|
692 |
|
693 | let _authFields;
|
694 | try {
|
695 | this.logger.info(`Exchanging auth code for access token using loginUrl: ${options.loginUrl}`);
|
696 | _authFields = await oauth2.requestToken(ts_types_1.ensure(options.authCode));
|
697 | }
|
698 | catch (err) {
|
699 | throw sfdxError_1.SfdxError.create('@salesforce/core', 'core', 'AuthCodeExchangeError', [err.message]);
|
700 | }
|
701 |
|
702 | const { userId, orgId } = _parseIdUrl(_authFields.id);
|
703 | let username = this.getUsername();
|
704 |
|
705 |
|
706 | if (!username) {
|
707 |
|
708 |
|
709 |
|
710 | const apiVersion = 'v42.0';
|
711 | const instance = ts_types_1.ensure(ts_types_1.getString(_authFields, 'instance_url'));
|
712 | const url = `${instance}/services/data/${apiVersion}/sobjects/User/${userId}`;
|
713 | const headers = Object.assign({ Authorization: `Bearer ${_authFields.access_token}` }, connection_1.SFDX_HTTP_HEADERS);
|
714 | try {
|
715 | this.logger.info(`Sending request for Username after successful auth code exchange to URL: ${url}`);
|
716 | const response = await new Transport().httpRequest({ url, headers });
|
717 | username = ts_types_1.asString(kit_1.parseJsonMap(response.body).Username);
|
718 | }
|
719 | catch (err) {
|
720 | throw sfdxError_1.SfdxError.create('@salesforce/core', 'core', 'AuthCodeUsernameRetrievalError', [orgId, err.message]);
|
721 | }
|
722 | }
|
723 | return {
|
724 | accessToken: _authFields.access_token,
|
725 |
|
726 | instanceUrl: _authFields.instance_url,
|
727 | orgId,
|
728 | username,
|
729 |
|
730 | loginUrl: options.loginUrl || _authFields.instance_url,
|
731 | refreshToken: _authFields.refresh_token,
|
732 | clientId: options.clientId,
|
733 | clientSecret: options.clientSecret
|
734 | };
|
735 | }
|
736 |
|
737 | async lookup(host) {
|
738 | return new Promise((resolve, reject) => {
|
739 | dns.lookup(host, (err, address, family) => {
|
740 | if (err) {
|
741 | reject(err);
|
742 | }
|
743 | else {
|
744 | resolve({ address, family });
|
745 | }
|
746 | });
|
747 | });
|
748 | }
|
749 | }
|
750 |
|
751 | AuthInfo.authFilenameFilterRegEx = /^[^.][^@]*@[^.]+(\.[^.\s]+)+\.json$/;
|
752 |
|
753 | AuthInfo.cache = new Map();
|
754 | exports.AuthInfo = AuthInfo;
|
755 |
|
\ | No newline at end of file |