@salesforce/core 8.12.0 → 8.12.1-dev.0
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/org/authInfo.d.ts +19 -1
- package/lib/org/authInfo.js +64 -17
- package/lib/org/connection.d.ts +4 -0
- package/lib/org/connection.js +1 -1
- package/lib/webOAuthServer.d.ts +27 -1
- package/lib/webOAuthServer.js +43 -8
- package/package.json +1 -1
package/lib/org/authInfo.d.ts
CHANGED
|
@@ -7,6 +7,15 @@ import { Org } from './org';
|
|
|
7
7
|
* Fields for authorization, org, and local information.
|
|
8
8
|
*/
|
|
9
9
|
export type AuthFields = {
|
|
10
|
+
apps?: {
|
|
11
|
+
[key: string]: {
|
|
12
|
+
clientId: string;
|
|
13
|
+
clientSecret?: string;
|
|
14
|
+
accessToken: string;
|
|
15
|
+
refreshToken: string;
|
|
16
|
+
oauthFlow: 'web';
|
|
17
|
+
};
|
|
18
|
+
};
|
|
10
19
|
accessToken?: string;
|
|
11
20
|
alias?: string;
|
|
12
21
|
authCode?: string;
|
|
@@ -234,8 +243,10 @@ export declare class AuthInfo extends AsyncOptionalCreatable<AuthInfo.Options> {
|
|
|
234
243
|
update(authData?: AuthFields): AuthInfo;
|
|
235
244
|
/**
|
|
236
245
|
* Get the auth fields (decrypted) needed to make a connection.
|
|
246
|
+
*
|
|
247
|
+
* @param app Name of the CA/ECA associated with the user.
|
|
237
248
|
*/
|
|
238
|
-
getConnectionOptions(): ConnectionOptions;
|
|
249
|
+
getConnectionOptions(app?: string): ConnectionOptions;
|
|
239
250
|
getClientId(): string;
|
|
240
251
|
getRedirectUri(): string;
|
|
241
252
|
/**
|
|
@@ -343,6 +354,13 @@ export declare namespace AuthInfo {
|
|
|
343
354
|
* OAuth options.
|
|
344
355
|
*/
|
|
345
356
|
oauth2Options?: JwtOAuth2Config;
|
|
357
|
+
apps?: Array<{
|
|
358
|
+
name: string;
|
|
359
|
+
accessToken: string;
|
|
360
|
+
refreshToken: string;
|
|
361
|
+
clientId: string;
|
|
362
|
+
clientSecret?: string;
|
|
363
|
+
}>;
|
|
346
364
|
/**
|
|
347
365
|
* Options for the access token auth.
|
|
348
366
|
*/
|
package/lib/org/authInfo.js
CHANGED
|
@@ -445,38 +445,85 @@ class AuthInfo extends kit_1.AsyncOptionalCreatable {
|
|
|
445
445
|
}
|
|
446
446
|
/**
|
|
447
447
|
* Get the auth fields (decrypted) needed to make a connection.
|
|
448
|
+
*
|
|
449
|
+
* @param app Name of the CA/ECA associated with the user.
|
|
448
450
|
*/
|
|
449
|
-
getConnectionOptions() {
|
|
451
|
+
getConnectionOptions(app) {
|
|
450
452
|
const decryptedCopy = this.getFields(true);
|
|
451
453
|
const { accessToken, instanceUrl, loginUrl } = decryptedCopy;
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
454
|
+
// return main app auth fields
|
|
455
|
+
if (!app) {
|
|
456
|
+
if (this.isAccessTokenFlow()) {
|
|
457
|
+
this.logger.info('Returning fields for a connection using access token.');
|
|
458
|
+
// Just auth with the accessToken
|
|
459
|
+
return { accessToken, instanceUrl, loginUrl };
|
|
460
|
+
}
|
|
461
|
+
if (this.isJwt()) {
|
|
462
|
+
this.logger.info('Returning fields for a connection using JWT config.');
|
|
463
|
+
return {
|
|
464
|
+
accessToken,
|
|
465
|
+
instanceUrl,
|
|
466
|
+
refreshFn: this.refreshFn.bind(this),
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
// @TODO: figure out loginUrl and redirectUri (probably get from config class)
|
|
470
|
+
//
|
|
471
|
+
// redirectUri: org.config.getOauthCallbackUrl()
|
|
472
|
+
// loginUrl: this.fields.instanceUrl || this.config.getAppConfig().sfdcLoginUrl
|
|
473
|
+
this.logger.info('Returning fields for a connection using OAuth config.');
|
|
474
|
+
// Decrypt a user provided client secret or use the default.
|
|
459
475
|
return {
|
|
476
|
+
oauth2: {
|
|
477
|
+
loginUrl: instanceUrl ?? sfdcUrl_1.SfdcUrl.PRODUCTION,
|
|
478
|
+
clientId: this.getClientId(),
|
|
479
|
+
redirectUri: this.getRedirectUri(),
|
|
480
|
+
},
|
|
460
481
|
accessToken,
|
|
461
482
|
instanceUrl,
|
|
462
483
|
refreshFn: this.refreshFn.bind(this),
|
|
463
484
|
};
|
|
464
485
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
486
|
+
if (!decryptedCopy.apps) {
|
|
487
|
+
throw new sfError_1.SfError(`${this.username} does not have any apps linked yet.`);
|
|
488
|
+
}
|
|
489
|
+
if (!(app in decryptedCopy.apps)) {
|
|
490
|
+
throw new sfError_1.SfError(`${this.username} does not have a "${app}" app linked yet.`);
|
|
491
|
+
}
|
|
492
|
+
const decryptedApp = decryptedCopy.apps[app];
|
|
471
493
|
return {
|
|
472
494
|
oauth2: {
|
|
473
495
|
loginUrl: instanceUrl ?? sfdcUrl_1.SfdcUrl.PRODUCTION,
|
|
474
|
-
clientId:
|
|
496
|
+
clientId: decryptedApp.clientId,
|
|
475
497
|
redirectUri: this.getRedirectUri(),
|
|
476
498
|
},
|
|
477
|
-
accessToken,
|
|
499
|
+
accessToken: decryptedApp.accessToken,
|
|
478
500
|
instanceUrl,
|
|
479
|
-
refreshFn
|
|
501
|
+
// Specific refreshFn for AuthInfo's apps.
|
|
502
|
+
//
|
|
503
|
+
// Each app stores the oauth flow used for its initial auth, here we ensure each refresh returns
|
|
504
|
+
// a token, update the auth file with it and send it back to jsforce's through the callback.
|
|
505
|
+
refreshFn: async (_conn, callback) => {
|
|
506
|
+
// This only handles refresh for web flow.
|
|
507
|
+
// When more flows are supported for apps, check the `app.oauthFlow` field to set the appropiate refresh helper.
|
|
508
|
+
const authFields = await this.buildRefreshTokenConfig({
|
|
509
|
+
clientId: decryptedApp.clientId,
|
|
510
|
+
clientSecret: decryptedApp.clientSecret,
|
|
511
|
+
refreshToken: decryptedApp.refreshToken,
|
|
512
|
+
loginUrl: instanceUrl,
|
|
513
|
+
});
|
|
514
|
+
await this.save({
|
|
515
|
+
apps: {
|
|
516
|
+
[app]: {
|
|
517
|
+
accessToken: (0, ts_types_1.ensureString)(authFields.accessToken),
|
|
518
|
+
clientId: decryptedApp.clientId,
|
|
519
|
+
clientSecret: decryptedApp.clientSecret,
|
|
520
|
+
refreshToken: decryptedApp.refreshToken,
|
|
521
|
+
oauthFlow: 'web',
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
await callback(null, authFields.accessToken);
|
|
526
|
+
},
|
|
480
527
|
};
|
|
481
528
|
}
|
|
482
529
|
getClientId() {
|
package/lib/org/connection.d.ts
CHANGED
package/lib/org/connection.js
CHANGED
|
@@ -86,7 +86,7 @@ class Connection extends jsforce_node_1.Connection {
|
|
|
86
86
|
callOptions: {
|
|
87
87
|
client: clientId,
|
|
88
88
|
},
|
|
89
|
-
...options.authInfo.getConnectionOptions(),
|
|
89
|
+
...options.authInfo.getConnectionOptions(options.app),
|
|
90
90
|
// this assertion is questionable, but has existed before core7
|
|
91
91
|
};
|
|
92
92
|
const conn = new this({ ...options, connectionOptions });
|
package/lib/webOAuthServer.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export declare class WebOAuthServer extends AsyncCreatable<WebOAuthServer.Option
|
|
|
26
26
|
private oauth2;
|
|
27
27
|
private oauthConfig;
|
|
28
28
|
private oauthError;
|
|
29
|
+
private app?;
|
|
30
|
+
private username?;
|
|
29
31
|
constructor(options: WebOAuthServer.Options);
|
|
30
32
|
/**
|
|
31
33
|
* Returns the configured oauthLocalPort or the WebOAuthServer.DEFAULT_PORT
|
|
@@ -80,7 +82,31 @@ export declare class WebOAuthServer extends AsyncCreatable<WebOAuthServer.Option
|
|
|
80
82
|
}
|
|
81
83
|
export declare namespace WebOAuthServer {
|
|
82
84
|
type Options = {
|
|
83
|
-
oauthConfig: JwtOAuth2Config
|
|
85
|
+
oauthConfig: JwtOAuth2Config & {
|
|
86
|
+
/**
|
|
87
|
+
* OAuth scopes to be requested for the access token.
|
|
88
|
+
*
|
|
89
|
+
* This should be a string with each scope separated by spaces:
|
|
90
|
+
* "refresh_token sfap_api chatbot_api web api"
|
|
91
|
+
*
|
|
92
|
+
* If not specified, all scopes assigned to the connected app are requested.
|
|
93
|
+
*/
|
|
94
|
+
scope?: string;
|
|
95
|
+
};
|
|
96
|
+
} | {
|
|
97
|
+
oauthConfig: JwtOAuth2Config & {
|
|
98
|
+
/**
|
|
99
|
+
* OAuth scopes to be requested for the access token.
|
|
100
|
+
*
|
|
101
|
+
* This should be a string with each scope separated by spaces:
|
|
102
|
+
* "refresh_token sfap_api chatbot_api web api"
|
|
103
|
+
*
|
|
104
|
+
* If not specified, all scopes assigned to the connected app are requested.
|
|
105
|
+
*/
|
|
106
|
+
scope?: string;
|
|
107
|
+
};
|
|
108
|
+
app: string;
|
|
109
|
+
username: string;
|
|
84
110
|
};
|
|
85
111
|
type Request = http.IncomingMessage & {
|
|
86
112
|
query: {
|
package/lib/webOAuthServer.js
CHANGED
|
@@ -73,9 +73,15 @@ class WebOAuthServer extends kit_1.AsyncCreatable {
|
|
|
73
73
|
oauth2;
|
|
74
74
|
oauthConfig;
|
|
75
75
|
oauthError = new Error('Oauth Error');
|
|
76
|
+
app;
|
|
77
|
+
username;
|
|
76
78
|
constructor(options) {
|
|
77
79
|
super(options);
|
|
78
80
|
this.oauthConfig = options.oauthConfig;
|
|
81
|
+
if ('app' in options) {
|
|
82
|
+
this.app = options.app;
|
|
83
|
+
this.username = options.username;
|
|
84
|
+
}
|
|
79
85
|
}
|
|
80
86
|
/**
|
|
81
87
|
* Returns the configured oauthLocalPort or the WebOAuthServer.DEFAULT_PORT
|
|
@@ -113,14 +119,43 @@ class WebOAuthServer extends kit_1.AsyncCreatable {
|
|
|
113
119
|
this.executeOauthRequest()
|
|
114
120
|
.then(async (response) => {
|
|
115
121
|
try {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
// Link app to an existing auth file.
|
|
123
|
+
if (this.app) {
|
|
124
|
+
const authInfo = await authInfo_1.AuthInfo.create({
|
|
125
|
+
oauth2Options: this.oauthConfig,
|
|
126
|
+
oauth2: this.oauth2,
|
|
127
|
+
});
|
|
128
|
+
const authFields = authInfo.getFields(true);
|
|
129
|
+
// get user authInfo and save app creds in `apps`
|
|
130
|
+
const userAuthInfo = await authInfo_1.AuthInfo.create({
|
|
131
|
+
username: this.username,
|
|
132
|
+
});
|
|
133
|
+
await userAuthInfo.save({
|
|
134
|
+
apps: {
|
|
135
|
+
[this.app]: {
|
|
136
|
+
clientId: (0, ts_types_1.ensureString)(authFields.clientId),
|
|
137
|
+
clientSecret: authFields.clientSecret,
|
|
138
|
+
accessToken: (0, ts_types_1.ensureString)(authFields.accessToken),
|
|
139
|
+
refreshToken: (0, ts_types_1.ensureString)(authFields.refreshToken),
|
|
140
|
+
oauthFlow: 'web',
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
await this.webServer.handleSuccess(response);
|
|
145
|
+
response.end();
|
|
146
|
+
resolve(authInfo);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// new auth, create new file.
|
|
150
|
+
const authInfo = await authInfo_1.AuthInfo.create({
|
|
151
|
+
oauth2Options: this.oauthConfig,
|
|
152
|
+
oauth2: this.oauth2,
|
|
153
|
+
});
|
|
154
|
+
await authInfo.save();
|
|
155
|
+
await this.webServer.handleSuccess(response);
|
|
156
|
+
response.end();
|
|
157
|
+
resolve(authInfo);
|
|
158
|
+
}
|
|
124
159
|
}
|
|
125
160
|
catch (err) {
|
|
126
161
|
this.oauthError = err;
|