From 1017903ee106e4a559d6c7dc0d18bfa5b4f27f2c Mon Sep 17 00:00:00 2001 From: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com> Date: Thu, 8 Jun 2023 14:27:49 +0530 Subject: [PATCH] fix: Adds domain option to user cookies set by SDK [CW-352] (#7070) * fix: Adds domain option to user cookies set by SDK * Adds domain to init event from chatwootSettings variable * Testing multiple domains on heroku * Updates with sdk from staging * Removes sdk init code * Testing why cookie is not getting set * Cleans up testing code * Refactors code to fix codeclimate issues * Update app/javascript/sdk/cookieHelpers.js Co-authored-by: Shivam Mishra * Adds test cases for setCookieWithDomain --------- Co-authored-by: Muhsin Keloth Co-authored-by: Shivam Mishra --- app/javascript/packs/sdk.js | 9 ++- app/javascript/sdk/IFrameHelper.js | 21 +++-- app/javascript/sdk/cookieHelpers.js | 15 ++++ .../sdk/specs/cookieHelpers.spec.js | 77 +++++++++++++++++++ app/views/widget_tests/index.html.erb | 1 + 5 files changed, 109 insertions(+), 14 deletions(-) diff --git a/app/javascript/packs/sdk.js b/app/javascript/packs/sdk.js index 912e7ca7e..9bb8314ca 100755 --- a/app/javascript/packs/sdk.js +++ b/app/javascript/packs/sdk.js @@ -11,6 +11,7 @@ import { hasUserKeys, } from '../sdk/cookieHelpers'; import { addClasses, removeClasses } from '../sdk/DOMHelpers'; +import { setCookieWithDomain } from '../sdk/cookieHelpers'; import { SDK_SET_BUBBLE_VISIBILITY } from 'shared/constants/sharedFrameEvents'; const runSDK = ({ baseUrl, websiteToken }) => { if (window.$chatwoot) { @@ -19,6 +20,7 @@ const runSDK = ({ baseUrl, websiteToken }) => { const chatwootSettings = window.chatwootSettings || {}; let locale = chatwootSettings.locale; + let baseDomain = chatwootSettings.baseDomain; if (chatwootSettings.useBrowserLanguage) { locale = window.navigator.language.replace('-', '_'); @@ -26,6 +28,7 @@ const runSDK = ({ baseUrl, websiteToken }) => { window.$chatwoot = { baseUrl, + baseDomain, hasLoaded: false, hideMessageBubble: chatwootSettings.hideMessageBubble || false, isOpen: false, @@ -90,9 +93,9 @@ const runSDK = ({ baseUrl, websiteToken }) => { window.$chatwoot.identifier = identifier; window.$chatwoot.user = user; IFrameHelper.sendMessage('set-user', { identifier, user }); - Cookies.set(userCookieName, hashToBeStored, { - expires: 365, - sameSite: 'Lax', + + setCookieWithDomain(userCookieName, hashToBeStored, { + baseDomain, }); }, diff --git a/app/javascript/sdk/IFrameHelper.js b/app/javascript/sdk/IFrameHelper.js index 9ded2c9bf..9d51599b9 100644 --- a/app/javascript/sdk/IFrameHelper.js +++ b/app/javascript/sdk/IFrameHelper.js @@ -29,7 +29,7 @@ import { CHATWOOT_READY, } from '../widget/constants/sdkEvents'; import { SET_USER_ERROR } from '../widget/constants/errorTypes'; -import { getUserCookieName } from './cookieHelpers'; +import { getUserCookieName, setCookieWithDomain } from './cookieHelpers'; import { getAlertAudio, initOnEvents, @@ -38,17 +38,16 @@ import { isFlatWidgetStyle } from './settingsHelper'; import { popoutChatWindow } from '../widget/helpers/popoutHelper'; import addHours from 'date-fns/addHours'; -const updateAuthCookie = cookieContent => - Cookies.set('cw_conversation', cookieContent, { - expires: 365, - sameSite: 'Lax', +const updateAuthCookie = (cookieContent, baseDomain = '') => + setCookieWithDomain('cw_conversation', cookieContent, { + baseDomain, }); -const updateCampaignReadStatus = () => { +const updateCampaignReadStatus = baseDomain => { const expireBy = addHours(new Date(), 1); - Cookies.set('cw_snooze_campaigns_till', Number(expireBy), { + setCookieWithDomain('cw_snooze_campaigns_till', Number(expireBy), { expires: expireBy, - sameSite: 'Lax', + baseDomain, }); }; @@ -154,7 +153,7 @@ export const IFrameHelper = { events: { loaded: message => { - updateAuthCookie(message.config.authToken); + updateAuthCookie(message.config.authToken, window.$chatwoot.baseDomain); window.$chatwoot.hasLoaded = true; const campaignsSnoozedTill = Cookies.get('cw_snooze_campaigns_till'); IFrameHelper.sendMessage('config-set', { @@ -200,11 +199,11 @@ export const IFrameHelper = { }, setAuthCookie({ data: { widgetAuthToken } }) { - updateAuthCookie(widgetAuthToken); + updateAuthCookie(widgetAuthToken, window.$chatwoot.baseDomain); }, setCampaignReadOn() { - updateCampaignReadStatus(); + updateCampaignReadStatus(window.$chatwoot.baseDomain); }, toggleBubble: state => { diff --git a/app/javascript/sdk/cookieHelpers.js b/app/javascript/sdk/cookieHelpers.js index afdc12cc2..64a7afbf7 100644 --- a/app/javascript/sdk/cookieHelpers.js +++ b/app/javascript/sdk/cookieHelpers.js @@ -1,4 +1,5 @@ import md5 from 'md5'; +import Cookies from 'js-cookie'; const REQUIRED_USER_KEYS = ['avatar_url', 'email', 'name']; const ALLOWED_USER_ATTRIBUTES = [...REQUIRED_USER_KEYS, 'identifier_hash']; @@ -21,3 +22,17 @@ export const computeHashForUserData = (...args) => md5(getUserString(...args)); export const hasUserKeys = user => REQUIRED_USER_KEYS.reduce((acc, key) => acc || !!user[key], false); + +export const setCookieWithDomain = ( + name, + value, + { expires = 365, baseDomain = undefined } = {} +) => { + const cookieOptions = { + expires, + sameSite: 'Lax', + domain: baseDomain, + }; + + Cookies.set(name, value, cookieOptions); +}; diff --git a/app/javascript/sdk/specs/cookieHelpers.spec.js b/app/javascript/sdk/specs/cookieHelpers.spec.js index 103224760..7da09315f 100644 --- a/app/javascript/sdk/specs/cookieHelpers.spec.js +++ b/app/javascript/sdk/specs/cookieHelpers.spec.js @@ -1,7 +1,9 @@ +import Cookies from 'js-cookie'; import { getUserCookieName, getUserString, hasUserKeys, + setCookieWithDomain, } from '../cookieHelpers'; describe('#getUserCookieName', () => { @@ -47,3 +49,78 @@ describe('#hasUserKeys', () => { expect(hasUserKeys({ avatar_url: 'randomValue' })).toBe(true); }); }); + +// Mock the 'set' method of the 'Cookies' object +jest.mock('js-cookie', () => ({ + set: jest.fn(), +})); + +describe('setCookieWithDomain', () => { + afterEach(() => { + // Clear mock calls after each test + Cookies.set.mockClear(); + }); + + it('should set a cookie with default parameters', () => { + setCookieWithDomain('myCookie', 'cookieValue'); + + expect(Cookies.set).toHaveBeenCalledWith( + 'myCookie', + 'cookieValue', + expect.objectContaining({ + expires: 365, + sameSite: 'Lax', + domain: undefined, + }) + ); + }); + + it('should set a cookie with custom expiration and sameSite attribute', () => { + setCookieWithDomain('myCookie', 'cookieValue', { + expires: 30, + }); + + expect(Cookies.set).toHaveBeenCalledWith( + 'myCookie', + 'cookieValue', + expect.objectContaining({ + expires: 30, + sameSite: 'Lax', + domain: undefined, + }) + ); + }); + + it('should set a cookie with a specific base domain', () => { + setCookieWithDomain('myCookie', 'cookieValue', { + baseDomain: 'example.com', + }); + + expect(Cookies.set).toHaveBeenCalledWith( + 'myCookie', + 'cookieValue', + expect.objectContaining({ + expires: 365, + sameSite: 'Lax', + domain: 'example.com', + }) + ); + }); + + it('should set a cookie with custom expiration, sameSite attribute, and specific base domain', () => { + setCookieWithDomain('myCookie', 'cookieValue', { + expires: 7, + baseDomain: 'example.com', + }); + + expect(Cookies.set).toHaveBeenCalledWith( + 'myCookie', + 'cookieValue', + expect.objectContaining({ + expires: 7, + sameSite: 'Lax', + domain: 'example.com', + }) + ); + }); +}); diff --git a/app/views/widget_tests/index.html.erb b/app/views/widget_tests/index.html.erb index 3c9b8624d..aa9415c69 100644 --- a/app/views/widget_tests/index.html.erb +++ b/app/views/widget_tests/index.html.erb @@ -14,6 +14,7 @@ window.chatwootSettings = { hideMessageBubble: false, + // baseDomain: '.loca.lt', position: '<%= @widget_position %>', locale: 'en', useBrowserLanguage: true,