Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add cookieless server hash mode #25915

Draft
wants to merge 47 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
aca1c00
Use ip address for the partitioning key
robbie-c Oct 29, 2024
a1ce236
Add uuidv7 code
robbie-c Oct 30, 2024
8caaebc
WIP
robbie-c Oct 30, 2024
6213985
Handle repeat ids better
robbie-c Oct 31, 2024
153ef1b
WIP
robbie-c Nov 1, 2024
98701d7
Update plugin-server/src/utils/db/db.ts
robbie-c Nov 28, 2024
4a137ed
WIP
robbie-c Dec 4, 2024
b524488
WIP
robbie-c Dec 4, 2024
90f8e0c
Typing
robbie-c Dec 5, 2024
af1d8f9
Fix
robbie-c Dec 5, 2024
e134d2c
Comment
robbie-c Dec 6, 2024
45e65e2
Do redis in a transaction
robbie-c Dec 9, 2024
8272fbf
Use UTC if timezone is invalid
robbie-c Dec 9, 2024
a04e563
Vendor the siphash npm library
robbie-c Dec 9, 2024
a8ca51b
Unvendor
robbie-c Dec 10, 2024
011cad2
Change naming of sentinel value
robbie-c Dec 10, 2024
4514a7a
Delete expired salts
robbie-c Dec 10, 2024
4f33d47
Make abortController optional
robbie-c Dec 12, 2024
db93cf7
Use $cklsh property
robbie-c Dec 12, 2024
1b81625
Add setting for opt in to cklsh
robbie-c Dec 12, 2024
f6224a0
Add simple mode of operation
robbie-c Dec 13, 2024
5b03a25
Make the cookieless mode an enum so we can disable staeful mode as a …
robbie-c Dec 16, 2024
d7ecd39
Store and load the session state as binary
robbie-c Dec 17, 2024
63cc285
Improve comment, strip PII, as $cklsh_extra
robbie-c Dec 17, 2024
67fca63
Update query snapshots
github-actions[bot] Dec 17, 2024
5ff0218
Fix
robbie-c Dec 18, 2024
10c48b5
Use correct sentinel value
robbie-c Dec 18, 2024
eafd127
Update query snapshots
github-actions[bot] Dec 18, 2024
02892e8
Update UI snapshots for `chromium` (1)
github-actions[bot] Dec 18, 2024
646f317
Update query snapshots
github-actions[bot] Dec 18, 2024
7702f48
Still randomly partition when overflowing
robbie-c Dec 18, 2024
0d5f20f
Modify capture.rs
robbie-c Dec 18, 2024
3ef22b9
Use npm version of siphash
robbie-c Dec 18, 2024
567d19f
Fix label
robbie-c Dec 18, 2024
5d404a7
Use ??
robbie-c Dec 18, 2024
ad3755d
Use env var
robbie-c Dec 18, 2024
563b883
Make clippy happy
robbie-c Dec 18, 2024
2a29b1a
Remove my irrelevant device id changes in capture.py
robbie-c Dec 18, 2024
2dc40f0
Only store true values for is_cookieless_mode
robbie-c Dec 18, 2024
00e5c96
tsc
robbie-c Dec 19, 2024
523a62b
Update UI snapshots for `chromium` (1)
github-actions[bot] Dec 19, 2024
7de87be
Fix runner tests
robbie-c Dec 19, 2024
b9f3cb7
Fix db tests
robbie-c Dec 19, 2024
456275f
Add tests for some DB functions
robbie-c Dec 19, 2024
cc511a0
Fix migration
robbie-c Dec 19, 2024
a5ce66f
Add test for redisScard
robbie-c Dec 19, 2024
164b6ff
Update query snapshots
github-actions[bot] Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export const FEATURE_FLAGS = {
EXPERIMENT_STATS_V2: 'experiment-stats-v2', // owner: @danielbachhuber #team-experiments
WEB_ANALYTICS_PERIOD_COMPARISON: 'web-analytics-period-comparison', // owner: @rafaeelaudibert #team-web-analytics
WEB_ANALYTICS_CONVERSION_GOAL_FILTERS: 'web-analytics-conversion-goal-filters', // owner: @rafaeelaudibert #team-web-analytics
COOKIELESS_SERVER_HASH_MODE_SETTING: 'cookieless-server-hash-mode-setting', // owner: @robbie-c #team-web-analytics
} as const
export type FeatureFlagKey = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS]

Expand Down
8 changes: 4 additions & 4 deletions frontend/src/lib/utils/concurrencyController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ConcurrencyControllerItem<T> {
constructor(
concurrencyController: ConcurrencyController,
userFn: () => Promise<T>,
abortController: AbortController,
abortController: AbortController | undefined,
priority: number = Infinity,
debugTag: string | undefined
) {
Expand All @@ -17,7 +17,7 @@ class ConcurrencyControllerItem<T> {
const { promise, resolve, reject } = promiseResolveReject<T>()
this._promise = promise
this._runFn = async () => {
if (abortController.signal.aborted) {
if (abortController?.signal.aborted) {
reject(new FakeAbortError(abortController.signal.reason || 'AbortError'))
return
}
Expand All @@ -32,7 +32,7 @@ class ConcurrencyControllerItem<T> {
reject(error)
}
}
abortController.signal.addEventListener('abort', () => {
abortController?.signal.addEventListener('abort', () => {
reject(new FakeAbortError(abortController.signal.reason || 'AbortError'))
})
promise
Expand Down Expand Up @@ -76,7 +76,7 @@ export class ConcurrencyController {
}: {
fn: () => Promise<T>
priority?: number
abortController: AbortController
abortController?: AbortController
debugTag?: string
}): Promise<T> => {
const item = new ConcurrencyControllerItem(this, fn, abortController, priority, debugTag)
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/scenes/settings/SettingsMap.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BounceRatePageViewModeSetting } from 'scenes/settings/environment/BounceRatePageViewMode'
import { CookielessServerHashModeSetting } from 'scenes/settings/environment/CookielessServerHashMode'
import { CustomChannelTypes } from 'scenes/settings/environment/CustomChannelTypes'
import { DeadClicksAutocaptureSettings } from 'scenes/settings/environment/DeadClicksAutocaptureSettings'
import { PersonsJoinMode } from 'scenes/settings/environment/PersonsJoinMode'
Expand Down Expand Up @@ -218,6 +219,12 @@ export const SETTINGS_MAP: SettingSection[] = [
title: 'Custom channel type',
component: <CustomChannelTypes />,
},
{
id: 'cookieless-server-hash-mode',
title: 'Cookieless server hash mode',
component: <CookielessServerHashModeSetting />,
flag: 'COOKIELESS_SERVER_HASH_MODE_SETTING',
},
],
},

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useActions, useValues } from 'kea'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { LemonRadio, LemonRadioOption } from 'lib/lemon-ui/LemonRadio'
import { useState } from 'react'
import { teamLogic } from 'scenes/teamLogic'

import { CookielessServerHashMode } from '~/types'

const options: LemonRadioOption<CookielessServerHashMode>[] = [
{
value: CookielessServerHashMode.Stateful,
label: (
<>
<div>Stateful</div>
</>
),
},
{
value: CookielessServerHashMode.Stateless,
label: (
<>
<div>Stateless</div>
</>
),
},
{
value: CookielessServerHashMode.Disabled,
label: (
<>
<div>Disabled</div>
</>
),
},
]

export function CookielessServerHashModeSetting(): JSX.Element {
const { updateCurrentTeam } = useActions(teamLogic)
const { currentTeam } = useValues(teamLogic)

const savedSetting = currentTeam?.cookieless_server_hash_mode ?? CookielessServerHashMode.Disabled
const [setting, setSetting] = useState<CookielessServerHashMode>(savedSetting)

const handleChange = (newSetting: CookielessServerHashMode): void => {
updateCurrentTeam({ cookieless_server_hash_mode: newSetting })
}

return (
<>
<p>
Use a cookieless server-side hash mode to hash user data. This is an experimental feature preview and
may result in dropped events.
</p>
Comment on lines +49 to +52
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We eventually need to explain this slightly better, it definitely won't be clear by this message what "cookieless server-side hash mode" means

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't ever be seen by a customer, only us

<LemonRadio value={setting} onChange={setSetting} options={options} />
<div className="mt-4">
<LemonButton
type="primary"
onClick={() => handleChange(setting)}
disabledReason={setting === savedSetting ? 'No changes to save' : undefined}
>
Save
</LemonButton>
</div>
</>
)
}
1 change: 1 addition & 0 deletions frontend/src/scenes/settings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export type SettingId =
| 'web-vitals-autocapture'
| 'dead-clicks-autocapture'
| 'channel-type'
| 'cookieless-server-hash-mode'

type FeatureFlagKey = keyof typeof FEATURE_FLAGS

Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/teamActivityDescriber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ const teamActionsMapping: Record<
user_access_level: () => null,
live_events_token: () => null,
product_intents: () => null,
cookieless_server_hash_mode: () => null,
}

function nameAndLink(logItem?: ActivityLogItem): JSX.Element {
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ export interface TeamType extends TeamBasicType {
primary_dashboard: number // Dashboard shown on the project homepage
live_events_columns: string[] | null // Custom columns shown on the Live Events page
live_events_token: string
cookieless_server_hash_mode?: CookielessServerHashMode

/** Effective access level of the user in this specific team. Null if user has no access. */
effective_membership_level: OrganizationMembershipLevel | null
Expand Down Expand Up @@ -4829,6 +4830,12 @@ export type ReplayTemplateVariableType = {
noTouch?: boolean
}

export enum CookielessServerHashMode {
Disabled = 0,
Stateless = 1,
Stateful = 2,
}

/**
* Assistant Conversation
*/
Expand Down
5 changes: 4 additions & 1 deletion plugin-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@posthog/cyclotron": "file:../rust/cyclotron-node",
"@posthog/hogvm": "^1.0.66",
"@posthog/plugin-scaffold": "1.4.4",
"@posthog/siphash": "1.1.1",
"@sentry/node": "^7.49.0",
"@sentry/profiling-node": "^0.3.0",
"@sentry/tracing": "^7.17.4",
Expand All @@ -69,16 +70,17 @@
"express": "^4.18.2",
"faker": "^5.5.3",
"fast-deep-equal": "^3.1.3",
"fastpriorityqueue": "^0.7.5",
robbie-c marked this conversation as resolved.
Show resolved Hide resolved
"fernet-nodejs": "^1.0.6",
"generic-pool": "^3.7.1",
"graphile-worker": "0.13.0",
"ioredis": "^4.27.6",
"ipaddr.js": "^2.1.0",
"kafkajs": "^2.2.0",
"lz4-kafkajs": "1.0.0",
"kafkajs-snappy": "^1.1.0",
"lru-cache": "^6.0.0",
"luxon": "^3.4.4",
"lz4-kafkajs": "1.0.0",
"node-fetch": "^2.6.1",
"node-rdkafka": "^2.17.0",
"node-schedule": "^2.1.0",
Expand All @@ -90,6 +92,7 @@
"re2": "^1.20.3",
"safe-stable-stringify": "^2.4.0",
"tail": "^2.2.6",
"tldts": "^6.1.57",
"uuid": "^9.0.1",
"v8-profiler-next": "^1.9.0",
"vm2": "3.9.18"
Expand Down
28 changes: 28 additions & 0 deletions plugin-server/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion plugin-server/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,12 @@ export enum PluginLogLevel {
Critical = 4, // only error type and system source
}

export enum CookielessServerHashMode {
Disabled = 0,
Stateless = 1,
Stateful = 2,
}

export interface PluginLogEntry {
id: string
team_id: number
Expand Down Expand Up @@ -633,13 +639,15 @@ export interface Team {
api_token: string
slack_incoming_webhook: string | null
session_recording_opt_in: boolean
person_processing_opt_out?: boolean
person_processing_opt_out: boolean | null
heatmaps_opt_in: boolean | null
ingested_event: boolean
person_display_name_properties: string[] | null
test_account_filters:
| (EventPropertyFilter | PersonPropertyFilter | ElementPropertyFilter | CohortPropertyFilter)[]
| null
cookieless_server_hash_mode: CookielessServerHashMode | null
timezone: string
}

/** Properties shared by RawEventMessage and EventMessage. */
Expand Down
Loading
Loading