Skip to content

Commit ebeebdf

Browse files
authored
Merge pull request #1423 from salesforcecli/cd/fix-scopes
fix(web): refactor logic/fix scopes W-20329175
2 parents e38d54d + 957862d commit ebeebdf

5 files changed

Lines changed: 68 additions & 65 deletions

File tree

messages/web.login.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ Username of the already-authenticated user to link to the connected app or exter
5656

5757
Authentication (OAuth) scopes to request. Use the scope's short name; specify multiple scopes using just one flag instance and separated by spaces: --scopes "sfap_api chatbot_api".
5858

59+
# flags.scopes.invalidFormat
60+
61+
The --scopes flag must be a space-separated list (example: "api web").
62+
5963
# linkedClientApp
6064

6165
Successfully linked "%s" client app to %s.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@inquirer/checkbox": "^2.5.0",
99
"@inquirer/select": "^2.5.0",
1010
"@oclif/core": "^4",
11-
"@salesforce/core": "8.23.4",
11+
"@salesforce/core": "^8.23.5",
1212
"@salesforce/kit": "^3.2.4",
1313
"@salesforce/plugin-info": "^3.4.96",
1414
"@salesforce/sf-plugins-core": "^12.2.6",

src/commands/org/login/web.ts

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
2424
const messages = Messages.loadMessages('@salesforce/plugin-auth', 'web.login');
2525
const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'messages');
2626

27+
export type ExecuteLoginFlowParams = {
28+
oauthConfig: OAuth2Config;
29+
browser?: string;
30+
scopes?: string;
31+
} & ({ clientApp: { name: string; username: string } } | { clientApp?: undefined });
32+
2733
export default class LoginWeb extends SfCommand<AuthFields> {
2834
public static readonly summary = messages.getMessage('summary');
2935
public static readonly description = messages.getMessage('description');
@@ -89,6 +95,12 @@ export default class LoginWeb extends SfCommand<AuthFields> {
8995
}),
9096
scopes: Flags.string({
9197
summary: messages.getMessage('flags.scopes.summary'),
98+
parse: async (input: string) => {
99+
if (input.includes(',')) {
100+
throw new SfError(messages.getMessage('flags.scopes.invalidFormat'));
101+
}
102+
return Promise.resolve(input);
103+
},
92104
}),
93105
};
94106

@@ -118,7 +130,12 @@ export default class LoginWeb extends SfCommand<AuthFields> {
118130
...{ clientSecret: await this.secretPrompt({ message: commonMessages.getMessage('clientSecretStdin') }) },
119131
};
120132

121-
await this.executeLoginFlow(oauthConfig, flags.browser, flags['client-app'], flags.username, flags.scopes);
133+
await this.executeLoginFlow({
134+
oauthConfig,
135+
browser: flags.browser,
136+
clientApp: { name: flags['client-app'], username: flags.username },
137+
scopes: flags.scopes,
138+
});
122139

123140
this.logSuccess(messages.getMessage('linkedClientApp', [flags['client-app'], flags.username]));
124141
return userAuthInfo.getFields(true);
@@ -133,7 +150,12 @@ export default class LoginWeb extends SfCommand<AuthFields> {
133150
};
134151

135152
try {
136-
const authInfo = await this.executeLoginFlow(oauthConfig, flags.browser, flags.scopes);
153+
const authInfo = await this.executeLoginFlow({
154+
oauthConfig,
155+
browser: flags.browser,
156+
clientApp: undefined,
157+
scopes: flags.scopes,
158+
});
137159
await authInfo.handleAliasAndDefaultSettings({
138160
alias: flags.alias,
139161
setDefault: flags['set-default'],
@@ -156,13 +178,12 @@ export default class LoginWeb extends SfCommand<AuthFields> {
156178

157179
// leave it because it's stubbed in the test
158180
// eslint-disable-next-line class-methods-use-this
159-
private async executeLoginFlow(
160-
oauthConfig: OAuth2Config,
161-
browser?: string,
162-
app?: string,
163-
username?: string,
164-
scopes?: string
165-
): Promise<AuthInfo> {
181+
private async executeLoginFlow({
182+
oauthConfig,
183+
browser,
184+
clientApp,
185+
scopes,
186+
}: ExecuteLoginFlowParams): Promise<AuthInfo> {
166187
// The server handles 2 possible auth scenarios:
167188
// a. 1st time auth, creates auth file.
168189
// b. Add CA/ECA to existing auth.
@@ -171,8 +192,8 @@ export default class LoginWeb extends SfCommand<AuthFields> {
171192
...oauthConfig,
172193
scope: scopes,
173194
},
174-
clientApp: app,
175-
username,
195+
clientApp: clientApp?.name,
196+
username: clientApp?.username,
176197
});
177198
await oauthServer.start();
178199
const browserApp = browser && browser in apps ? (browser as AppName) : undefined;

test/commands/org/login/login.web.test.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { StubbedType, stubInterface, stubMethod } from '@salesforce/ts-sinon';
2323
import { assert, expect } from 'chai';
2424
import { Env } from '@salesforce/kit';
2525
import { SfCommand, Ux } from '@salesforce/sf-plugins-core';
26-
import LoginWeb from '../../../../src/commands/org/login/web.js';
26+
import LoginWeb, { ExecuteLoginFlowParams } from '../../../../src/commands/org/login/web.js';
2727

2828
describe('org:login:web', () => {
2929
const $$ = new TestContext();
@@ -195,8 +195,8 @@ describe('org:login:web', () => {
195195

196196
// Verify that executeLoginFlow was called with the scopes parameter
197197
expect(executeLoginFlowStub.callCount).to.equal(1);
198-
const callArgs = executeLoginFlowStub.getCall(0).args;
199-
expect(callArgs[2]).to.equal('api web refresh_token'); // scopes should be the 3rd argument
198+
const callArgs = executeLoginFlowStub.getCall(0).args[0] as ExecuteLoginFlowParams;
199+
expect(callArgs.scopes).to.equal('api web refresh_token'); // scopes should be present in the object
200200
});
201201

202202
it('should pass undefined scopes to executeLoginFlow when scopes flag is not provided', async () => {
@@ -223,8 +223,8 @@ describe('org:login:web', () => {
223223

224224
// Verify that executeLoginFlow was called without scopes (undefined)
225225
expect(executeLoginFlowStub.callCount).to.equal(1);
226-
const callArgs = executeLoginFlowStub.getCall(0).args;
227-
expect(callArgs[2]).to.be.undefined; // scopes should be undefined when not provided
226+
const callArgs = executeLoginFlowStub.getCall(0).args[0] as ExecuteLoginFlowParams;
227+
expect(callArgs.scopes).to.be.undefined;
228228
});
229229

230230
it('should pass scopes flag to executeLoginFlow when linking client-app with scopes', async () => {
@@ -242,8 +242,11 @@ describe('org:login:web', () => {
242242
$$.SANDBOX.stub(AuthInfo, 'create').resolves(authInfoStub);
243243
$$.SANDBOX.stub(AuthInfo, 'listAllAuthorizations').resolves([]);
244244

245-
// @ts-ignore
246-
const login = new LoginWeb(['--client-app', 'MyApp', '--username', 'test@example.com', '--scopes', 'api web'], config);
245+
const login = new LoginWeb(
246+
['--client-app', 'MyApp', '--username', 'test@example.com', '--scopes', 'api web'],
247+
// @ts-ignore
248+
config
249+
);
247250
// @ts-ignore because protected member
248251
login.ux = uxStub;
249252
// @ts-ignore because protected member
@@ -258,10 +261,10 @@ describe('org:login:web', () => {
258261

259262
// Verify that executeLoginFlow was called with the correct parameters
260263
expect(executeLoginFlowStub.callCount).to.equal(1);
261-
const callArgs = executeLoginFlowStub.getCall(0).args;
262-
expect(callArgs[2]).to.equal('MyApp'); // client-app should be the 3rd argument
263-
expect(callArgs[3]).to.equal('test@example.com'); // username should be the 4th argument
264-
expect(callArgs[4]).to.equal('api web'); // scopes should be the 5th argument
264+
const callArgs = executeLoginFlowStub.getCall(0).args[0] as ExecuteLoginFlowParams;
265+
expect(callArgs.clientApp?.name).to.equal('MyApp');
266+
expect(callArgs.clientApp?.username).to.equal('test@example.com');
267+
expect(callArgs.scopes).to.equal('api web');
265268
});
266269

267270
it('should pass undefined scopes to executeLoginFlow when linking client-app without scopes', async () => {
@@ -294,9 +297,9 @@ describe('org:login:web', () => {
294297

295298
// Verify that executeLoginFlow was called with the correct parameters
296299
expect(executeLoginFlowStub.callCount).to.equal(1);
297-
const callArgs = executeLoginFlowStub.getCall(0).args;
298-
expect(callArgs[2]).to.equal('MyApp'); // client-app should be the 3rd argument
299-
expect(callArgs[3]).to.equal('test@example.com'); // username should be the 4th argument
300-
expect(callArgs[4]).to.be.undefined; // scopes should be undefined when not provided
300+
const callArgs = executeLoginFlowStub.getCall(0).args[0] as ExecuteLoginFlowParams;
301+
expect(callArgs.clientApp?.name).to.equal('MyApp');
302+
expect(callArgs.clientApp?.username).to.equal('test@example.com');
303+
expect(callArgs.scopes).to.be.undefined;
301304
});
302305
});

yarn.lock

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -583,22 +583,14 @@
583583
"@smithy/types" "^4.9.0"
584584
tslib "^2.6.2"
585585

586-
"@aws-sdk/types@3.936.0":
586+
"@aws-sdk/types@3.936.0", "@aws-sdk/types@^3.222.0":
587587
version "3.936.0"
588588
resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.936.0.tgz#ecd3a4bec1a1bd4df834ab21fe52a76e332dc27a"
589589
integrity sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==
590590
dependencies:
591591
"@smithy/types" "^4.9.0"
592592
tslib "^2.6.2"
593593

594-
"@aws-sdk/types@^3.222.0":
595-
version "3.910.0"
596-
resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.910.0.tgz#1707a9f5d36d828789173fcd5622a5684cf67b2f"
597-
integrity sha512-o67gL3vjf4nhfmuSUNNkit0d62QJEwwHLxucwVJkR/rw9mfUtAWsgBs8Tp16cdUbMgsyQtCQilL8RAJDoGtadQ==
598-
dependencies:
599-
"@smithy/types" "^4.7.1"
600-
tslib "^2.6.2"
601-
602594
"@aws-sdk/util-arn-parser@3.893.0":
603595
version "3.893.0"
604596
resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.893.0.tgz#fcc9b792744b9da597662891c2422dda83881d8d"
@@ -1144,16 +1136,11 @@
11441136
chardet "^2.1.1"
11451137
iconv-lite "^0.7.0"
11461138

1147-
"@inquirer/figures@^1.0.15":
1139+
"@inquirer/figures@^1.0.15", "@inquirer/figures@^1.0.5":
11481140
version "1.0.15"
11491141
resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.15.tgz#dbb49ed80df11df74268023b496ac5d9acd22b3a"
11501142
integrity sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==
11511143

1152-
"@inquirer/figures@^1.0.5":
1153-
version "1.0.13"
1154-
resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.13.tgz#ad0afd62baab1c23175115a9b62f511b6a751e45"
1155-
integrity sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==
1156-
11571144
"@inquirer/input@^2.2.4", "@inquirer/input@^2.3.0":
11581145
version "2.3.0"
11591146
resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-2.3.0.tgz#9b99022f53780fecc842908f3f319b52a5a16865"
@@ -1333,10 +1320,10 @@
13331320
"@jridgewell/resolve-uri" "^3.1.0"
13341321
"@jridgewell/sourcemap-codec" "^1.4.14"
13351322

1336-
"@jsforce/jsforce-node@^3.10.8":
1337-
version "3.10.8"
1338-
resolved "https://registry.yarnpkg.com/@jsforce/jsforce-node/-/jsforce-node-3.10.8.tgz#f13903a0885fa3501a513512984cf9a717aebb9a"
1339-
integrity sha512-XGD/ivZz+htN5SgctFyEZ+JNG6C8FXzaEwvPbRSdsIy/hpWlexY38XtTpdT5xX3KnYSnOE4zA1M/oIbTm7RD/Q==
1323+
"@jsforce/jsforce-node@^3.10.10", "@jsforce/jsforce-node@^3.10.8":
1324+
version "3.10.10"
1325+
resolved "https://registry.yarnpkg.com/@jsforce/jsforce-node/-/jsforce-node-3.10.10.tgz#2d7bb77d1d739712733a30de7e9c941d2127bc4a"
1326+
integrity sha512-/zUOX9kapwk8lyjmTYgXlBF+GbqcEpb0zrkDfX9i94xu5cvzERZxRHqSSaS/IImoDmvoSbatFSVfB7Y4lmANOw==
13401327
dependencies:
13411328
"@sindresorhus/is" "^4"
13421329
base64url "^3.0.1"
@@ -1538,12 +1525,12 @@
15381525
strip-ansi "6.0.1"
15391526
ts-retry-promise "^0.8.1"
15401527

1541-
"@salesforce/core@8.23.4", "@salesforce/core@^8.18.7", "@salesforce/core@^8.23.1", "@salesforce/core@^8.23.3", "@salesforce/core@^8.23.4", "@salesforce/core@^8.5.1", "@salesforce/core@^8.8.0":
1542-
version "8.23.4"
1543-
resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.23.4.tgz#f1fa18eace08f685e72975a09d96e7f6958ca3b4"
1544-
integrity sha512-+JZMFD76P7X8fLSrHJRi9+ygjTehqZqJRXxmNq51miqIHY1Xlb0qH/yr9u5QEGsFIOZ8H8oStl/Zj+ZbrFs0vw==
1528+
"@salesforce/core@^8.18.7", "@salesforce/core@^8.23.1", "@salesforce/core@^8.23.3", "@salesforce/core@^8.23.4", "@salesforce/core@^8.23.5", "@salesforce/core@^8.5.1", "@salesforce/core@^8.8.0":
1529+
version "8.23.5"
1530+
resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.23.5.tgz#fc4a18a814ff3c6c0c3a138a0369441595ef74a2"
1531+
integrity sha512-EOA4JzvYk5KZ7YJ6mnBrHCrR0e1x7ellb6e8s4/+kIGGYU8mMnD0PYIUnc2jjYKXujY1hPgdQh39NLBQiQmt8g==
15451532
dependencies:
1546-
"@jsforce/jsforce-node" "^3.10.8"
1533+
"@jsforce/jsforce-node" "^3.10.10"
15471534
"@salesforce/kit" "^3.2.4"
15481535
"@salesforce/schemas" "^1.10.3"
15491536
"@salesforce/ts-types" "^2.0.12"
@@ -2130,14 +2117,7 @@
21302117
"@smithy/util-stream" "^4.5.6"
21312118
tslib "^2.6.2"
21322119

2133-
"@smithy/types@^4.7.1":
2134-
version "4.8.0"
2135-
resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.8.0.tgz#e6f65e712478910b74747081e6046e68159f767d"
2136-
integrity sha512-QpELEHLO8SsQVtqP+MkEgCYTFW0pleGozfs3cZ183ZBj9z3VC1CX1/wtFMK64p+5bhtZo41SeLK1rBRtd25nHQ==
2137-
dependencies:
2138-
tslib "^2.6.2"
2139-
2140-
"@smithy/types@^4.9.0":
2120+
"@smithy/types@^4.7.1", "@smithy/types@^4.9.0":
21412121
version "4.9.0"
21422122
resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.9.0.tgz#c6636ddfa142e1ddcb6e4cf5f3e1a628d420486f"
21432123
integrity sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA==
@@ -8280,12 +8260,7 @@ yocto-queue@^0.1.0:
82808260
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
82818261
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
82828262

8283-
yoctocolors-cjs@^2.1.2:
8284-
version "2.1.2"
8285-
resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242"
8286-
integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==
8287-
8288-
yoctocolors-cjs@^2.1.3:
8263+
yoctocolors-cjs@^2.1.2, yoctocolors-cjs@^2.1.3:
82898264
version "2.1.3"
82908265
resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa"
82918266
integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==

0 commit comments

Comments
 (0)