From c5ea2531817e2d254692dd48bc4985184528233d Mon Sep 17 00:00:00 2001 From: James Salter Date: Tue, 3 Aug 2021 07:30:02 +0100 Subject: [PATCH] Revert "Add support for Posthog Analytics under a labs flag" --- package.json | 1 - src/@types/posthog.d.ts | 748 ------------------ src/Lifecycle.ts | 5 - src/PosthogAnalytics.ts | 355 --------- src/components/structures/MatrixChat.tsx | 6 - .../tabs/user/SecurityUserSettingsTab.js | 2 - src/i18n/strings/en_EN.json | 1 - src/settings/Settings.tsx | 8 - .../PseudonymousAnalyticsController.ts | 26 - test/PosthogAnalytics-test.ts | 232 ------ tsconfig.json | 9 +- yarn.lock | 12 - 12 files changed, 2 insertions(+), 1403 deletions(-) delete mode 100644 src/@types/posthog.d.ts delete mode 100644 src/PosthogAnalytics.ts delete mode 100644 src/settings/controllers/PseudonymousAnalyticsController.ts delete mode 100644 test/PosthogAnalytics-test.ts diff --git a/package.json b/package.json index b7e06fe012..9744aa7685 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,6 @@ "pako": "^2.0.3", "parse5": "^6.0.1", "png-chunks-extract": "^1.0.0", - "posthog-js": "1.12.1", "prop-types": "^15.7.2", "qrcode": "^1.4.4", "re-resizable": "^6.9.0", diff --git a/src/@types/posthog.d.ts b/src/@types/posthog.d.ts deleted file mode 100644 index 1ca475cd3b..0000000000 --- a/src/@types/posthog.d.ts +++ /dev/null @@ -1,748 +0,0 @@ -// A clone of the type definitions from posthog-js, stripped of references to transitive -// dependencies which we don't actually use, so that we don't need to install them. -// -// Original file lives in node_modules/posthog/dist/module.d.ts - -/* eslint-disable @typescript-eslint/member-delimiter-style */ -/* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable camelcase */ - -// Type definitions for exported methods - -declare class posthog { - /** - * This function initializes a new instance of the PostHog capturing object. - * All new instances are added to the main posthog object as sub properties (such as - * posthog.library_name) and also returned by this function. To define a - * second instance on the page, you would call: - * - * posthog.init('new token', { your: 'config' }, 'library_name'); - * - * and use it like so: - * - * posthog.library_name.capture(...); - * - * @param {String} token Your PostHog API token - * @param {Object} [config] A dictionary of config options to override. See a list of default config options. - * @param {String} [name] The name for the new posthog instance that you want created - */ - static init(token: string, config?: posthog.Config, name?: string): posthog - - /** - * Clears super properties and generates a new random distinct_id for this instance. - * Useful for clearing data when a user logs out. - */ - static reset(reset_device_id?: boolean): void - - /** - * Capture an event. This is the most important and - * frequently used PostHog function. - * - * ### Usage: - * - * // capture an event named 'Registered' - * posthog.capture('Registered', {'Gender': 'Male', 'Age': 21}); - * - * // capture an event using navigator.sendBeacon - * posthog.capture('Left page', {'duration_seconds': 35}, {transport: 'sendBeacon'}); - * - * @param {String} event_name The name of the event. This can be anything the user does - 'Button Click', 'Sign Up', 'Item Purchased', etc. - * @param {Object} [properties] A set of properties to include with the event you're sending. These describe the user who did the event or details about the event itself. - * @param {Object} [options] Optional configuration for this capture request. - * @param {String} [options.transport] Transport method for network request ('XHR' or 'sendBeacon'). - */ - static capture( - event_name: string, - properties?: posthog.Properties, - options?: { transport: 'XHR' | 'sendBeacon' } - ): posthog.CaptureResult - - /** - * Capture a page view event, which is currently ignored by the server. - * This function is called by default on page load unless the - * capture_pageview configuration variable is false. - * - * @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url. - * @api private - */ - static capture_pageview(page?: string): void - - /** - * Register a set of super properties, which are included with all - * events. This will overwrite previous super property values. - * - * ### Usage: - * - * // register 'Gender' as a super property - * posthog.register({'Gender': 'Female'}); - * - * // register several super properties when a user signs up - * posthog.register({ - * 'Email': 'jdoe@example.com', - * 'Account Type': 'Free' - * }); - * - * @param {Object} properties An associative array of properties to store about the user - * @param {Number} [days] How many days since the user's last visit to store the super properties - */ - static register(properties: posthog.Properties, days?: number): void - - /** - * Register a set of super properties only once. This will not - * overwrite previous super property values, unlike register(). - * - * ### Usage: - * - * // register a super property for the first time only - * posthog.register_once({ - * 'First Login Date': new Date().toISOString() - * }); - * - * ### Notes: - * - * If default_value is specified, current super properties - * with that value will be overwritten. - * - * @param {Object} properties An associative array of properties to store about the user - * @param {*} [default_value] Value to override if already set in super properties (ex: 'False') Default: 'None' - * @param {Number} [days] How many days since the users last visit to store the super properties - */ - static register_once(properties: posthog.Properties, default_value?: posthog.Property, days?: number): void - - /** - * Delete a super property stored with the current user. - * - * @param {String} property The name of the super property to remove - */ - static unregister(property: string): void - - /** - * Identify a user with a unique ID instead of a PostHog - * randomly generated distinct_id. If the method is never called, - * then unique visitors will be identified by a UUID generated - * the first time they visit the site. - * - * If user properties are passed, they are also sent to posthog. - * - * ### Usage: - * - * posthog.identify('[user unique id]') - * posthog.identify('[user unique id]', { email: 'john@example.com' }) - * posthog.identify('[user unique id]', {}, { referral_code: '12345' }) - * - * ### Notes: - * - * You can call this function to overwrite a previously set - * unique ID for the current user. PostHog cannot translate - * between IDs at this time, so when you change a user's ID - * they will appear to be a new user. - * - * When used alone, posthog.identify will change the user's - * distinct_id to the unique ID provided. When used in tandem - * with posthog.alias, it will allow you to identify based on - * unique ID and map that back to the original, anonymous - * distinct_id given to the user upon her first arrival to your - * site (thus connecting anonymous pre-signup activity to - * post-signup activity). Though the two work together, do not - * call identify() at the same time as alias(). Calling the two - * at the same time can cause a race condition, so it is best - * practice to call identify on the original, anonymous ID - * right after you've aliased it. - * - * @param {String} [unique_id] A string that uniquely identifies a user. If not provided, the distinct_id currently in the persistent store (cookie or localStorage) will be used. - * @param {Object} [userProperties] Optional: An associative array of properties to store about the user - * @param {Object} [userPropertiesToSetOnce] Optional: An associative array of properties to store about the user. If property is previously set, this does not override that value. - */ - static identify( - unique_id?: string, - userPropertiesToSet?: posthog.Properties, - userPropertiesToSetOnce?: posthog.Properties - ): void - - /** - * Create an alias, which PostHog will use to link two distinct_ids going forward (not retroactively). - * Multiple aliases can map to the same original ID, but not vice-versa. Aliases can also be chained - the - * following is a valid scenario: - * - * posthog.alias('new_id', 'existing_id'); - * ... - * posthog.alias('newer_id', 'new_id'); - * - * If the original ID is not passed in, we will use the current distinct_id - probably the auto-generated GUID. - * - * ### Notes: - * - * The best practice is to call alias() when a unique ID is first created for a user - * (e.g., when a user first registers for an account and provides an email address). - * alias() should never be called more than once for a given user, except to - * chain a newer ID to a previously new ID, as described above. - * - * @param {String} alias A unique identifier that you want to use for this user in the future. - * @param {String} [original] The current identifier being used for this user. - */ - static alias(alias: string, original?: string): posthog.CaptureResult | number - - /** - * Update the configuration of a posthog library instance. - * - * The default config is: - * - * { - * // HTTP method for capturing requests - * api_method: 'POST' - * - * // transport for sending requests ('XHR' or 'sendBeacon') - * // NB: sendBeacon should only be used for scenarios such as - * // page unload where a "best-effort" attempt to send is - * // acceptable; the sendBeacon API does not support callbacks - * // or any way to know the result of the request. PostHog - * // capturing via sendBeacon will not support any event- - * // batching or retry mechanisms. - * api_transport: 'XHR' - * - * // Automatically capture clicks, form submissions and change events - * autocapture: true - * - * // Capture rage clicks (beta) - useful for session recording - * rageclick: false - * - * // super properties cookie expiration (in days) - * cookie_expiration: 365 - * - * // super properties span subdomains - * cross_subdomain_cookie: true - * - * // debug mode - * debug: false - * - * // if this is true, the posthog cookie or localStorage entry - * // will be deleted, and no user persistence will take place - * disable_persistence: false - * - * // if this is true, PostHog will automatically determine - * // City, Region and Country data using the IP address of - * //the client - * ip: true - * - * // opt users out of capturing by this PostHog instance by default - * opt_out_capturing_by_default: false - * - * // opt users out of browser data storage by this PostHog instance by default - * opt_out_persistence_by_default: false - * - * // persistence mechanism used by opt-in/opt-out methods - cookie - * // or localStorage - falls back to cookie if localStorage is unavailable - * opt_out_capturing_persistence_type: 'localStorage' - * - * // customize the name of cookie/localStorage set by opt-in/opt-out methods - * opt_out_capturing_cookie_prefix: null - * - * // type of persistent store for super properties (cookie/ - * // localStorage) if set to 'localStorage', any existing - * // posthog cookie value with the same persistence_name - * // will be transferred to localStorage and deleted - * persistence: 'cookie' - * - * // name for super properties persistent store - * persistence_name: '' - * - * // names of properties/superproperties which should never - * // be sent with capture() calls - * property_blacklist: [] - * - * // if this is true, posthog cookies will be marked as - * // secure, meaning they will only be transmitted over https - * secure_cookie: false - * - * // should we capture a page view on page load - * capture_pageview: true - * - * // if you set upgrade to be true, the library will check for - * // a cookie from our old js library and import super - * // properties from it, then the old cookie is deleted - * // The upgrade config option only works in the initialization, - * // so make sure you set it when you create the library. - * upgrade: false - * - * // extra HTTP request headers to set for each API request, in - * // the format {'Header-Name': value} - * xhr_headers: {} - * - * // protocol for fetching in-app message resources, e.g. - * // 'https://' or 'http://'; defaults to '//' (which defers to the - * // current page's protocol) - * inapp_protocol: '//' - * - * // whether to open in-app message link in new tab/window - * inapp_link_new_window: false - * - * // a set of rrweb config options that PostHog users can configure - * // see https://github.com/rrweb-io/rrweb/blob/master/guide.md - * session_recording: { - * blockClass: 'ph-no-capture', - * blockSelector: null, - * ignoreClass: 'ph-ignore-input', - * maskAllInputs: false, - * maskInputOptions: {}, - * maskInputFn: null, - * slimDOMOptions: {}, - * collectFonts: false - * } - * - * // prevent autocapture from capturing any attribute names on elements - * mask_all_element_attributes: false - * - * // prevent autocapture from capturing textContent on all elements - * mask_all_text: false - * - * // will disable requests to the /decide endpoint (please review documentation for details) - * // autocapture, feature flags, compression and session recording will be disabled when set to `true` - * advanced_disable_decide: false - * - * } - * - * - * @param {Object} config A dictionary of new configuration values to update - */ - static set_config(config: posthog.Config): void - - /** - * returns the current config object for the library. - */ - static get_config(prop_name: T): posthog.Config[T] - - /** - * Returns the value of the super property named property_name. If no such - * property is set, get_property() will return the undefined value. - * - * ### Notes: - * - * get_property() can only be called after the PostHog library has finished loading. - * init() has a loaded function available to handle this automatically. For example: - * - * // grab value for 'user_id' after the posthog library has loaded - * posthog.init('YOUR PROJECT TOKEN', { - * loaded: function(posthog) { - * user_id = posthog.get_property('user_id'); - * } - * }); - * - * @param {String} property_name The name of the super property you want to retrieve - */ - static get_property(property_name: string): posthog.Property | undefined - - /** - * Returns the current distinct id of the user. This is either the id automatically - * generated by the library or the id that has been passed by a call to identify(). - * - * ### Notes: - * - * get_distinct_id() can only be called after the PostHog library has finished loading. - * init() has a loaded function available to handle this automatically. For example: - * - * // set distinct_id after the posthog library has loaded - * posthog.init('YOUR PROJECT TOKEN', { - * loaded: function(posthog) { - * distinct_id = posthog.get_distinct_id(); - * } - * }); - */ - static get_distinct_id(): string - - /** - * Opt the user out of data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * // opt user out - * posthog.opt_out_capturing(); - * - * // opt user out with different cookie configuration from PostHog instance - * posthog.opt_out_capturing({ - * cookie_expiration: 30, - * secure_cookie: true - * }); - * - * @param {Object} [options] A dictionary of config options to override - * @param {boolean} [options.clear_persistence=true] If true, will delete all data stored by the sdk in persistence - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) - */ - static opt_out_capturing(options?: posthog.OptInOutCapturingOptions): void - - /** - * Opt the user in to data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * // opt user in - * posthog.opt_in_capturing(); - * - * // opt user in with specific event name, properties, cookie configuration - * posthog.opt_in_capturing({ - * capture_event_name: 'User opted in', - * capture_event_properties: { - * 'Email': 'jdoe@example.com' - * }, - * cookie_expiration: 30, - * secure_cookie: true - * }); - * - * @param {Object} [options] A dictionary of config options to override - * @param {function} [options.capture] Function used for capturing a PostHog event to record the opt-in action (default is this PostHog instance's capture method) - * @param {string} [options.capture_event_name=$opt_in] Event name to be used for capturing the opt-in action - * @param {Object} [options.capture_properties] Set of properties to be captured along with the opt-in action - * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) - */ - static opt_in_capturing(options?: posthog.OptInOutCapturingOptions): void - - /** - * Check whether the user has opted out of data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * const has_opted_out = posthog.has_opted_out_capturing(); - * // use has_opted_out value - * - * @param {Object} [options] A dictionary of config options to override - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @returns {boolean} current opt-out status - */ - static has_opted_out_capturing(options?: posthog.HasOptedInOutCapturingOptions): boolean - - /** - * Check whether the user has opted in to data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * const has_opted_in = posthog.has_opted_in_capturing(); - * // use has_opted_in value - * - * @param {Object} [options] A dictionary of config options to override - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @returns {boolean} current opt-in status - */ - static has_opted_in_capturing(options?: posthog.HasOptedInOutCapturingOptions): boolean - - /** - * Clear the user's opt in/out status of data capturing and cookies/localstorage for this PostHog instance - * - * ### Usage - * - * // clear user's opt-in/out status - * posthog.clear_opt_in_out_capturing(); - * - * // clear user's opt-in/out status with specific cookie configuration - should match - * // configuration used when opt_in_capturing/opt_out_capturing methods were called. - * posthog.clear_opt_in_out_capturing({ - * cookie_expiration: 30, - * secure_cookie: true - * }); - * - * @param {Object} [options] A dictionary of config options to override - * @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence - * @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable - * @param {string} [options.cookie_prefix=__ph_opt_in_out] Custom prefix to be used in the cookie/localstorage name - * @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this PostHog instance's config) - * @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this PostHog instance's config) - */ - static clear_opt_in_out_capturing(options?: posthog.ClearOptInOutCapturingOptions): void - - /* - * See if feature flag is enabled for user. - * - * ### Usage: - * - * if(posthog.isFeatureEnabled('beta-feature')) { // do something } - * - * @param {Object|String} prop Key of the feature flag. - * @param {Object|String} options (optional) If {send_event: false}, we won't send an $feature_flag_call event to PostHog. - */ - static isFeatureEnabled(key: string, options?: posthog.isFeatureEnabledOptions): boolean - - /* - * See if feature flags are available. - * - * ### Usage: - * - * posthog.onFeatureFlags(function(featureFlags) { // do something }) - * - * @param {Function} [callback] The callback function will be called once the feature flags are ready. It'll return a list of feature flags enabled for the user. - */ - static onFeatureFlags(callback: (flags: string[]) => void): false | undefined - - /* - * Reload all feature flags for the user. - * - * ### Usage: - * - * posthog.reloadFeatureFlags() - */ - static reloadFeatureFlags(): void - - static toString(): string - - /* Will log all capture requests to the Javascript console, including event properties for easy debugging */ - static debug(): void - - /* - * Starts session recording and updates disable_session_recording to false. - * Used for manual session recording management. By default, session recording is enabled and - * starts automatically. - * - * ### Usage: - * - * posthog.startSessionRecording() - */ - static startSessionRecording(): void - - /* - * Stops session recording and updates disable_session_recording to true. - * - * ### Usage: - * - * posthog.stopSessionRecording() - */ - static stopSessionRecording(): void - - /* - * Check if session recording is currently running. - * - * ### Usage: - * - * const isSessionRecordingOn = posthog.sessionRecordingStarted() - */ - static sessionRecordingStarted(): boolean -} - -declare namespace posthog { - /* eslint-disable @typescript-eslint/no-explicit-any */ - type Property = any; - type Properties = Record; - type CaptureResult = { event: string; properties: Properties } | undefined; - type CaptureCallback = (response: any, data: any) => void; - /* eslint-enable @typescript-eslint/no-explicit-any */ - - interface Config { - api_host?: string - api_method?: string - api_transport?: string - autocapture?: boolean - rageclick?: boolean - cdn?: string - cross_subdomain_cookie?: boolean - persistence?: 'localStorage' | 'cookie' | 'memory' - persistence_name?: string - cookie_name?: string - loaded?: (posthog_instance: typeof posthog) => void - store_google?: boolean - save_referrer?: boolean - test?: boolean - verbose?: boolean - img?: boolean - capture_pageview?: boolean - debug?: boolean - cookie_expiration?: number - upgrade?: boolean - disable_session_recording?: boolean - disable_persistence?: boolean - disable_cookie?: boolean - secure_cookie?: boolean - ip?: boolean - opt_out_capturing_by_default?: boolean - opt_out_persistence_by_default?: boolean - opt_out_capturing_persistence_type?: 'localStorage' | 'cookie' - opt_out_capturing_cookie_prefix?: string | null - respect_dnt?: boolean - property_blacklist?: string[] - xhr_headers?: { [header_name: string]: string } - inapp_protocol?: string - inapp_link_new_window?: boolean - request_batching?: boolean - sanitize_properties?: (properties: posthog.Properties, event_name: string) => posthog.Properties - properties_string_max_length?: number - mask_all_element_attributes?: boolean - mask_all_text?: boolean - advanced_disable_decide?: boolean - } - - interface OptInOutCapturingOptions { - clear_persistence: boolean - persistence_type: string - cookie_prefix: string - cookie_expiration: number - cross_subdomain_cookie: boolean - secure_cookie: boolean - } - - interface HasOptedInOutCapturingOptions { - persistence_type: string - cookie_prefix: string - } - - interface ClearOptInOutCapturingOptions { - enable_persistence: boolean - persistence_type: string - cookie_prefix: string - cookie_expiration: number - cross_subdomain_cookie: boolean - secure_cookie: boolean - } - - interface isFeatureEnabledOptions { - send_event: boolean - } - - export class persistence { - static properties(): posthog.Properties - - static load(): void - - static save(): void - - static remove(): void - - static clear(): void - - /** - * @param {Object} props - * @param {*=} default_value - * @param {number=} days - */ - static register_once(props: Properties, default_value?: Property, days?: number): boolean - - /** - * @param {Object} props - * @param {number=} days - */ - static register(props: posthog.Properties, days?: number): boolean - - static unregister(prop: string): void - - static update_campaign_params(): void - - static update_search_keyword(referrer: string): void - - static update_referrer_info(referrer: string): void - - static get_referrer_info(): posthog.Properties - - static safe_merge(props: posthog.Properties): posthog.Properties - - static update_config(config: posthog.Config): void - - static set_disabled(disabled: boolean): void - - static set_cross_subdomain(cross_subdomain: boolean): void - - static get_cross_subdomain(): boolean - - static set_secure(secure: boolean): void - - static set_event_timer(event_name: string, timestamp: Date): void - - static remove_event_timer(event_name: string): Date | undefined - } - - export class people { - /* - * Set properties on a user record. - * - * ### Usage: - * - * posthog.people.set('gender', 'm'); - * - * // or set multiple properties at once - * posthog.people.set({ - * 'Company': 'Acme', - * 'Plan': 'Premium', - * 'Upgrade date': new Date() - * }); - * // properties can be strings, integers, dates, or lists - * - * @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values. - * @param {*} [to] A value to set on the given property name - * @param {Function} [callback] If provided, the callback will be called after capturing the event. - */ - static set( - prop: posthog.Properties | string, - to?: posthog.Property, - callback?: posthog.CaptureCallback - ): posthog.Properties - - /* - * Set properties on a user record, only if they do not yet exist. - * This will not overwrite previous people property values, unlike - * people.set(). - * - * ### Usage: - * - * posthog.people.set_once('First Login Date', new Date()); - * - * // or set multiple properties at once - * posthog.people.set_once({ - * 'First Login Date': new Date(), - * 'Starting Plan': 'Premium' - * }); - * - * // properties can be strings, integers or dates - * - * @param {Object|String} prop If a string, this is the name of the property. If an object, this is an associative array of names and values. - * @param {*} [to] A value to set on the given property name - * @param {Function} [callback] If provided, the callback will be called after capturing the event. - */ - static set_once( - prop: posthog.Properties | string, - to?: posthog.Property, - callback?: posthog.CaptureCallback - ): posthog.Properties - - static toString(): string - } - - export class featureFlags { - static getFlags(): string[] - - static reloadFeatureFlags(): void - - /* - * See if feature flag is enabled for user. - * - * ### Usage: - * - * if(posthog.isFeatureEnabled('beta-feature')) { // do something } - * - * @param {Object|String} prop Key of the feature flag. - * @param {Object|String} options (optional) If {send_event: false}, we won't send an $feature_flag_call event to PostHog. - */ - static isFeatureEnabled(key: string, options?: { send_event?: boolean }): boolean - - /* - * See if feature flags are available. - * - * ### Usage: - * - * posthog.onFeatureFlags(function(featureFlags) { // do something }) - * - * @param {Function} [callback] The callback function will be called once the feature flags are ready. It'll return a list of feature flags enabled for the user. - */ - static onFeatureFlags(callback: (flags: string[]) => void): false | undefined - } - - export class feature_flags extends featureFlags {} -} - -export type PostHog = typeof posthog; - -export default posthog; diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index e48fd52cb1..410124a637 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -48,7 +48,6 @@ import { Jitsi } from "./widgets/Jitsi"; import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY, SSO_IDP_ID_KEY } from "./BasePlatform"; import ThreepidInviteStore from "./stores/ThreepidInviteStore"; import CountlyAnalytics from "./CountlyAnalytics"; -import { PosthogAnalytics } from "./PosthogAnalytics"; import CallHandler from './CallHandler'; import LifecycleCustomisations from "./customisations/Lifecycle"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; @@ -574,8 +573,6 @@ async function doSetLoggedIn( await abortLogin(); } - PosthogAnalytics.instance.updateAnonymityFromSettings(credentials.userId); - Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl); MatrixClientPeg.replaceUsingCreds(credentials); @@ -703,8 +700,6 @@ export function logout(): void { CountlyAnalytics.instance.enable(/* anonymous = */ true); } - PosthogAnalytics.instance.logout(); - if (MatrixClientPeg.get().isGuest()) { // logout doesn't work for guest sessions // Also we sometimes want to re-log in a guest session if we abort the login. diff --git a/src/PosthogAnalytics.ts b/src/PosthogAnalytics.ts deleted file mode 100644 index 860a155aff..0000000000 --- a/src/PosthogAnalytics.ts +++ /dev/null @@ -1,355 +0,0 @@ -/* -Copyright 2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import posthog, { PostHog } from 'posthog-js'; -import PlatformPeg from './PlatformPeg'; -import SdkConfig from './SdkConfig'; -import SettingsStore from './settings/SettingsStore'; - -/* Posthog analytics tracking. - * - * Anonymity behaviour is as follows: - * - * - If Posthog isn't configured in `config.json`, events are not sent. - * - If [Do Not Track](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/doNotTrack) is - * enabled, events are not sent (this detection is built into posthog and turned on via the - * `respect_dnt` flag being passed to `posthog.init`). - * - If the `feature_pseudonymous_analytics_opt_in` labs flag is `true`, track pseudonomously, i.e. - * hash all matrix identifiers in tracking events (user IDs, room IDs etc) using SHA-256. - * - Otherwise, if the existing `analyticsOptIn` flag is `true`, track anonymously, i.e. - * redact all matrix identifiers in tracking events. - * - If both flags are false or not set, events are not sent. - */ - -interface IEvent { - // The event name that will be used by PostHog. Event names should use snake_case. - eventName: string; - - // The properties of the event that will be stored in PostHog. This is just a placeholder, - // extending interfaces must override this with a concrete definition to do type validation. - properties: {}; -} - -export enum Anonymity { - Disabled, - Anonymous, - Pseudonymous -} - -// If an event extends IPseudonymousEvent, the event contains pseudonymous data -// that won't be sent unless the user has explicitly consented to pseudonymous tracking. -// For example, it might contain hashed user IDs or room IDs. -// Such events will be automatically dropped if PosthogAnalytics.anonymity isn't set to Pseudonymous. -export interface IPseudonymousEvent extends IEvent {} - -// If an event extends IAnonymousEvent, the event strictly contains *only* anonymous data; -// i.e. no identifiers that can be associated with the user. -export interface IAnonymousEvent extends IEvent {} - -export interface IRoomEvent extends IPseudonymousEvent { - hashedRoomId: string; -} - -interface IPageView extends IAnonymousEvent { - eventName: "$pageview"; - properties: { - durationMs?: number; - screen?: string; - }; -} - -const hashHex = async (input: string): Promise => { - const buf = new TextEncoder().encode(input); - const digestBuf = await window.crypto.subtle.digest("sha-256", buf); - return [...new Uint8Array(digestBuf)].map((b: number) => b.toString(16).padStart(2, "0")).join(""); -}; - -const whitelistedScreens = new Set([ - "register", "login", "forgot_password", "soft_logout", "new", "settings", "welcome", "home", "start", "directory", - "start_sso", "start_cas", "groups", "complete_security", "post_registration", "room", "user", "group", -]); - -export async function getRedactedCurrentLocation( - origin: string, - hash: string, - pathname: string, - anonymity: Anonymity, -): Promise { - // Redact PII from the current location. - // If anonymous is true, redact entirely, if false, substitute it with a hash. - // For known screens, assumes a URL structure of //might/be/pii - if (origin.startsWith('file://')) { - pathname = "//"; - } - - let hashStr; - if (hash == "") { - hashStr = ""; - } else { - let [beforeFirstSlash, screen, ...parts] = hash.split("/"); - - if (!whitelistedScreens.has(screen)) { - screen = ""; - } - - for (let i = 0; i < parts.length; i++) { - parts[i] = anonymity === Anonymity.Anonymous ? `` : await hashHex(parts[i]); - } - - hashStr = `${beforeFirstSlash}/${screen}/${parts.join("/")}`; - } - return origin + pathname + hashStr; -} - -interface PlatformProperties { - appVersion: string; - appPlatform: string; -} - -export class PosthogAnalytics { - /* Wrapper for Posthog analytics. - * 3 modes of anonymity are supported, governed by this.anonymity - * - Anonymity.Disabled means *no data* is passed to posthog - * - Anonymity.Anonymous means all identifers will be redacted before being passed to posthog - * - Anonymity.Pseudonymous means all identifiers will be hashed via SHA-256 before being passed - * to Posthog - * - * To update anonymity, call updateAnonymityFromSettings() or you can set it directly via setAnonymity(). - * - * To pass an event to Posthog: - * - * 1. Declare a type for the event, extending IAnonymousEvent, IPseudonymousEvent or IRoomEvent. - * 2. Call the appropriate track*() method. Pseudonymous events will be dropped when anonymity is - * Anonymous or Disabled; Anonymous events will be dropped when anonymity is Disabled. - */ - - private anonymity = Anonymity.Disabled; - // set true during the constructor if posthog config is present, otherwise false - private enabled = false; - private static _instance = null; - private platformSuperProperties = {}; - - public static get instance(): PosthogAnalytics { - if (!this._instance) { - this._instance = new PosthogAnalytics(posthog); - } - return this._instance; - } - - constructor(private readonly posthog: PostHog) { - const posthogConfig = SdkConfig.get()["posthog"]; - if (posthogConfig) { - this.posthog.init(posthogConfig.projectApiKey, { - api_host: posthogConfig.apiHost, - autocapture: false, - mask_all_text: true, - mask_all_element_attributes: true, - // This only triggers on page load, which for our SPA isn't particularly useful. - // Plus, the .capture call originating from somewhere in posthog makes it hard - // to redact URLs, which requires async code. - // - // To raise this manually, just call .capture("$pageview") or posthog.capture_pageview. - capture_pageview: false, - sanitize_properties: this.sanitizeProperties, - respect_dnt: true, - }); - this.enabled = true; - } else { - this.enabled = false; - } - } - - private sanitizeProperties = (properties: posthog.Properties): posthog.Properties => { - // Callback from posthog to sanitize properties before sending them to the server. - // - // Here we sanitize posthog's built in properties which leak PII e.g. url reporting. - // See utils.js _.info.properties in posthog-js. - - // Replace the $current_url with a redacted version. - // $redacted_current_url is injected by this class earlier in capture(), as its generation - // is async and can't be done in this non-async callback. - if (!properties['$redacted_current_url']) { - console.log("$redacted_current_url not set in sanitizeProperties, will drop $current_url entirely"); - } - properties['$current_url'] = properties['$redacted_current_url']; - delete properties['$redacted_current_url']; - - if (this.anonymity == Anonymity.Anonymous) { - // drop referrer information for anonymous users - properties['$referrer'] = null; - properties['$referring_domain'] = null; - properties['$initial_referrer'] = null; - properties['$initial_referring_domain'] = null; - - // drop device ID, which is a UUID persisted in local storage - properties['$device_id'] = null; - } - - return properties; - }; - - private static getAnonymityFromSettings(): Anonymity { - // determine the current anonymity level based on current user settings - - // "Send anonymous usage data which helps us improve Element. This will use a cookie." - const analyticsOptIn = SettingsStore.getValue("analyticsOptIn", null, true); - - // (proposed wording) "Send pseudonymous usage data which helps us improve Element. This will use a cookie." - // - // TODO: Currently, this is only a labs flag, for testing purposes. - const pseudonumousOptIn = SettingsStore.getValue("feature_pseudonymous_analytics_opt_in", null, true); - - let anonymity; - if (pseudonumousOptIn) { - anonymity = Anonymity.Pseudonymous; - } else if (analyticsOptIn) { - anonymity = Anonymity.Anonymous; - } else { - anonymity = Anonymity.Disabled; - } - - return anonymity; - } - - private registerSuperProperties(properties: posthog.Properties) { - if (this.enabled) { - this.posthog.register(properties); - } - } - - private static async getPlatformProperties(): Promise { - const platform = PlatformPeg.get(); - let appVersion; - try { - appVersion = await platform.getAppVersion(); - } catch (e) { - // this happens if no version is set i.e. in dev - appVersion = "unknown"; - } - - return { - appVersion, - appPlatform: platform.getHumanReadableName(), - }; - } - - private async capture(eventName: string, properties: posthog.Properties) { - if (!this.enabled) { - return; - } - const { origin, hash, pathname } = window.location; - properties['$redacted_current_url'] = await getRedactedCurrentLocation( - origin, hash, pathname, this.anonymity); - this.posthog.capture(eventName, properties); - } - - public isEnabled(): boolean { - return this.enabled; - } - - public setAnonymity(anonymity: Anonymity): void { - // Update this.anonymity. - // This is public for testing purposes, typically you want to call updateAnonymityFromSettings - // to ensure this value is in step with the user's settings. - if (this.enabled && (anonymity == Anonymity.Disabled || anonymity == Anonymity.Anonymous)) { - // when transitioning to Disabled or Anonymous ensure we clear out any prior state - // set in posthog e.g. distinct ID - this.posthog.reset(); - // Restore any previously set platform super properties - this.registerSuperProperties(this.platformSuperProperties); - } - this.anonymity = anonymity; - } - - public async identifyUser(userId: string): Promise { - if (this.anonymity == Anonymity.Pseudonymous) { - this.posthog.identify(await hashHex(userId)); - } - } - - public getAnonymity(): Anonymity { - return this.anonymity; - } - - public logout(): void { - if (this.enabled) { - this.posthog.reset(); - } - this.setAnonymity(Anonymity.Anonymous); - } - - public async trackPseudonymousEvent( - eventName: E["eventName"], - properties: E["properties"] = {}, - ) { - if (this.anonymity == Anonymity.Anonymous || this.anonymity == Anonymity.Disabled) return; - await this.capture(eventName, properties); - } - - public async trackAnonymousEvent( - eventName: E["eventName"], - properties: E["properties"] = {}, - ): Promise { - if (this.anonymity == Anonymity.Disabled) return; - await this.capture(eventName, properties); - } - - public async trackRoomEvent( - eventName: E["eventName"], - roomId: string, - properties: Omit, - ): Promise { - const updatedProperties = { - ...properties, - hashedRoomId: roomId ? await hashHex(roomId) : null, - }; - await this.trackPseudonymousEvent(eventName, updatedProperties); - } - - public async trackPageView(durationMs: number): Promise { - const hash = window.location.hash; - - let screen = null; - const split = hash.split("/"); - if (split.length >= 2) { - screen = split[1]; - } - - await this.trackAnonymousEvent("$pageview", { - durationMs, - screen, - }); - } - - public async updatePlatformSuperProperties(): Promise { - // Update super properties in posthog with our platform (app version, platform). - // These properties will be subsequently passed in every event. - // - // This only needs to be done once per page lifetime. Note that getPlatformProperties - // is async and can involve a network request if we are running in a browser. - this.platformSuperProperties = await PosthogAnalytics.getPlatformProperties(); - this.registerSuperProperties(this.platformSuperProperties); - } - - public async updateAnonymityFromSettings(userId?: string): Promise { - // Update this.anonymity based on the user's analytics opt-in settings - // Identify the user (via hashed user ID) to posthog if anonymity is pseudonmyous - this.setAnonymity(PosthogAnalytics.getAnonymityFromSettings()); - if (userId && this.getAnonymity() == Anonymity.Pseudonymous) { - await this.identifyUser(userId); - } - } -} diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 60c78b5f9e..8cfe35c4cf 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -107,7 +107,6 @@ import UIStore, { UI_EVENTS } from "../../stores/UIStore"; import SoftLogout from './auth/SoftLogout'; import { makeRoomPermalink } from "../../utils/permalinks/Permalinks"; import { copyPlaintext } from "../../utils/strings"; -import { PosthogAnalytics } from '../../PosthogAnalytics'; /** constants for MatrixChat.state.view */ export enum Views { @@ -388,10 +387,6 @@ export default class MatrixChat extends React.PureComponent { if (SettingsStore.getValue("analyticsOptIn")) { Analytics.enable(); } - - PosthogAnalytics.instance.updateAnonymityFromSettings(); - PosthogAnalytics.instance.updatePlatformSuperProperties(); - CountlyAnalytics.instance.enable(/* anonymous = */ true); } @@ -448,7 +443,6 @@ export default class MatrixChat extends React.PureComponent { const durationMs = this.stopPageChangeTimer(); Analytics.trackPageChange(durationMs); CountlyAnalytics.instance.trackPageChange(durationMs); - PosthogAnalytics.instance.trackPageView(durationMs); } if (this.focusComposer) { dis.fire(Action.FocusSendMessageComposer); diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index 25b0b86cb1..79d501e712 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -36,7 +36,6 @@ import { UIFeature } from "../../../../../settings/UIFeature"; import { isE2eAdvancedPanelPossible } from "../../E2eAdvancedPanel"; import CountlyAnalytics from "../../../../../CountlyAnalytics"; import { replaceableComponent } from "../../../../../utils/replaceableComponent"; -import { PosthogAnalytics } from "../../../../../PosthogAnalytics"; export class IgnoredUser extends React.Component { static propTypes = { @@ -107,7 +106,6 @@ export default class SecurityUserSettingsTab extends React.Component { _updateAnalytics = (checked) => { checked ? Analytics.enable() : Analytics.disable(); CountlyAnalytics.instance.enable(/* anonymous = */ !checked); - PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId()); }; _onExportE2eKeysClicked = () => { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 87cd9afb5b..3ad8daa85c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -813,7 +813,6 @@ "Show message previews for reactions in DMs": "Show message previews for reactions in DMs", "Show message previews for reactions in all rooms": "Show message previews for reactions in all rooms", "Offline encrypted messaging using dehydrated devices": "Offline encrypted messaging using dehydrated devices", - "Send pseudonymous analytics data": "Send pseudonymous analytics data", "Enable advanced debugging for the room list": "Enable advanced debugging for the room list", "Show info about bridges in room settings": "Show info about bridges in room settings", "New layout switcher (with message bubbles)": "New layout switcher (with message bubbles)", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index cfe2c097fc..c36e2b90bf 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -41,7 +41,6 @@ import { Layout } from "./Layout"; import ReducedMotionController from './controllers/ReducedMotionController'; import IncompatibleController from "./controllers/IncompatibleController"; import SdkConfig from "../SdkConfig"; -import PseudonymousAnalyticsController from './controllers/PseudonymousAnalyticsController'; import NewLayoutSwitcherController from './controllers/NewLayoutSwitcherController'; // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times @@ -269,13 +268,6 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_FEATURE, default: false, }, - "feature_pseudonymous_analytics_opt_in": { - isFeature: true, - supportedLevels: LEVELS_FEATURE, - displayName: _td('Send pseudonymous analytics data'), - default: false, - controller: new PseudonymousAnalyticsController(), - }, "advancedRoomListLogging": { // TODO: Remove flag before launch: https://github.com/vector-im/element-web/issues/14231 displayName: _td("Enable advanced debugging for the room list"), diff --git a/src/settings/controllers/PseudonymousAnalyticsController.ts b/src/settings/controllers/PseudonymousAnalyticsController.ts deleted file mode 100644 index a82b9685ef..0000000000 --- a/src/settings/controllers/PseudonymousAnalyticsController.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* -Copyright 2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import SettingController from "./SettingController"; -import { SettingLevel } from "../SettingLevel"; -import { PosthogAnalytics } from "../../PosthogAnalytics"; -import { MatrixClientPeg } from "../../MatrixClientPeg"; - -export default class PseudonymousAnalyticsController extends SettingController { - public onChange(level: SettingLevel, roomId: string, newValue: any) { - PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId()); - } -} diff --git a/test/PosthogAnalytics-test.ts b/test/PosthogAnalytics-test.ts deleted file mode 100644 index 6cb1743051..0000000000 --- a/test/PosthogAnalytics-test.ts +++ /dev/null @@ -1,232 +0,0 @@ -/* -Copyright 2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { - Anonymity, - getRedactedCurrentLocation, - IAnonymousEvent, - IPseudonymousEvent, - IRoomEvent, - PosthogAnalytics, -} from '../src/PosthogAnalytics'; - -import SdkConfig from '../src/SdkConfig'; - -class FakePosthog { - public capture; - public init; - public identify; - public reset; - public register; - - constructor() { - this.capture = jest.fn(); - this.init = jest.fn(); - this.identify = jest.fn(); - this.reset = jest.fn(); - this.register = jest.fn(); - } -} - -export interface ITestEvent extends IAnonymousEvent { - key: "jest_test_event"; - properties: { - foo: string; - }; -} - -export interface ITestPseudonymousEvent extends IPseudonymousEvent { - key: "jest_test_pseudo_event"; - properties: { - foo: string; - }; -} - -export interface ITestRoomEvent extends IRoomEvent { - key: "jest_test_room_event"; - properties: { - foo: string; - }; -} - -describe("PosthogAnalytics", () => { - let fakePosthog: FakePosthog; - const shaHashes = { - "42": "73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049", - "some": "a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b", - "pii": "bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4", - "foo": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", - }; - - beforeEach(() => { - fakePosthog = new FakePosthog(); - - window.crypto = { - subtle: { - digest: async (_, encodedMessage) => { - const message = new TextDecoder().decode(encodedMessage); - const hexHash = shaHashes[message]; - const bytes = []; - for (let c = 0; c < hexHash.length; c += 2) { - bytes.push(parseInt(hexHash.substr(c, 2), 16)); - } - return bytes; - }, - }, - }; - }); - - afterEach(() => { - window.crypto = null; - }); - - describe("Initialisation", () => { - it("Should not be enabled without config being set", () => { - jest.spyOn(SdkConfig, "get").mockReturnValue({}); - const analytics = new PosthogAnalytics(fakePosthog); - expect(analytics.isEnabled()).toBe(false); - }); - - it("Should be enabled if config is set", () => { - jest.spyOn(SdkConfig, "get").mockReturnValue({ - posthog: { - projectApiKey: "foo", - apiHost: "bar", - }, - }); - const analytics = new PosthogAnalytics(fakePosthog); - analytics.setAnonymity(Anonymity.Pseudonymous); - expect(analytics.isEnabled()).toBe(true); - }); - }); - - describe("Tracking", () => { - let analytics: PosthogAnalytics; - - beforeEach(() => { - jest.spyOn(SdkConfig, "get").mockReturnValue({ - posthog: { - projectApiKey: "foo", - apiHost: "bar", - }, - }); - - analytics = new PosthogAnalytics(fakePosthog); - }); - - it("Should pass trackAnonymousEvent() to posthog", async () => { - analytics.setAnonymity(Anonymity.Pseudonymous); - await analytics.trackAnonymousEvent("jest_test_event", { - foo: "bar", - }); - expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event"); - expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar"); - }); - - it("Should pass trackRoomEvent to posthog", async () => { - analytics.setAnonymity(Anonymity.Pseudonymous); - const roomId = "42"; - await analytics.trackRoomEvent("jest_test_event", roomId, { - foo: "bar", - }); - expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event"); - expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar"); - expect(fakePosthog.capture.mock.calls[0][1]["hashedRoomId"]) - .toEqual("73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049"); - }); - - it("Should pass trackPseudonymousEvent() to posthog", async () => { - analytics.setAnonymity(Anonymity.Pseudonymous); - await analytics.trackPseudonymousEvent("jest_test_pseudo_event", { - foo: "bar", - }); - expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_pseudo_event"); - expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar"); - }); - - it("Should not track pseudonymous messages if anonymous", async () => { - analytics.setAnonymity(Anonymity.Anonymous); - await analytics.trackPseudonymousEvent("jest_test_event", { - foo: "bar", - }); - expect(fakePosthog.capture.mock.calls.length).toBe(0); - }); - - it("Should not track any events if disabled", async () => { - analytics.setAnonymity(Anonymity.Disabled); - await analytics.trackPseudonymousEvent("jest_test_event", { - foo: "bar", - }); - await analytics.trackAnonymousEvent("jest_test_event", { - foo: "bar", - }); - await analytics.trackRoomEvent("room id", "foo", { - foo: "bar", - }); - await analytics.trackPageView(200); - expect(fakePosthog.capture.mock.calls.length).toBe(0); - }); - - it("Should pseudonymise a location of a known screen", async () => { - const location = await getRedactedCurrentLocation( - "https://foo.bar", "#/register/some/pii", "/", Anonymity.Pseudonymous); - expect(location).toBe( - `https://foo.bar/#/register/\ -a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b/\ -bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4`); - }); - - it("Should anonymise a location of a known screen", async () => { - const location = await getRedactedCurrentLocation( - "https://foo.bar", "#/register/some/pii", "/", Anonymity.Anonymous); - expect(location).toBe("https://foo.bar/#/register//"); - }); - - it("Should pseudonymise a location of an unknown screen", async () => { - const location = await getRedactedCurrentLocation( - "https://foo.bar", "#/not_a_screen_name/some/pii", "/", Anonymity.Pseudonymous); - expect(location).toBe( - `https://foo.bar/#//\ -a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b/\ -bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4`); - }); - - it("Should anonymise a location of an unknown screen", async () => { - const location = await getRedactedCurrentLocation( - "https://foo.bar", "#/not_a_screen_name/some/pii", "/", Anonymity.Anonymous); - expect(location).toBe("https://foo.bar/#///"); - }); - - it("Should handle an empty hash", async () => { - const location = await getRedactedCurrentLocation( - "https://foo.bar", "", "/", Anonymity.Anonymous); - expect(location).toBe("https://foo.bar/"); - }); - - it("Should identify the user to posthog if pseudonymous", async () => { - analytics.setAnonymity(Anonymity.Pseudonymous); - await analytics.identifyUser("foo"); - expect(fakePosthog.identify.mock.calls[0][0]) - .toBe("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"); - }); - - it("Should not identify the user to posthog if anonymous", async () => { - analytics.setAnonymity(Anonymity.Anonymous); - await analytics.identifyUser("foo"); - expect(fakePosthog.identify.mock.calls.length).toBe(0); - }); - }); -}); diff --git a/tsconfig.json b/tsconfig.json index b982d40b07..b139e8e8d1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,15 +22,10 @@ "es2019", "dom", "dom.iterable" - ], - "paths": { - "posthog-js": [ - "./src/@types/posthog.d.ts" - ] - } + ] }, "include": [ "./src/**/*.ts", "./src/**/*.tsx" - ], + ] } diff --git a/yarn.lock b/yarn.lock index daed6f4377..2a03f640ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3601,11 +3601,6 @@ fbjs@^0.8.4: setimmediate "^1.0.5" ua-parser-js "^0.7.18" -fflate@^0.4.1: - version "0.4.8" - resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" - integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== - file-entry-cache@^6.0.0, file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -6254,13 +6249,6 @@ postcss@^8.0.2: nanoid "^3.1.23" source-map-js "^0.6.2" -posthog-js@1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.12.1.tgz#97834ee2574f34ffb5db2f5b07452c847e3c4d27" - integrity sha512-Y3lzcWkS8xFY6Ryj3I4ees7qWP2WGkLw0Arcbk5xaT0+5YlA6UC2jlL/+fN9bz/Bl62EoN3BML901Cuot/QNjg== - dependencies: - fflate "^0.4.1" - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"