From 8de51d363560155e08a055d9e0027a0d562bf50c Mon Sep 17 00:00:00 2001 From: Ravali Rimmalapudi Date: Fri, 25 Jun 2021 13:38:59 +0530 Subject: [PATCH 1/5] chore: CLI Profile Update - Using config file instead of the system keychain --- src/commands/profiles/create.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/commands/profiles/create.js b/src/commands/profiles/create.js index 16ce12aaa..aef0790fc 100644 --- a/src/commands/profiles/create.js +++ b/src/commands/profiles/create.js @@ -218,6 +218,17 @@ class ProfilesCreate extends BaseCommand { } } + async removeKeytarKeysByProfileId(profileId) { + if (this.userConfig.projects.find((p) => p.id === profileId)) { + const removed = await this.secureStorage.removeCredentials(profileId); + if (removed === true) { + this.logger.info('Deleted key from keytar.'); + } else { + this.logger.warn('Could not delete key from keytar.'); + } + } + } + async saveCredentials() { const apiKeyFriendlyName = this.getApiKeyFriendlyName(); let apiKey = null; @@ -230,7 +241,7 @@ class ProfilesCreate extends BaseCommand { this.logger.debug(error); throw new TwilioCliError('Could not create an API Key.'); } - + await this.removeKeytarKeysByProfileId(this.profileId); this.userConfig.addProfile(this.profileId, this.accountSid, this.region, apiKey.sid, apiKey.secret); const configSavedMessage = await this.configFile.save(this.userConfig); From dac8bcb840e85c243d8e4d19e35c3c33fbb1dbc5 Mon Sep 17 00:00:00 2001 From: Ravali Rimmalapudi Date: Fri, 25 Jun 2021 17:32:17 +0530 Subject: [PATCH 2/5] Added the test cases. --- test/commands/profiles/create.test.js | 43 ++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/test/commands/profiles/create.test.js b/test/commands/profiles/create.test.js index 3c7d22127..d12c84770 100644 --- a/test/commands/profiles/create.test.js +++ b/test/commands/profiles/create.test.js @@ -11,9 +11,15 @@ const helpMessages = require('../../../src/services/messaging/help-messages'); describe('commands', () => { describe('profiles', () => { describe('create', () => { - const createTest = (commandArgs = [], profileId = 'default') => + const createTest = (commandArgs = [], { profileId = 'default', addProjects = 0, removeCred = true } = {}) => test .twilioFakeProfile(ConfigData) + .do((ctx) => { + ctx.userConfig = new ConfigData(); + for (let i = 1; i <= addProjects; i++) { + ctx.userConfig.addProject(`profile${i}`, constants.FAKE_ACCOUNT_SID); + } + }) .twilioCliEnv(Config) .twilioCreateCommand(ProfilesCreate, commandArgs) .stdout() @@ -35,6 +41,11 @@ describe('commands', () => { overwrite: true, }); ctx.testCmd.inquirer.prompt = fakePrompt; + }) + .do((ctx) => { + ctx.testCmd.secureStorage.removeCredentials = () => { + return removeCred; + }; }); const mockSuccess = (api) => { @@ -65,6 +76,36 @@ describe('commands', () => { ); }); + createTest([], { profileId: 'profile1', addProjects: 1 }) + .nock('https://api.twilio.com', mockSuccess) + .do((ctx) => ctx.testCmd.run()) + .it('runs profiles:create with existing profile in Projects', (ctx) => { + expect(ctx.stdout).to.equal(''); + expect(ctx.stderr).to.contain(helpMessages.AUTH_TOKEN_NOT_SAVED); + expect(ctx.stderr).to.contain('Saved profile1.'); + expect(ctx.stderr).to.contain('Deleted key from keytar.'); + expect(ctx.stderr).to.contain('configuration saved'); + expect(ctx.stderr).to.contain(`Created API Key ${constants.FAKE_API_KEY} and stored the secret in Config.`); + expect(ctx.stderr).to.contain( + `See: https://www.twilio.com/console/runtime/api-keys/${constants.FAKE_API_KEY}`, + ); + }); + + createTest([], { profileId: 'profile1', addProjects: 1, removeCred: false }) + .nock('https://api.twilio.com', mockSuccess) + .do((ctx) => ctx.testCmd.run()) + .it('runs profiles:create with existing profile in Projects with Keytar remove failed', (ctx) => { + expect(ctx.stdout).to.equal(''); + expect(ctx.stderr).to.contain(helpMessages.AUTH_TOKEN_NOT_SAVED); + expect(ctx.stderr).to.contain('Saved profile1.'); + expect(ctx.stderr).to.contain('Could not delete key from keytar'); + expect(ctx.stderr).to.contain('configuration saved'); + expect(ctx.stderr).to.contain(`Created API Key ${constants.FAKE_API_KEY} and stored the secret in Config.`); + expect(ctx.stderr).to.contain( + `See: https://www.twilio.com/console/runtime/api-keys/${constants.FAKE_API_KEY}`, + ); + }); + createTest() .do((ctx) => { sinon.stub(os, 'hostname').returns('some_super_long_fake_hostname'); From d9187632607809c344e5eb3362e228b877411ba2 Mon Sep 17 00:00:00 2001 From: Ravali Rimmalapudi Date: Mon, 28 Jun 2021 12:04:52 +0530 Subject: [PATCH 3/5] Addressed the review comments --- test/commands/profiles/create.test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/commands/profiles/create.test.js b/test/commands/profiles/create.test.js index d12c84770..edbd02a8f 100644 --- a/test/commands/profiles/create.test.js +++ b/test/commands/profiles/create.test.js @@ -11,13 +11,13 @@ const helpMessages = require('../../../src/services/messaging/help-messages'); describe('commands', () => { describe('profiles', () => { describe('create', () => { - const createTest = (commandArgs = [], { profileId = 'default', addProjects = 0, removeCred = true } = {}) => + const createTest = (commandArgs = [], { profileId = 'default', addProjects = [], removeCred = true } = {}) => test .twilioFakeProfile(ConfigData) .do((ctx) => { ctx.userConfig = new ConfigData(); - for (let i = 1; i <= addProjects; i++) { - ctx.userConfig.addProject(`profile${i}`, constants.FAKE_ACCOUNT_SID); + for (let i = 0; i <=addProjects.length; i++) { + ctx.userConfig.addProject(addProjects[i], constants.FAKE_ACCOUNT_SID); } }) .twilioCliEnv(Config) @@ -76,7 +76,7 @@ describe('commands', () => { ); }); - createTest([], { profileId: 'profile1', addProjects: 1 }) + createTest([], { profileId: 'profile1', addProjects: ['profile1'] }) .nock('https://api.twilio.com', mockSuccess) .do((ctx) => ctx.testCmd.run()) .it('runs profiles:create with existing profile in Projects', (ctx) => { @@ -91,7 +91,7 @@ describe('commands', () => { ); }); - createTest([], { profileId: 'profile1', addProjects: 1, removeCred: false }) + createTest([], { profileId: 'profile1', addProjects: ['profile1'], removeCred: false }) .nock('https://api.twilio.com', mockSuccess) .do((ctx) => ctx.testCmd.run()) .it('runs profiles:create with existing profile in Projects with Keytar remove failed', (ctx) => { From e621ea63977f722bfb0b1f155fe4bc60b901917c Mon Sep 17 00:00:00 2001 From: Ravali Rimmalapudi Date: Mon, 28 Jun 2021 12:11:07 +0530 Subject: [PATCH 4/5] Added the missing alignment. --- test/commands/profiles/create.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/commands/profiles/create.test.js b/test/commands/profiles/create.test.js index edbd02a8f..c15d9b932 100644 --- a/test/commands/profiles/create.test.js +++ b/test/commands/profiles/create.test.js @@ -16,7 +16,7 @@ describe('commands', () => { .twilioFakeProfile(ConfigData) .do((ctx) => { ctx.userConfig = new ConfigData(); - for (let i = 0; i <=addProjects.length; i++) { + for (let i = 0; i <= addProjects.length; i++) { ctx.userConfig.addProject(addProjects[i], constants.FAKE_ACCOUNT_SID); } }) From 8f7b1369d62070f21e8bfd0aa80ed4f66a977dfd Mon Sep 17 00:00:00 2001 From: Ravali Rimmalapudi Date: Mon, 28 Jun 2021 19:37:34 +0530 Subject: [PATCH 5/5] Addressed the review comments --- src/commands/profiles/create.js | 22 +++++++++++----------- test/commands/profiles/create.test.js | 6 ++---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/commands/profiles/create.js b/src/commands/profiles/create.js index aef0790fc..03663d801 100644 --- a/src/commands/profiles/create.js +++ b/src/commands/profiles/create.js @@ -218,17 +218,6 @@ class ProfilesCreate extends BaseCommand { } } - async removeKeytarKeysByProfileId(profileId) { - if (this.userConfig.projects.find((p) => p.id === profileId)) { - const removed = await this.secureStorage.removeCredentials(profileId); - if (removed === true) { - this.logger.info('Deleted key from keytar.'); - } else { - this.logger.warn('Could not delete key from keytar.'); - } - } - } - async saveCredentials() { const apiKeyFriendlyName = this.getApiKeyFriendlyName(); let apiKey = null; @@ -250,6 +239,17 @@ class ProfilesCreate extends BaseCommand { ); this.logger.info(configSavedMessage); } + + async removeKeytarKeysByProfileId(profileId) { + if (this.userConfig.projects.find((p) => p.id === profileId)) { + const removed = await this.secureStorage.removeCredentials(profileId); + if (removed === true) { + this.logger.info('Deleted key from keytar.'); + } else { + this.logger.warn(`Could not delete ${profileId} key from keytar.`); + } + } + } } ProfilesCreate.aliases = ['profiles:add', 'login']; diff --git a/test/commands/profiles/create.test.js b/test/commands/profiles/create.test.js index c15d9b932..33142d9ad 100644 --- a/test/commands/profiles/create.test.js +++ b/test/commands/profiles/create.test.js @@ -16,9 +16,7 @@ describe('commands', () => { .twilioFakeProfile(ConfigData) .do((ctx) => { ctx.userConfig = new ConfigData(); - for (let i = 0; i <= addProjects.length; i++) { - ctx.userConfig.addProject(addProjects[i], constants.FAKE_ACCOUNT_SID); - } + addProjects.forEach((project) => ctx.userConfig.addProject(project, constants.FAKE_ACCOUNT_SID)); }) .twilioCliEnv(Config) .twilioCreateCommand(ProfilesCreate, commandArgs) @@ -98,7 +96,7 @@ describe('commands', () => { expect(ctx.stdout).to.equal(''); expect(ctx.stderr).to.contain(helpMessages.AUTH_TOKEN_NOT_SAVED); expect(ctx.stderr).to.contain('Saved profile1.'); - expect(ctx.stderr).to.contain('Could not delete key from keytar'); + expect(ctx.stderr).to.contain('Could not delete profile1 key from keytar.'); expect(ctx.stderr).to.contain('configuration saved'); expect(ctx.stderr).to.contain(`Created API Key ${constants.FAKE_API_KEY} and stored the secret in Config.`); expect(ctx.stderr).to.contain(