@rudderstack/analytics-js-cookies
Version:
RudderStack JavaScript SDK Cookies Utilities
95 lines (85 loc) • 8.05 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.rsaCookies = {}));
})(this, (function (exports) { 'use strict';
/**
* A function to check given value is null or not
* @param value input value
* @returns boolean
*/const isNull=value=>value===null;/**
* A function to check given value is undefined
* @param value input value
* @returns boolean
*/const isUndefined=value=>typeof value==='undefined';/**
* A function to check given value is null or undefined
* @param value input value
* @returns boolean
*/const isNullOrUndefined=value=>isNull(value)||isUndefined(value);
// https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
/**
* Converts a base64 encoded string to bytes array
* @param base64Str base64 encoded string
* @returns bytes array
*/const base64ToBytes=base64Str=>{const binString=globalThis.atob(base64Str);const bytes=binString.split('').map(char=>char.charCodeAt(0));return new Uint8Array(bytes);};/**
* Converts a bytes array to base64 encoded string
* @param bytes bytes array to be converted to base64
* @returns base64 encoded string
*/const bytesToBase64=bytes=>{const binString=Array.from(bytes,x=>String.fromCodePoint(x)).join('');return globalThis.btoa(binString);};/**
* Encodes a string to base64 even with unicode characters
* @param value input string
* @returns base64 encoded string
*/const toBase64=value=>bytesToBase64(new TextEncoder().encode(value));/**
* Decodes a base64 encoded string
* @param value base64 encoded string
* @returns decoded string
*/const fromBase64=value=>new TextDecoder().decode(base64ToBytes(value));
const CIRCULAR_REFERENCE_PLACEHOLDER='[Circular Reference]';const getCircularReplacer=(excludeNull,excludeKeys,logger)=>{const ancestors=[];// Here we do not want to use arrow function to use "this" in function context
// eslint-disable-next-line func-names
return function(key,value){if(typeof value!=='object'||isNull(value)){return value;}// `this` is the object that value is contained in, i.e., its direct parent.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-next-line
while(ancestors.length>0&&ancestors[ancestors.length-1]!==this){ancestors.pop();}if(ancestors.includes(value)){return CIRCULAR_REFERENCE_PLACEHOLDER;}ancestors.push(value);return value;};};/**
* Utility method for JSON stringify object excluding null values & circular references
*
* @param {*} value input
* @param {boolean} excludeNull if it should exclude nul or not
* @param {function} logger optional logger methods for warning
* @returns string
*/const stringifyWithoutCircular=(value,excludeNull,excludeKeys,logger)=>{try{return JSON.stringify(value,getCircularReplacer(excludeNull,excludeKeys,logger));}catch(err){return null;}};
/**
* Encode.
*/const encode=(value,logger)=>{try{return encodeURIComponent(value);}catch(err){return undefined;}};/**
* Decode
*/const decode=value=>{try{return decodeURIComponent(value);}catch(err){// Do nothing as non-RS SDK cookies may not be URI encoded
return undefined;}};/**
* Parse cookie `str`
*/const parse=str=>{const obj={};const pairs=str.split(/\s*;\s*/);let pair;if(!pairs[0]){return obj;}// TODO: Decode only the cookies that are needed by the SDK
pairs.forEach(pairItem=>{pair=pairItem.split('=');const keyName=pair[0]?decode(pair[0]):undefined;if(keyName){obj[keyName]=pair[1]?decode(pair[1]):undefined;}});return obj;};/**
* Set cookie `name` to `value`
*/const set=(name,value,optionsConfig,logger)=>{const options={...({})};let cookieString=`${encode(name)}=${encode(value)}`;if(isNull(value)){options.maxage=-1;}if(options.maxage){options.expires=new Date(+new Date()+options.maxage);}if(options.path){cookieString+=`; path=${options.path}`;}if(options.domain){cookieString+=`; domain=${options.domain}`;}if(options.expires){cookieString+=`; expires=${options.expires.toUTCString()}`;}if(options.samesite){cookieString+=`; samesite=${options.samesite}`;}if(options.secure){cookieString+=`; secure`;}globalThis.document.cookie=cookieString;};/**
* Return all cookies
*/const all=()=>{const cookieStringValue=globalThis.document.cookie;return parse(cookieStringValue);};/**
* Get cookie `name`
*/const get=name=>all()[name];/**
* Set or get cookie `name` with `value` and `options` object
*/// eslint-disable-next-line func-names
const cookie=function(name,value,options,logger){switch(arguments.length){case 4:case 3:case 2:return set(name,value);case 1:if(name){return get(name);}return all();default:return all();}};
const userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserIdKey='rl_anonymous_id';const groupIdKey='rl_group_id';const groupTraitsKey='rl_group_trait';const pageInitialReferrerKey='rl_page_init_referrer';const pageInitialReferringDomainKey='rl_page_init_referring_domain';const sessionInfoKey='rl_session';const authTokenKey='rl_auth_token';const COOKIE_KEYS={userId:userIdKey,userTraits:userTraitsKey,anonymousId:anonymousUserIdKey,groupId:groupIdKey,groupTraits:groupTraitsKey,initialReferrer:pageInitialReferrerKey,initialReferringDomain:pageInitialReferringDomainKey,sessionInfo:sessionInfoKey,authToken:authTokenKey};const ENCRYPTION_PREFIX_V3='RS_ENC_v3_';
const getEncryptedValueInternal=(value,encryptFn,debug)=>{const fallbackValue=null;try{const strValue=stringifyWithoutCircular(value,false);if(isNull(strValue)){return null;}return encryptFn(strValue);}catch(err){if(debug){console.error('Error occurred during encryption: ',err);}return fallbackValue;}};const getDecryptedValueInternal=(value,decryptFn,debug)=>{const fallbackValue=null;try{const decryptedVal=decryptFn(value);if(isNullOrUndefined(decryptedVal)){return fallbackValue;}return JSON.parse(decryptedVal);}catch(err){if(debug){console.error('Error occurred during decryption: ',err);}return fallbackValue;}};const encryptBrowser=value=>`${ENCRYPTION_PREFIX_V3}${toBase64(value)}`;const decryptBrowser=value=>{if(value?.startsWith(ENCRYPTION_PREFIX_V3)){return fromBase64(value.substring(ENCRYPTION_PREFIX_V3.length));}return value;};const getEncryptedValueBrowser=(value,debug=false)=>getEncryptedValueInternal(value,encryptBrowser,debug);const getDecryptedValueBrowser=(value,debug=false)=>getDecryptedValueInternal(value,decryptBrowser,debug);const getDecryptedCookieBrowser=(cookieKey,debug=false)=>{if(Object.values(COOKIE_KEYS).includes(cookieKey)){return getDecryptedValueBrowser(cookie(cookieKey),debug);}return null;};const encrypt=value=>`${ENCRYPTION_PREFIX_V3}${Buffer.from(value,'utf-8').toString('base64')}`;const decrypt=value=>{if(value?.startsWith(ENCRYPTION_PREFIX_V3)){return Buffer.from(value.substring(ENCRYPTION_PREFIX_V3.length),'base64').toString('utf-8');}return value;};const getDecryptedValue=(value,debug=false)=>getDecryptedValueInternal(value,decrypt,debug);const getEncryptedValue=(value,debug=false)=>getEncryptedValueInternal(value,encrypt,debug);
exports.anonymousUserIdKey = anonymousUserIdKey;
exports.authTokenKey = authTokenKey;
exports.getDecryptedCookieBrowser = getDecryptedCookieBrowser;
exports.getDecryptedValue = getDecryptedValue;
exports.getDecryptedValueBrowser = getDecryptedValueBrowser;
exports.getEncryptedValue = getEncryptedValue;
exports.getEncryptedValueBrowser = getEncryptedValueBrowser;
exports.groupIdKey = groupIdKey;
exports.groupTraitsKey = groupTraitsKey;
exports.pageInitialReferrerKey = pageInitialReferrerKey;
exports.pageInitialReferringDomainKey = pageInitialReferringDomainKey;
exports.sessionInfoKey = sessionInfoKey;
exports.userIdKey = userIdKey;
exports.userTraitsKey = userTraitsKey;
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}));