diff --git a/packages/server/app/analytics/collect.ts b/packages/server/app/analytics/collect.ts index d240bd4e..b8e4a39d 100644 --- a/packages/server/app/analytics/collect.ts +++ b/packages/server/app/analytics/collect.ts @@ -1,6 +1,7 @@ import { UAParser } from "ua-parser-js"; import type { RequestInit } from "@cloudflare/workers-types"; +import { maskBrowserVersion } from "~/lib/utils"; // Cookieless visitor/session tracking // Uses the approach described here: https://notes.normally.com/cookieless-unique-visitor-counts/ @@ -100,6 +101,10 @@ export function collectRequestHandler(request: Request, env: Env) { ifModifiedSince ? new Date(ifModifiedSince) : null, ); + const browserVersion = maskBrowserVersion( + parsedUserAgent.getBrowser().version, + ); + const data: DataPoint = { siteId: params.sid, host: params.h, @@ -111,7 +116,7 @@ export function collectRequestHandler(request: Request, env: Env) { // user agent stuff userAgent: userAgent, browserName: parsedUserAgent.getBrowser().name, - browserVersion: parsedUserAgent.getBrowser().version, + browserVersion: browserVersion, deviceModel: parsedUserAgent.getDevice().model, }; diff --git a/packages/server/app/lib/__tests__/utils.test.ts b/packages/server/app/lib/__tests__/utils.test.ts index 2d3a8494..0c8f9937 100644 --- a/packages/server/app/lib/__tests__/utils.test.ts +++ b/packages/server/app/lib/__tests__/utils.test.ts @@ -1,4 +1,8 @@ -import { getFiltersFromSearchParams, getDateTimeRange } from "../utils"; +import { + getFiltersFromSearchParams, + getDateTimeRange, + maskBrowserVersion, +} from "../utils"; import { describe, test, expect, beforeEach, afterEach, vi } from "vitest"; import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; @@ -91,3 +95,19 @@ describe("getDateTimeRange", () => { expect(london.startDate).toEqual(new Date("2024-01-15T00:00:00Z")); }); }); + +describe("maskBrowserVersion", () => { + const browserVersions = [ + ["Microsoft Edge", "119.0.0.0", "119.x.x.x"], + ["Google Chrome", "119.0.0.0", "119.x.x.x"], + ["Mozilla Firefox", "119.0", "119.x"], + ["Safari", "605.1.15", "605.x.x"], + ["DuckDuckGo", "5", "5"], + ["Brave", "129.0.6668.54", "129.x.x.x"], + ["Opera", "117.0.0.0", "117.x.x.x"], + ]; + + test.each(browserVersions)("%s", (_, version, expected) => { + expect(maskBrowserVersion(version)).toEqual(expected); + }); +}); diff --git a/packages/server/app/lib/utils.ts b/packages/server/app/lib/utils.ts index b84bc3b8..aa877e7a 100644 --- a/packages/server/app/lib/utils.ts +++ b/packages/server/app/lib/utils.ts @@ -112,3 +112,17 @@ export function getDateTimeRange(interval: string, tz: string) { endDate: localEndDateTime.toDate(), }; } + +export function maskBrowserVersion(version?: string) { + if (!version) return version; + + const majorEnd = version.indexOf("."); + + if (majorEnd != -1) { + version = + version.substring(0, majorEnd) + + version.slice(majorEnd).replaceAll(/\.[^.]+/g, ".x"); + } + + return version; +} diff --git a/packages/server/app/routes/resources.browserversion.tsx b/packages/server/app/routes/resources.browserversion.tsx index 1140d0da..4433fd39 100644 --- a/packages/server/app/routes/resources.browserversion.tsx +++ b/packages/server/app/routes/resources.browserversion.tsx @@ -43,7 +43,7 @@ export const BrowserVersionCard = ({ ()} loaderUrl="/resources/browserversion" onClick={(browserVersion) =>