chore: Add a check for data diff in setUser call (#1272)
This commit is contained in:
parent
701eccb35c
commit
dbd1720aeb
4 changed files with 114 additions and 9 deletions
|
@ -1,6 +1,31 @@
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import { IFrameHelper } from '../sdk/IFrameHelper';
|
import { IFrameHelper } from '../sdk/IFrameHelper';
|
||||||
import { getBubbleView } from '../sdk/bubbleHelpers';
|
import { getBubbleView } from '../sdk/bubbleHelpers';
|
||||||
|
import md5 from 'md5';
|
||||||
|
|
||||||
|
const ALLOWED_LIST_OF_SET_USER_ATTRIBUTES = ['avatar_url', 'email', 'name'];
|
||||||
|
|
||||||
|
export const getUserCookieName = () => {
|
||||||
|
const SET_USER_COOKIE_PREFIX = 'cw_user_';
|
||||||
|
const { websiteToken: websiteIdentifier } = window.$chatwoot;
|
||||||
|
return `${SET_USER_COOKIE_PREFIX}${websiteIdentifier}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getUserString = ({ identifier = '', user }) => {
|
||||||
|
const userStringWithSortedKeys = ALLOWED_LIST_OF_SET_USER_ATTRIBUTES.reduce(
|
||||||
|
(acc, key) => `${acc}${key}${user[key] || ''}`,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
return `${userStringWithSortedKeys}identifier${identifier}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const computeHashForUserData = (...args) => md5(getUserString(...args));
|
||||||
|
|
||||||
|
export const hasUserKeys = user =>
|
||||||
|
ALLOWED_LIST_OF_SET_USER_ATTRIBUTES.reduce(
|
||||||
|
(acc, key) => acc || !!user[key],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
const runSDK = ({ baseUrl, websiteToken }) => {
|
const runSDK = ({ baseUrl, websiteToken }) => {
|
||||||
const chatwootSettings = window.chatwootSettings || {};
|
const chatwootSettings = window.chatwootSettings || {};
|
||||||
|
@ -21,16 +46,30 @@ const runSDK = ({ baseUrl, websiteToken }) => {
|
||||||
},
|
},
|
||||||
|
|
||||||
setUser(identifier, user) {
|
setUser(identifier, user) {
|
||||||
if (typeof identifier === 'string' || typeof identifier === 'number') {
|
if (typeof identifier !== 'string' && typeof identifier !== 'number') {
|
||||||
window.$chatwoot.identifier = identifier;
|
|
||||||
window.$chatwoot.user = user || {};
|
|
||||||
IFrameHelper.sendMessage('set-user', {
|
|
||||||
identifier,
|
|
||||||
user: window.$chatwoot.user,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new Error('Identifier should be a string or a number');
|
throw new Error('Identifier should be a string or a number');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasUserKeys()) {
|
||||||
|
throw new Error(
|
||||||
|
'User object should have one of the keys [avatar_url, email, name]'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userCookieName = getUserCookieName();
|
||||||
|
const existingCookieValue = Cookies.get(userCookieName);
|
||||||
|
const hashToBeStored = computeHashForUserData({ identifier, user });
|
||||||
|
if (hashToBeStored === existingCookieValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.$chatwoot.identifier = identifier;
|
||||||
|
window.$chatwoot.user = user;
|
||||||
|
IFrameHelper.sendMessage('set-user', { identifier, user });
|
||||||
|
Cookies.set(userCookieName, hashToBeStored, {
|
||||||
|
expires: 365,
|
||||||
|
sameSite: 'Lax',
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setCustomAttributes(customAttributes = {}) {
|
setCustomAttributes(customAttributes = {}) {
|
||||||
|
@ -69,6 +108,8 @@ const runSDK = ({ baseUrl, websiteToken }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
Cookies.remove('cw_conversation');
|
Cookies.remove('cw_conversation');
|
||||||
|
Cookies.remove(getUserCookieName());
|
||||||
|
|
||||||
const iframe = IFrameHelper.getAppFrame();
|
const iframe = IFrameHelper.getAppFrame();
|
||||||
iframe.src = IFrameHelper.getUrl({
|
iframe.src = IFrameHelper.getUrl({
|
||||||
baseUrl: window.$chatwoot.baseUrl,
|
baseUrl: window.$chatwoot.baseUrl,
|
||||||
|
|
44
app/javascript/specs/packs/sdk.spec.js
Normal file
44
app/javascript/specs/packs/sdk.spec.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { getUserCookieName, getUserString, hasUserKeys } from '../../packs/sdk';
|
||||||
|
|
||||||
|
describe('#getUserCookieName', () => {
|
||||||
|
it('returns correct cookie name', () => {
|
||||||
|
global.$chatwoot = { websiteToken: '123456' };
|
||||||
|
expect(getUserCookieName()).toBe('cw_user_123456');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#getUserString', () => {
|
||||||
|
it('returns correct user string', () => {
|
||||||
|
expect(
|
||||||
|
getUserString({
|
||||||
|
user: {
|
||||||
|
name: 'Pranav',
|
||||||
|
email: 'pranav@example.com',
|
||||||
|
avatar_url: 'https://images.chatwoot.com/placeholder',
|
||||||
|
},
|
||||||
|
identifier: '12345',
|
||||||
|
})
|
||||||
|
).toBe(
|
||||||
|
'avatar_urlhttps://images.chatwoot.com/placeholderemailpranav@example.comnamePranavidentifier12345'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getUserString({
|
||||||
|
user: {
|
||||||
|
email: 'pranav@example.com',
|
||||||
|
avatar_url: 'https://images.chatwoot.com/placeholder',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).toBe(
|
||||||
|
'avatar_urlhttps://images.chatwoot.com/placeholderemailpranav@example.comnameidentifier'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#hasUserKeys', () => {
|
||||||
|
it('checks whether the allowed list of keys are present', () => {
|
||||||
|
expect(hasUserKeys({})).toBe(false);
|
||||||
|
expect(hasUserKeys({ randomKey: 'randomValue' })).toBe(false);
|
||||||
|
expect(hasUserKeys({ avatar_url: 'randomValue' })).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -28,6 +28,7 @@
|
||||||
"ionicons": "~2.0.1",
|
"ionicons": "~2.0.1",
|
||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"lodash.groupby": "^4.6.0",
|
"lodash.groupby": "^4.6.0",
|
||||||
|
"md5": "^2.3.0",
|
||||||
"query-string": "5",
|
"query-string": "5",
|
||||||
"spinkit": "~1.2.5",
|
"spinkit": "~1.2.5",
|
||||||
"tween.js": "~16.6.0",
|
"tween.js": "~16.6.0",
|
||||||
|
|
21
yarn.lock
21
yarn.lock
|
@ -2644,6 +2644,11 @@ chardet@^0.7.0:
|
||||||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
||||||
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
||||||
|
|
||||||
|
charenc@0.0.2:
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||||
|
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
||||||
|
|
||||||
chart.js@~2.5.0:
|
chart.js@~2.5.0:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.5.0.tgz#fe6e751a893769f56e72bee5ad91207e1c592957"
|
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.5.0.tgz#fe6e751a893769f56e72bee5ad91207e1c592957"
|
||||||
|
@ -3200,6 +3205,11 @@ cross-spawn@^7.0.0:
|
||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
which "^2.0.1"
|
which "^2.0.1"
|
||||||
|
|
||||||
|
crypt@0.0.2:
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
|
||||||
|
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
|
||||||
|
|
||||||
crypto-browserify@^3.11.0:
|
crypto-browserify@^3.11.0:
|
||||||
version "3.12.0"
|
version "3.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
||||||
|
@ -5560,7 +5570,7 @@ is-binary-path@~2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
binary-extensions "^2.0.0"
|
binary-extensions "^2.0.0"
|
||||||
|
|
||||||
is-buffer@^1.1.5:
|
is-buffer@^1.1.5, is-buffer@~1.1.6:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||||
|
@ -6931,6 +6941,15 @@ md5.js@^1.3.4:
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.1.2"
|
safe-buffer "^5.1.2"
|
||||||
|
|
||||||
|
md5@^2.3.0:
|
||||||
|
version "2.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
|
||||||
|
integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
|
||||||
|
dependencies:
|
||||||
|
charenc "0.0.2"
|
||||||
|
crypt "0.0.2"
|
||||||
|
is-buffer "~1.1.6"
|
||||||
|
|
||||||
mdn-data@2.0.4:
|
mdn-data@2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"
|
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"
|
||||||
|
|
Loading…
Reference in a new issue