From c4237d02ed7fd5af30f3e057edbe75320076c653 Mon Sep 17 00:00:00 2001 From: Maxim Schuwalow Date: Thu, 14 Sep 2023 20:58:54 +0200 Subject: [PATCH] wip --- live-connect-js-6.0.3-alpha-8f0b28c.0.tgz | Bin 0 -> 60301 bytes package-lock.json | 8 +- package.json | 2 +- src/cache.ts | 128 ++++++++++++++++++++++ src/enrichers/people-verified.ts | 6 +- src/handlers/storage-handler.ts | 84 -------------- src/manager/identifiers.ts | 82 ++++---------- src/pixel/state.ts | 12 +- src/standard-live-connect.ts | 24 +++- src/types.ts | 2 + src/utils/domain.ts | 21 ++++ src/utils/wrapping.ts | 10 +- tsconfig.json | 3 +- 13 files changed, 224 insertions(+), 158 deletions(-) create mode 100644 live-connect-js-6.0.3-alpha-8f0b28c.0.tgz create mode 100644 src/cache.ts create mode 100644 src/utils/domain.ts diff --git a/live-connect-js-6.0.3-alpha-8f0b28c.0.tgz b/live-connect-js-6.0.3-alpha-8f0b28c.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..136fbb9902b9437cc89eed2b76a57664ac4b6f6f GIT binary patch literal 60301 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 GNCN;$*bNi_ literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json index a184b42f..b227c479 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "6.0.3-alpha-8f0b28c.0", "license": "Apache-2.0", "dependencies": { - "live-connect-common": "^v3.0.1", + "live-connect-common": "^v3.0.2", "tiny-hashes": "1.0.1" }, "devDependencies": { @@ -14665,9 +14665,9 @@ "dev": true }, "node_modules/live-connect-common": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/live-connect-common/-/live-connect-common-3.0.1.tgz", - "integrity": "sha512-m8DS4GVonoV9dEbM+vFmDZXWK3PUu0+Ox5qGEnx6ar04MkC33MTb328PhgPNdmMyfz7C+hCgEsDgZmMZSl0+UA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/live-connect-common/-/live-connect-common-3.0.2.tgz", + "integrity": "sha512-K3LNKd9CpREDJbXGdwKqPojjQaxd4G6c7OAD6Yzp3wsCWTH2hV8xNAbUksSOpOcVyyOT9ilteEFXIJQJrbODxQ==", "engines": { "node": ">=18" } diff --git a/package.json b/package.json index 0e3490dc..ee6d9b35 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "release:ci:major": "release-it major --ci" }, "dependencies": { - "live-connect-common": "^v3.0.1", + "live-connect-common": "^v3.0.2", "tiny-hashes": "1.0.1" }, "devDependencies": { diff --git a/src/cache.ts b/src/cache.ts new file mode 100644 index 00000000..a58d8200 --- /dev/null +++ b/src/cache.ts @@ -0,0 +1,128 @@ +import { strEqualsIgnoreCase, expiresInHours } from 'live-connect-common' +import { WrappedStorageHandler } from './handlers/storage-handler' +import { StorageStrategies, StorageStrategy } from './model/storage-strategy' + +export type CacheRecord = { + data: string + expiresAt?: Date +} + +export interface DurableCache { + get: (key: string) => CacheRecord | null // null is used to signal missing value + set: (key: string, value: string, expiration?: Date) => void +} + +export type StorageHandlerBackedCacheOpts = { + strategy: 'cookie' | 'ls', + storageHandler: WrappedStorageHandler, + domain: string, + defaultExpirationHours?: number +} + +export type MakeCacheOpts = StorageHandlerBackedCacheOpts & { + strategy: StorageStrategy, +} + +export function makeCache(opts: MakeCacheOpts): DurableCache { + if (!strEqualsIgnoreCase(opts.strategy, StorageStrategies.cookie) && strEqualsIgnoreCase(opts.strategy, StorageStrategies.none)) { + return NoOpCache + } else { + // TODO: Remove once we validate config properly + const strategyWithDefault = opts.strategy ?? StorageStrategies.cookie + return new StorageHandlerBackedCache({ ...opts, strategy: strategyWithDefault }) + } +} + +export class StorageHandlerBackedCache implements DurableCache { + private handler + private storageStrategy + private defaultExpirationHours? + private domain + + constructor (opts: StorageHandlerBackedCacheOpts) { + this.handler = opts.storageHandler + this.storageStrategy = opts.strategy + this.defaultExpirationHours = opts.defaultExpirationHours + this.domain = opts.domain + } + + private getCookieRecord(key: string): CacheRecord | null { + let expiresAt: Date | undefined + + const cookieExpirationEntry = this.handler.getCookie(expirationKey(key)) + if (cookieExpirationEntry && cookieExpirationEntry.length > 0) { + expiresAt = new Date(cookieExpirationEntry) + if (expiresAt <= new Date()) { + return null + } + } + + const data = this.handler.getCookie(key) + if (data) { + return { data, expiresAt } + } else { + return null + } + } + + private getLSRecord(key: string): CacheRecord | null { + let expiresAt: Date | undefined + const oldLsExpirationEntry = this.handler.getDataFromLocalStorage(expirationKey(key)) + + if (oldLsExpirationEntry) { + expiresAt = new Date(oldLsExpirationEntry) + if (expiresAt <= new Date()) { + this.handler.removeDataFromLocalStorage(key) + this.handler.removeDataFromLocalStorage(expirationKey(key)) + return null + } + } + + const data = this.handler.getDataFromLocalStorage(key) + if (data) { + return { data, expiresAt } + } else { + return null + } + } + + get(key: string): CacheRecord | null { + if (strEqualsIgnoreCase(this.storageStrategy, StorageStrategies.localStorage) && this.handler.localStorageIsEnabled()) { + return this.getLSRecord(key) + } else { + return this.getCookieRecord(key) + } + } + + set(key: string, value: string, expires?: Date): void { + if (!expires && this.defaultExpirationHours) { + expires = expiresInHours(this.defaultExpirationHours) + } + + if (strEqualsIgnoreCase(this.storageStrategy, StorageStrategies.localStorage) && this.handler.localStorageIsEnabled()) { + this.handler.setDataInLocalStorage(key, value) + if (expires) { + this.handler.setDataInLocalStorage(expirationKey(key), `${expires}`) + } else { + this.handler.removeDataFromLocalStorage(expirationKey(key)) + } + } else { + this.handler.setCookie(key, value, expires, 'Lax', this.domain) + if (expires) { + this.handler.setCookie(expirationKey(key), `${expires}`, expires, 'Lax', this.domain) + } else { + // sentinel value to indicate no expiration + this.handler.setCookie(expirationKey(key), '', undefined, 'Lax', this.domain) + } + } + } +} + +export const NoOpCache: DurableCache = { + get: () => null, + set: () => undefined +} + +function expirationKey(baseKey: string): string { + return `${baseKey}_exp` +} diff --git a/src/enrichers/people-verified.ts b/src/enrichers/people-verified.ts index 80bb3325..6a9f9c23 100644 --- a/src/enrichers/people-verified.ts +++ b/src/enrichers/people-verified.ts @@ -1,10 +1,10 @@ import { PEOPLE_VERIFIED_LS_ENTRY } from '../utils/consts' import { EventBus, State } from '../types' -import { WrappedReadOnlyStorageHandler } from '../handlers/storage-handler' +import { DurableCache } from '../cache' -export function enrich(state: State, storageHandler: WrappedReadOnlyStorageHandler, eventBus: EventBus): State { +export function enrich(state: State, cache: DurableCache, eventBus: EventBus): State { try { - return { peopleVerifiedId: state.peopleVerifiedId || storageHandler.getDataFromLocalStorage(PEOPLE_VERIFIED_LS_ENTRY) || undefined } + return { peopleVerifiedId: state.peopleVerifiedId || cache.get(PEOPLE_VERIFIED_LS_ENTRY)?.data || undefined } } catch (e) { eventBus.emitError('PeopleVerifiedEnrich', e) return {} diff --git a/src/handlers/storage-handler.ts b/src/handlers/storage-handler.ts index 282dfa4a..acdbc182 100644 --- a/src/handlers/storage-handler.ts +++ b/src/handlers/storage-handler.ts @@ -2,11 +2,6 @@ import { StorageStrategies, StorageStrategy } from '../model/storage-strategy' import { EventBus, ReadOnlyStorageHandler, StorageHandler, strEqualsIgnoreCase } from 'live-connect-common' import { WrappingContext } from '../utils/wrapping' -type StorageRecord = { - data: string - expiresAt?: Date -} - const noop = () => undefined function wrapRead(wrapper: WrappingContext, storageStrategy: StorageStrategy, functionName: K) { @@ -72,81 +67,6 @@ export class WrappedStorageHandler extends WrappedReadOnlyStorageHandler impleme return handler } - private getCookieRecord(key: string): StorageRecord | null { - let expiresAt: Date | undefined - - const cookieExpirationEntry = this.getCookie(expirationKey(key)) - if (cookieExpirationEntry && cookieExpirationEntry.length > 0) { - expiresAt = new Date(cookieExpirationEntry) - if (expiresAt <= new Date()) { - return null - } - } - - const data = this.getCookie(key) - if (data) { - return { data, expiresAt } - } else { - return null - } - } - - private getLSRecord(key: string): StorageRecord | null { - if (this.localStorageIsEnabled()) { - let expiresAt: Date | undefined - const oldLsExpirationEntry = this.getDataFromLocalStorage(expirationKey(key)) - - if (oldLsExpirationEntry) { - expiresAt = new Date(oldLsExpirationEntry) - if (expiresAt <= new Date()) { - this.removeDataFromLocalStorage(key) - this.removeDataFromLocalStorage(expirationKey(key)) - return null - } - } - - const data = this.getDataFromLocalStorage(key) - if (data) { - return { data, expiresAt } - } else { - return null - } - } else { - return null - } - } - - get(key: string): StorageRecord | null { - if (strEqualsIgnoreCase(this.storageStrategy, StorageStrategies.none) || strEqualsIgnoreCase(this.storageStrategy, StorageStrategies.disabled)) { - return null - } else if (strEqualsIgnoreCase(this.storageStrategy, StorageStrategies.localStorage)) { - return this.getLSRecord(key) - } else { - return this.getCookieRecord(key) - } - } - - set(key: string, value: string, expires?: Date, domain?: string): void { - if (strEqualsIgnoreCase(this.storageStrategy, StorageStrategies.none) || strEqualsIgnoreCase(this.storageStrategy, StorageStrategies.disabled)) { - // pass - } else if (strEqualsIgnoreCase(this.storageStrategy, StorageStrategies.localStorage) && this.localStorageIsEnabled()) { - this.setDataInLocalStorage(key, value) - if (expires) { - this.setDataInLocalStorage(expirationKey(key), `${expires}`) - } else { - this.removeDataFromLocalStorage(expirationKey(key)) - } - } else { - this.setCookie(key, value, expires, 'Lax', domain) - if (expires) { - this.setCookie(expirationKey(key), `${expires}`, expires, 'Lax', domain) - } else { - // sentinel value to indicate no expiration - this.setCookie(expirationKey(key), '', undefined, 'Lax', domain) - } - } - } - setCookie(key: string, value: string, expires?: Date, sameSite?: string, domain?: string): void { this.functions.setCookie(key, value, expires, sameSite, domain) } @@ -163,7 +83,3 @@ export class WrappedStorageHandler extends WrappedReadOnlyStorageHandler impleme return this.functions.findSimilarCookies(substring) || [] } } - -function expirationKey(baseKey: string): string { - return `${baseKey}_exp` -} diff --git a/src/manager/identifiers.ts b/src/manager/identifiers.ts index 7c01dcb6..bb5d67e8 100644 --- a/src/manager/identifiers.ts +++ b/src/manager/identifiers.ts @@ -5,72 +5,36 @@ import { expiresInDays } from 'live-connect-common' import { PEOPLE_VERIFIED_LS_ENTRY } from '../utils/consts' import { EventBus, State } from '../types' import { WrappedStorageHandler } from '../handlers/storage-handler' +import { DurableCache } from '../cache' const NEXT_GEN_FP_NAME = '_lc2_fpi' -const TLD_CACHE_KEY = '_li_dcdm_c' const DEFAULT_EXPIRATION_DAYS = 730 -export function resolve(state: State, storageHandler: WrappedStorageHandler, eventBus: EventBus): State { - try { - const determineTld = () => { - const cachedDomain = storageHandler.getCookie(TLD_CACHE_KEY) - if (cachedDomain) { - return cachedDomain - } - const domain = loadedDomain() - const arr = domain.split('.') - for (let i = arr.length; i > 0; i--) { - const newD = `.${arr.slice(i - 1, arr.length).join('.')}` - storageHandler.setCookie(TLD_CACHE_KEY, newD, undefined, 'Lax', newD) - if (storageHandler.getCookie(TLD_CACHE_KEY)) { - return newD - } - } - return `.${domain}` - } +export function resolve( + state: { expirationDays?: number, domain: string }, + storageHandler: WrappedStorageHandler, + cache: DurableCache, + eventBus: EventBus +): State { + const expiry = state.expirationDays || DEFAULT_EXPIRATION_DAYS + const oldValue = cache.get(NEXT_GEN_FP_NAME)?.data - const getOrAddWithExpiration = (key: string, value: string) => { - try { - const oldValue = storageHandler.get(key)?.data - const expiry = expiresInDays(storageOptions.expires) - if (oldValue) { - storageHandler.set(key, oldValue, expiry, storageOptions.domain) - } else { - storageHandler.set(key, value, expiry, storageOptions.domain) - } - return storageHandler.get(key)?.data - } catch (e) { - eventBus.emitErrorWithMessage('CookieLsGetOrAdd', 'Failed manipulating cookie jar or ls', e) - return null - } - } + if (oldValue) { + cache.set(NEXT_GEN_FP_NAME, oldValue, expiresInDays(expiry)) + } else { + const newValue = `${domainHash(state.domain)}--${ulid()}` - const generateCookie = (apexDomain: string) => { - const cookie = `${domainHash(apexDomain)}--${ulid()}` - return cookie.toLocaleLowerCase() - } + cache.set(NEXT_GEN_FP_NAME, newValue, expiresInDays(expiry)) + } + + const liveConnectIdentifier = cache.get(NEXT_GEN_FP_NAME)?.data || undefined - const expiry = state.expirationDays || DEFAULT_EXPIRATION_DAYS - const cookieDomain = determineTld() - const storageOptions = { - expires: expiry, - domain: cookieDomain - } - const liveConnectIdentifier = getOrAddWithExpiration( - NEXT_GEN_FP_NAME, - generateCookie(cookieDomain) - ) || undefined + if (liveConnectIdentifier) { + storageHandler.setDataInLocalStorage(PEOPLE_VERIFIED_LS_ENTRY, liveConnectIdentifier) + } - if (liveConnectIdentifier) { - storageHandler.setDataInLocalStorage(PEOPLE_VERIFIED_LS_ENTRY, liveConnectIdentifier) - } - return { - domain: cookieDomain, - liveConnectId: liveConnectIdentifier, - peopleVerifiedId: liveConnectIdentifier - } - } catch (e) { - eventBus.emitErrorWithMessage('IdentifiersResolve', 'Error while managing identifiers', e) - return {} + return { + liveConnectId: liveConnectIdentifier, + peopleVerifiedId: liveConnectIdentifier } } diff --git a/src/pixel/state.ts b/src/pixel/state.ts index 0b6ee90e..a17d668a 100644 --- a/src/pixel/state.ts +++ b/src/pixel/state.ts @@ -4,7 +4,7 @@ import { fiddle, mergeObjects } from './fiddler' import { isObject, trim, isArray, nonNull } from 'live-connect-common' import { asStringParam, asParamOrEmpty, asStringParamWhen, asStringParamTransform } from '../utils/params' import { toParams } from '../utils/url' -import { EventBus, State } from '../types' +import { Enricher, EventBus, State } from '../types' import { collectUrl } from './url-collector' const noOpEvents = ['setemail', 'setemailhash', 'sethashedemail'] @@ -108,6 +108,16 @@ export class StateWrapper { return new StateWrapper(mergeObjects(this.data, newInfo), this.eventBus) } + enrich(enrichers: Enricher[]): void { + enrichers.forEach((enricher) => { + try { + enricher(this.data) + } catch (e) { + this.eventBus.emitErrorWithMessage('StateEnrich', 'Error while enriching state', e) + } + }) + } + sendsPixel() { const source = isObject(this.data.eventSource) ? this.data.eventSource : {} const eventKeys = Object.keys(source) diff --git a/src/standard-live-connect.ts b/src/standard-live-connect.ts index 0309ca1d..fd1bcca2 100644 --- a/src/standard-live-connect.ts +++ b/src/standard-live-connect.ts @@ -18,6 +18,8 @@ import { WrappedCallHandler } from './handlers/call-handler' import { StorageStrategies } from './model/storage-strategy' import { ConfigMismatch, EventBus, ILiveConnect, LiveConnectConfig, State } from './types' import { LocalEventBus, getAvailableBus } from './events/event-bus' +import { determineHighestAccessibleDomain } from './utils/domain' +import { makeCache } from './cache' const hemStore: State = {} function _pushSingleEvent (event: any, pixelClient: PixelSender, enrichedState: StateWrapper, eventBus: EventBus) { @@ -83,12 +85,26 @@ function _getInitializedLiveConnect (liveConnectConfig: LiveConnectConfig): ILiv function _standardInitialization (liveConnectConfig: LiveConnectConfig, externalStorageHandler: StorageHandler, externalCallHandler: CallHandler, eventBus: EventBus): ILiveConnect { try { - const callHandler = new WrappedCallHandler(externalCallHandler, eventBus) + // TODO: proper config validation const validLiveConnectConfig = removeInvalidPairs(liveConnectConfig, eventBus) + + const callHandler = new WrappedCallHandler(externalCallHandler, eventBus) + const configWithPrivacy = mergeObjects(validLiveConnectConfig, privacyConfig(validLiveConnectConfig)) - errorHandler.register(configWithPrivacy, callHandler, eventBus) - const storageStrategy = configWithPrivacy.privacyMode ? StorageStrategies.disabled : configWithPrivacy.storageStrategy + const domain = determineHighestAccessibleDomain(storageHandler) + const configWithDomain = mergeObjects(configWithPrivacy, { domain: domain }) + + errorHandler.register(configWithDomain, callHandler, eventBus) + + const storageStrategy = configWithPrivacy.privacyMode ? StorageStrategies.disabled : (configWithPrivacy.storageStrategy || StorageStrategies.cookie) const storageHandler = WrappedStorageHandler.make(storageStrategy, externalStorageHandler, eventBus) + + const cache = makeCache({ + strategy: storageStrategy, + storageHandler: storageHandler, + domain: domain, + }) + const reducer = (accumulator, func) => accumulator.combineWith(func(accumulator.data, storageHandler, eventBus)) const enrichers = [pageEnrich, identifiersEnrich] @@ -102,7 +118,9 @@ function _standardInitialization (liveConnectConfig: LiveConnectConfig, external const onPixelPreload = () => eventBus.emit(C.PRELOAD_PIXEL, '0') const pixelClient = new PixelSender(configWithPrivacy, callHandler, eventBus, onPixelLoad, onPixelPreload) const resolver = IdentityResolver.make(postManagedState.data, storageHandler, callHandler, eventBus) + const _push = (...args: any[]) => _processArgs(args, pixelClient, postManagedState, eventBus) + return { push: _push, fire: () => _push({}), diff --git a/src/types.ts b/src/types.ts index 3660798f..9a8fcaeb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,6 +4,8 @@ import { StorageStrategy } from './model/storage-strategy' import { UrlCollectionMode } from './model/url-collection-mode' import { ErrorDetails } from 'live-connect-common' +export type Enricher = (state: State) => void // should mutate state in-place + export interface IdentityResolutionConfig { url?: string expirationHours?: number diff --git a/src/utils/domain.ts b/src/utils/domain.ts new file mode 100644 index 00000000..0e9b5cdd --- /dev/null +++ b/src/utils/domain.ts @@ -0,0 +1,21 @@ +import { WrappedStorageHandler } from "../handlers/storage-handler" +import { loadedDomain } from "./page" + +const TLD_CACHE_KEY = '_li_dcdm_c' + +export function determineHighestAccessibleDomain(storageHandler: WrappedStorageHandler): string { + const cachedDomain = storageHandler.getCookie(TLD_CACHE_KEY) + if (cachedDomain) { + return cachedDomain + } + const domain = loadedDomain() + const arr = domain.split('.') + for (let i = arr.length; i > 0; i--) { + const newD = `.${arr.slice(i - 1, arr.length).join('.')}` + storageHandler.setCookie(TLD_CACHE_KEY, newD, undefined, 'Lax', newD) + if (storageHandler.getCookie(TLD_CACHE_KEY)) { + return newD + } + } + return `.${domain}` +} diff --git a/src/utils/wrapping.ts b/src/utils/wrapping.ts index 720ae633..d8015cf5 100644 --- a/src/utils/wrapping.ts +++ b/src/utils/wrapping.ts @@ -22,8 +22,14 @@ export class WrappingContext { if (isObject(this.obj)) { const member = this.obj[functionName] if (isFunction(member)) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return member.bind(this.obj as any) as NonNullable + return ((...args) => { + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (member as any).call(this.obj, ...args) + } catch (e) { + this.eventBus.emitErrorWithMessage(this.name, `Failed calling ${functionName}`, e) + } + }) } } this.errors.push(functionName) diff --git a/tsconfig.json b/tsconfig.json index 476920af..14b3f468 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,8 @@ "declaration": true, "sourceMap": true, "moduleResolution": "Node", - "module": "ESNext" + "module": "ESNext", + "noEmitOnError": false, }, "include": ["./src/**/*", "./test/**/*"] }