From 822d9afe600101d85386a2b13208366636218959 Mon Sep 17 00:00:00 2001 From: Priya Date: Tue, 25 Jun 2024 12:53:08 +0530 Subject: [PATCH 1/6] fix(meeting): fetching captcha details within meeting object --- src/MeetingsSDKAdapter.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/MeetingsSDKAdapter.js b/src/MeetingsSDKAdapter.js index 0b859bd1..1a7cce89 100644 --- a/src/MeetingsSDKAdapter.js +++ b/src/MeetingsSDKAdapter.js @@ -544,7 +544,10 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { */ createMeeting(destination) { const newMeeting$ = from(this.datasource.meetings.create(destination)).pipe( - map(({id, meetingInfo: {meetingName}, passwordStatus}) => ({ + tap((meeting) => { + console.log('pkesari_meeting object: ', meeting); + }), + map(({id, meetingInfo: {meetingName}, passwordStatus}, requiredCaptcha) => ({ ID: id, title: meetingName, localAudio: { @@ -559,6 +562,7 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { stream: null, }, passwordRequired: passwordStatus === 'REQUIRED', + requiredCaptcha, remoteAudio: null, remoteVideo: null, remoteShare: null, @@ -1406,4 +1410,10 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { async clearInvalidHostKeyFlag(ID) { await this.updateMeeting(ID, async () => ({invalidHostKey: false})); } + + async refreshCaptcha(ID) { + const sdkMeeting = this.fetchMeeting(ID); + + await sdkMeeting.refreshCaptcha(); + } } From a5c107f315c47db6e983a4240be5e05b31839994 Mon Sep 17 00:00:00 2001 From: Priya Date: Wed, 26 Jun 2024 01:27:20 +0530 Subject: [PATCH 2/6] fix(meeting): updated changes with more correct approach --- src/MeetingsSDKAdapter.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/MeetingsSDKAdapter.js b/src/MeetingsSDKAdapter.js index 1a7cce89..96fed33c 100644 --- a/src/MeetingsSDKAdapter.js +++ b/src/MeetingsSDKAdapter.js @@ -544,10 +544,7 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { */ createMeeting(destination) { const newMeeting$ = from(this.datasource.meetings.create(destination)).pipe( - tap((meeting) => { - console.log('pkesari_meeting object: ', meeting); - }), - map(({id, meetingInfo: {meetingName}, passwordStatus}, requiredCaptcha) => ({ + map(({id, meetingInfo: {meetingName}, passwordStatus}) => ({ ID: id, title: meetingName, localAudio: { @@ -562,7 +559,6 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { stream: null, }, passwordRequired: passwordStatus === 'REQUIRED', - requiredCaptcha, remoteAudio: null, remoteVideo: null, remoteShare: null, @@ -638,7 +634,26 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { const sdkMeeting = this.fetchMeeting(ID); if (sdkMeeting.passwordStatus === 'REQUIRED') { - await sdkMeeting.verifyPassword(options.hostKey || options.password); + sdkMeeting.verifyPassword(options.hostKey || options.password).then((res) => { + console.log('pkesari_response from verify password: ', res); + if (!res.isPasswordValid) { + this.updateMeeting(ID, () => ( + { + failureReason: res.failureReason, + invalidPassword: true, + ...(res.requiredCaptcha && { + requiredCaptcha: { + captchaId: res.requiredCaptcha.captchaId, + refreshURL: res.requiredCaptcha.refreshURL, + verificationAudioURL: res.requiredCaptcha.verificationAudioURL, + verificationImageURL: res.requiredCaptcha.verificationImageURL, + }, + }), + })); + } else { + logger.info('MEETING', ID, 'joinMeeting()', 'Password succesfully verified'); + } + }); } sdkMeeting.meetingFiniteStateMachine.reset(); logger.debug('MEETING', ID, 'joinMeeting()', ['calling sdkMeeting.join() with', {pin: options.password, moderator: false, name: options.name}]); From 326e6652715d78a22b6a092020af1d42c68f7cf5 Mon Sep 17 00:00:00 2001 From: Priya Date: Wed, 26 Jun 2024 12:59:55 +0530 Subject: [PATCH 3/6] fix(meeting): small corrections --- src/MeetingsSDKAdapter.js | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/MeetingsSDKAdapter.js b/src/MeetingsSDKAdapter.js index 96fed33c..f45e5464 100644 --- a/src/MeetingsSDKAdapter.js +++ b/src/MeetingsSDKAdapter.js @@ -562,6 +562,7 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { remoteAudio: null, remoteVideo: null, remoteShare: null, + requiredCaptcha: {}, showRoster: null, settings: { visible: false, @@ -634,26 +635,25 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { const sdkMeeting = this.fetchMeeting(ID); if (sdkMeeting.passwordStatus === 'REQUIRED') { - sdkMeeting.verifyPassword(options.hostKey || options.password).then((res) => { - console.log('pkesari_response from verify password: ', res); - if (!res.isPasswordValid) { - this.updateMeeting(ID, () => ( - { - failureReason: res.failureReason, - invalidPassword: true, - ...(res.requiredCaptcha && { - requiredCaptcha: { - captchaId: res.requiredCaptcha.captchaId, - refreshURL: res.requiredCaptcha.refreshURL, - verificationAudioURL: res.requiredCaptcha.verificationAudioURL, - verificationImageURL: res.requiredCaptcha.verificationImageURL, - }, - }), - })); - } else { - logger.info('MEETING', ID, 'joinMeeting()', 'Password succesfully verified'); - } - }); + const res = await sdkMeeting.verifyPassword(options.hostKey || options.password); + + if (!res.isPasswordValid) { + this.updateMeeting(ID, () => ( + { + failureReason: res.failureReason, + invalidPassword: true, + ...(res.requiredCaptcha && { + requiredCaptcha: { + captchaId: res.requiredCaptcha.captchaId, + refreshURL: res.requiredCaptcha.refreshURL, + verificationAudioURL: res.requiredCaptcha.verificationAudioURL, + verificationImageURL: res.requiredCaptcha.verificationImageURL, + }, + }), + })); + } else { + logger.info('MEETING', ID, 'joinMeeting()', 'Password succesfully verified'); + } } sdkMeeting.meetingFiniteStateMachine.reset(); logger.debug('MEETING', ID, 'joinMeeting()', ['calling sdkMeeting.join() with', {pin: options.password, moderator: false, name: options.name}]); From dfe440a879be9c88a05aada335f85300b47f471e Mon Sep 17 00:00:00 2001 From: Priya Date: Thu, 27 Jun 2024 00:38:22 +0530 Subject: [PATCH 4/6] fix(meeting): join meeting with captcha --- src/MeetingsSDKAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MeetingsSDKAdapter.js b/src/MeetingsSDKAdapter.js index f45e5464..1792b192 100644 --- a/src/MeetingsSDKAdapter.js +++ b/src/MeetingsSDKAdapter.js @@ -635,7 +635,7 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { const sdkMeeting = this.fetchMeeting(ID); if (sdkMeeting.passwordStatus === 'REQUIRED') { - const res = await sdkMeeting.verifyPassword(options.hostKey || options.password); + const res = await sdkMeeting.verifyPassword(options.hostKey || options.password, options.captcha); if (!res.isPasswordValid) { this.updateMeeting(ID, () => ( From 22ea21d0a249921a77c54a85d88b0834a585d7ae Mon Sep 17 00:00:00 2001 From: Priya Date: Thu, 27 Jun 2024 19:39:37 +0530 Subject: [PATCH 5/6] fix(meeting): tested refresh captcha --- src/MeetingsSDKAdapter.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/MeetingsSDKAdapter.js b/src/MeetingsSDKAdapter.js index 1792b192..9c68262a 100644 --- a/src/MeetingsSDKAdapter.js +++ b/src/MeetingsSDKAdapter.js @@ -652,7 +652,7 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { }), })); } else { - logger.info('MEETING', ID, 'joinMeeting()', 'Password succesfully verified'); + logger.info('MEETING', ID, 'joinMeeting()', 'Password successfully verified'); } } sdkMeeting.meetingFiniteStateMachine.reset(); @@ -1426,9 +1426,21 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { await this.updateMeeting(ID, async () => ({invalidHostKey: false})); } + /** + * Refreshes the captcha code. + * + * @async + * @param {string} ID Id of the meeting + */ async refreshCaptcha(ID) { + logger.debug('MEETING', ID, 'refreshCaptcha()', ['called with', {ID}]); const sdkMeeting = this.fetchMeeting(ID); await sdkMeeting.refreshCaptcha(); + this.updateMeeting(ID, () => ( + { + requiredCaptcha: sdkMeeting.requiredCaptcha, + } + )); } } From 6e79d8577db0443c4ce17553671bcb042e454cc7 Mon Sep 17 00:00:00 2001 From: Priya Date: Fri, 28 Jun 2024 14:49:04 +0530 Subject: [PATCH 6/6] fix(meeting): ut added --- src/MeetingsSDKAdapter.js | 8 +- src/MeetingsSDKAdapter.test.js | 110 +++++++++++++++++++++++++++ src/MeetingsSDKAdapter/testHelper.js | 1 + src/mockSdk.js | 4 + 4 files changed, 120 insertions(+), 3 deletions(-) diff --git a/src/MeetingsSDKAdapter.js b/src/MeetingsSDKAdapter.js index 9c68262a..9f84f916 100644 --- a/src/MeetingsSDKAdapter.js +++ b/src/MeetingsSDKAdapter.js @@ -635,7 +635,8 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { const sdkMeeting = this.fetchMeeting(ID); if (sdkMeeting.passwordStatus === 'REQUIRED') { - const res = await sdkMeeting.verifyPassword(options.hostKey || options.password, options.captcha); + const res = await sdkMeeting + .verifyPassword(options.hostKey || options.password, options.captcha); if (!res.isPasswordValid) { this.updateMeeting(ID, () => ( @@ -1372,6 +1373,7 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { deepMerge(meeting, updates); logger.debug('MEETING', ID, 'updateMeeting()', ['meeting updated with', EVENT_MEETING_UPDATED, 'event', 'meeting object', {meeting}]); + sdkMeeting.emit(EVENT_MEETING_UPDATED, meeting); } @@ -1436,8 +1438,8 @@ export default class MeetingsSDKAdapter extends MeetingsAdapter { logger.debug('MEETING', ID, 'refreshCaptcha()', ['called with', {ID}]); const sdkMeeting = this.fetchMeeting(ID); - await sdkMeeting.refreshCaptcha(); - this.updateMeeting(ID, () => ( + sdkMeeting.refreshCaptcha(); + await this.updateMeeting(ID, () => ( { requiredCaptcha: sdkMeeting.requiredCaptcha, } diff --git a/src/MeetingsSDKAdapter.test.js b/src/MeetingsSDKAdapter.test.js index 7367eaf6..a1f69c91 100644 --- a/src/MeetingsSDKAdapter.test.js +++ b/src/MeetingsSDKAdapter.test.js @@ -1087,4 +1087,114 @@ describe('Meetings SDK Adapter', () => { expect(mockSDKMeeting.emit.mock.calls[0][1]).toMatchObject({invalidHostKey: false}); }); }); + + describe('refreshCaptcha()', () => { + const mockCaptcha = { + captchaId: 'Captcha_c57280d4-6baf-4a27-87e9-290757754bb6', + verificationImageURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_c57280d4-6baf-4a27-87e9-290757754bb6/verificationCodeImage', + refreshURL: 'https://cisco.webex.com/captchaservice/v1/captchas/refresh?siteurl=cisco&captchaID=Captcha_c57280d4-6baf-4a27-87e9-290757754bb6', + verificationAudioURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_c57280d4-6baf-4a27-87e9-290757754bb6/verificationCodeAudio', + }; + + it('refreshes the captcha', async () => { + meetingsSDKAdapter.meetings[meetingID].requiredCaptcha = { + captchaId: 'Captcha_b40798d4-6baf-4a27-bf77-2907577524d6', + verificationImageURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_b40798d4-6baf-4a27-bf77-2907577524d6/verificationCodeImage', + refreshURL: 'https://cisco.webex.com/captchaservice/v1/captchas/refresh?siteurl=cisco&captchaID=Captcha_b40798d4-6baf-4a27-bf77-2907577524d6', + verificationAudioURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_b40798d4-6baf-4a27-bf77-2907577524d6/verificationCodeAudio', + }; + + mockSDKMeeting.requiredCaptcha = mockCaptcha; + + await meetingsSDKAdapter.refreshCaptcha(meetingID); + + expect(mockSDKMeeting.refreshCaptcha).toHaveBeenCalledWith(); + expect(mockSDKMeeting.emit).toHaveBeenCalledTimes(1); + expect(mockSDKMeeting.emit.mock.calls[0][0]).toBe('adapter:meeting:updated'); + expect(mockSDKMeeting.emit.mock.calls[0][1]).toMatchObject({requiredCaptcha: mockCaptcha}); + }); + }); + + describe('joinMeeting()', () => { + const verifyPasswordRes1 = { + failureReason: 'WRONG_PASSWORD', + isPasswordValid: false, + requiredCaptcha: { + captchaId: 'Captcha_c3c3009f-c844-4305-b1c4-6aed2a251247', + refreshURL: 'https://cisco.webex.com/captchaservice/v1/captchas/refresh?siteurl=cisco&captchaID=Captcha_c3c3009f-c844-4305-b1c4-6aed2a251247', + verificationAudioURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_c3c3009f-c844-4305-b1c4-6aed2a251247/verificationCodeAudio', + verificationImageURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_c3c3009f-c844-4305-b1c4-6aed2a251247/verificationCodeImage', + }, + }; + + const mockResponse1 = { + failureReason: 'WRONG_PASSWORD', + invalidPassword: true, + requiredCaptcha: { + captchaId: 'Captcha_c3c3009f-c844-4305-b1c4-6aed2a251247', + refreshURL: 'https://cisco.webex.com/captchaservice/v1/captchas/refresh?siteurl=cisco&captchaID=Captcha_c3c3009f-c844-4305-b1c4-6aed2a251247', + verificationAudioURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_c3c3009f-c844-4305-b1c4-6aed2a251247/verificationCodeAudio', + verificationImageURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_c3c3009f-c844-4305-b1c4-6aed2a251247/verificationCodeImage', + }, + }; + + const verifyPasswordRes2 = { + failureReason: 'WRONG_CAPTCHA', + isPasswordValid: false, + requiredCaptcha: { + captchaId: 'Captcha_e34a56d8-c75e-4424-9a34-b1dd28badd68', + refreshURL: 'https://cisco.webex.com/captchaservice/v1/captchas/refresh?siteurl=cisco&captchaID=Captcha_e34a56d8-c75e-4424-9a34-b1dd28badd68', + verificationAudioURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_e34a56d8-c75e-4424-9a34-b1dd28badd68/verificationCodeAudio', + verificationImageURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_e34a56d8-c75e-4424-9a34-b1dd28badd68/verificationCodeImage', + }, + }; + + const mockResponse2 = { + failureReason: 'WRONG_CAPTCHA', + invalidPassword: true, + requiredCaptcha: { + captchaId: 'Captcha_e34a56d8-c75e-4424-9a34-b1dd28badd68', + refreshURL: 'https://cisco.webex.com/captchaservice/v1/captchas/refresh?siteurl=cisco&captchaID=Captcha_e34a56d8-c75e-4424-9a34-b1dd28badd68', + verificationAudioURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_e34a56d8-c75e-4424-9a34-b1dd28badd68/verificationCodeAudio', + verificationImageURL: 'https://cisco.webex.com/captchaservice/v1/captchas/Captcha_e34a56d8-c75e-4424-9a34-b1dd28badd68/verificationCodeImage', + }, + }; + + it('joinMeeting with correct password with no captcha needed', async () => { + mockSDKMeeting.verifyPassword = jest.fn(() => Promise.resolve({ + failureReason: 'NONE', + isPasswordValid: true, + requiredCaptcha: null, + })); + await meetingsSDKAdapter.joinMeeting(meetingID, {password: 'BJzbHDKd347'}); + + expect(mockSDKMeeting.verifyPassword).toHaveBeenCalledWith('BJzbHDKd347', undefined); + expect(mockSDKMeeting.emit).not.toHaveBeenCalled(); + expect(mockSDKMeeting.join).toHaveBeenCalledTimes(1); + }); + + it('joinMeeting with incorrect password multiple times and receiving captcha code to be entered', async () => { + mockSDKMeeting.verifyPassword = jest.fn(() => Promise.resolve(verifyPasswordRes1)); + mockSDKMeeting.requiredCaptcha = verifyPasswordRes1.requiredCaptcha; + + await meetingsSDKAdapter.joinMeeting(meetingID, {password: 'fahdkwlr'}); + + expect(mockSDKMeeting.verifyPassword).toHaveBeenCalledWith('fahdkwlr', undefined); + expect(mockSDKMeeting.emit).toHaveBeenCalledTimes(1); + expect(mockSDKMeeting.emit.mock.calls[0][0]).toBe('adapter:meeting:updated'); + expect(mockSDKMeeting.emit.mock.calls[0][1]).toMatchObject(mockResponse1); + }); + + it('joinMeeting with correct password and incorrect captcha', async () => { + mockSDKMeeting.verifyPassword = jest.fn(() => Promise.resolve(verifyPasswordRes2)); + mockSDKMeeting.requiredCaptcha = verifyPasswordRes2.requiredCaptcha; + + await meetingsSDKAdapter.joinMeeting(meetingID, {password: 'BJzbHDKd347', captcha: 'pfucip'}); + + expect(mockSDKMeeting.verifyPassword).toHaveBeenCalledWith('BJzbHDKd347', 'pfucip'); + expect(mockSDKMeeting.emit).toHaveBeenCalledTimes(1); + expect(mockSDKMeeting.emit.mock.calls[0][0]).toBe('adapter:meeting:updated'); + expect(mockSDKMeeting.emit.mock.calls[0][1]).toMatchObject(mockResponse2); + }); + }); }); diff --git a/src/MeetingsSDKAdapter/testHelper.js b/src/MeetingsSDKAdapter/testHelper.js index cb5c7f0a..8d45d4e3 100644 --- a/src/MeetingsSDKAdapter/testHelper.js +++ b/src/MeetingsSDKAdapter/testHelper.js @@ -25,6 +25,7 @@ export function createTestMeetingsSDKAdapter() { remoteAudio: null, remoteVideo: null, remoteShare: null, + requiredCaptcha: {}, showRoster: null, settings: { visible: false, diff --git a/src/mockSdk.js b/src/mockSdk.js index 639fd4b2..8a4c7033 100644 --- a/src/mockSdk.js +++ b/src/mockSdk.js @@ -83,6 +83,9 @@ export const createMockSDKMeeting = () => ({ meetingInfo: { isWebexScheduled: true, }, + meetingFiniteStateMachine: { + reset: jest.fn(), + }, members: { membersCollection: { members: { @@ -174,6 +177,7 @@ export const createMockSDKMeeting = () => ({ canUpdateMedia: jest.fn(() => true), updateShare: jest.fn(() => Promise.resolve()), changeVideoLayout: jest.fn(() => Promise.resolve()), + refreshCaptcha: jest.fn(), }); export const mockSDKMembership = {