diff --git a/gui/package.json b/gui/package.json index 00deaa49e..488f4879b 100644 --- a/gui/package.json +++ b/gui/package.json @@ -12,7 +12,7 @@ "@react-hookz/deep-equal": "^3.0.3", "@react-three/drei": "^9.114.3", "@react-three/fiber": "^8.17.10", - "@sentry/react": "^9.9.0", + "@sentry/react": "^10.29.0", "@sentry/vite-plugin": "^2.22.7", "@tailwindcss/typography": "^0.5.15", "@tanstack/react-query": "^5.48.0", diff --git a/gui/src/hooks/crypto.ts b/gui/src/hooks/crypto.ts new file mode 100644 index 000000000..0152a1c92 --- /dev/null +++ b/gui/src/hooks/crypto.ts @@ -0,0 +1,10 @@ +export function hash(str: string) { + let hash = 2166136261; + for (let i = 0; i < str.length; i++) { + hash ^= str.charCodeAt(i); + hash = Math.imul(hash, 16777619); // FNV prime + } + + // Convert to unsigned 32-bit integer and normalize (0, 1) + return (hash >>> 0) / 2 ** 32; +}; diff --git a/gui/src/hooks/firmware-update.ts b/gui/src/hooks/firmware-update.ts index 7557aee7e..09734a7b6 100644 --- a/gui/src/hooks/firmware-update.ts +++ b/gui/src/hooks/firmware-update.ts @@ -3,6 +3,8 @@ import { fetch as tauriFetch } from '@tauri-apps/plugin-http'; import { cacheWrap } from './cache'; import semver from 'semver'; import { hostname, locale, platform, version } from '@tauri-apps/plugin-os'; +import { hash } from './crypto'; +import { getUserID } from './user'; export interface FirmwareRelease { name: string; @@ -12,18 +14,6 @@ export interface FirmwareRelease { userCanUpdate: boolean; } -// implemetation of https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function -const hash = (str: string) => { - let hash = 2166136261; - for (let i = 0; i < str.length; i++) { - hash ^= str.charCodeAt(i); - hash = Math.imul(hash, 16777619); // FNV prime - } - - // Convert to unsigned 32-bit integer and normalize (0, 1) - return (hash >>> 0) / 2 ** 32; -}; - const firstAsset = (assets: any[], name: string) => assets.find((asset: any) => asset.name === name && asset.browser_download_url); @@ -67,7 +57,7 @@ const checkUserCanUpdate = async (url: string, fwVersion: string) => { const todayUpdateRange = todaysRange(deployData); if (!todayUpdateRange) return false; - const uniqueUserKey = `${await hostname()}-${await locale()}-${platform()}-${version()}`; + const uniqueUserKey = await getUserID(); // Make it so the hash change every version. Prevent the same user from getting the same delay return hash(`${uniqueUserKey}-${fwVersion}`) <= todayUpdateRange; }; diff --git a/gui/src/hooks/user.ts b/gui/src/hooks/user.ts new file mode 100644 index 000000000..3a9358568 --- /dev/null +++ b/gui/src/hooks/user.ts @@ -0,0 +1,9 @@ +import { locale } from '@tauri-apps/plugin-os'; +import { hostname, platform, version } from 'os'; +import { hash } from './crypto'; + +export async function getUserID() { + // FIXME: This does not support android. It currently return the same id for all android users + + return hash(`${hostname()}-${await locale()}-${platform()}-${version()}`); +} diff --git a/gui/src/utils/sentry.ts b/gui/src/utils/sentry.ts index 5f4611f8f..4c124c7ba 100644 --- a/gui/src/utils/sentry.ts +++ b/gui/src/utils/sentry.ts @@ -8,6 +8,7 @@ import { useNavigationType, } from 'react-router-dom'; import { DeviceDataT } from 'solarxr-protocol'; +import { getUserID } from '@/hooks/user'; export function getSentryOrCompute(enabled = false) { // if sentry is already initialized - SKIP @@ -62,6 +63,10 @@ export function getSentryOrCompute(enabled = false) { log('Initialized the Sentry client'); } + getUserID().then((id) => { + Sentry.setUser({ id }) + }) + return newClient; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 247679860..69100fa15 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,8 +42,8 @@ importers: specifier: ^8.17.10 version: 8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) '@sentry/react': - specifier: ^9.9.0 - version: 9.9.0(react@18.3.1) + specifier: ^10.29.0 + version: 10.29.0(react@18.3.1) '@sentry/vite-plugin': specifier: ^2.22.7 version: 2.22.7 @@ -759,6 +759,9 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -771,15 +774,21 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.6': - resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@mediapipe/tasks-vision@0.10.8': resolution: {integrity: sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==} @@ -901,7 +910,7 @@ packages: '@react-hookz/deep-equal@3.0.3': resolution: {integrity: sha512-SLy+NmiDpncqc2d9TR4Y4R7f8lUFOQK9WbnIq02A6wDxy+dTHfA2Np0dPvj0SFp6i1nqERLmEUe9MxPLuO/IqA==} engines: {node: '>=18.0.0'} - deprecated: Package is deprecated and will be deleted soon. Use @ver0/deep-equal instead. + deprecated: PACKAGE IS DEPRECATED AND WILL BE DETED SOON, USE @ver0/deep-equal INSTEAD '@react-spring/animated@9.6.1': resolution: {integrity: sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==} @@ -1054,28 +1063,28 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@sentry-internal/browser-utils@9.9.0': - resolution: {integrity: sha512-V/YhKLis98JFkqBGZaEBlDNFpJHJjoCvNb05raAYXdITfDIl37Kxqj0zX+IzyRhqnswkQ+DBTyoEoci09IR2bQ==} + '@sentry-internal/browser-utils@10.29.0': + resolution: {integrity: sha512-M3kycMY6f3KY9a8jDYac+yG0E3ZgWVWSxlOEC5MhYyX+g7mqxkwrb3LFQyuxSm/m+CCgMTCaPOOaB2twXP6EQg==} engines: {node: '>=18'} - '@sentry-internal/feedback@9.9.0': - resolution: {integrity: sha512-hrxuOLm0Xsnx75hTNt3eLgNNjER3egrHZShdRzlMiakfKpA9f2X10z75vlZmT5ZUygDQnp9UVUnu28cDuVb9Zw==} + '@sentry-internal/feedback@10.29.0': + resolution: {integrity: sha512-Y7IRsNeS99cEONu1mZWZc3HvbjNnu59Hgymm0swFFKbdgbCgdT6l85kn2oLsuq4Ew8Dw/pL/Sgpwsl9UgYFpUg==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@9.9.0': - resolution: {integrity: sha512-YK0ixGjquahGpNsQskCEVwycdHlwNBLCx9XJr1BmGnlOw6fUCmpyVetaGg/ZyhkzKGNXAGoTa4s7FUFnAG4bKg==} + '@sentry-internal/replay-canvas@10.29.0': + resolution: {integrity: sha512-typY4JrpAQQGPuSyd/BD8+nNCbvTV2UVvKzr+iKgI0m1qc4Dz8tHZ4Nfais2Z8eYn/pL1kqVQN5ERTmJoYFdIw==} engines: {node: '>=18'} - '@sentry-internal/replay@9.9.0': - resolution: {integrity: sha512-EWczKMu3qiZ0SUUWU3zkGod+AWD/VQCLiQw+tw+PEpdHbRZIdYKsEptengZCFKthrwe2QmYpVCTSRxGvujJ/6g==} + '@sentry-internal/replay@10.29.0': + resolution: {integrity: sha512-45NVw9PwB9TQ8z+xJ6G6Za+wmQ1RTA35heBSzR6U4bknj8LmA04k2iwnobvxCBEQXeLfcJEO1vFgagMoqMZMBw==} engines: {node: '>=18'} '@sentry/babel-plugin-component-annotate@2.22.7': resolution: {integrity: sha512-aa7XKgZMVl6l04NY+3X7BP7yvQ/s8scn8KzQfTLrGRarziTlMGrsCOBQtCNWXOPEbtxAIHpZ9dsrAn5EJSivOQ==} engines: {node: '>= 14'} - '@sentry/browser@9.9.0': - resolution: {integrity: sha512-pIMdkOC+iggZefBs6ck5fL1mBhbLzjdw/8K99iqSeDh+lLvmlHVZajAhPlmw50xfH8CyQ1s22dhcL+zXbg3NKw==} + '@sentry/browser@10.29.0': + resolution: {integrity: sha512-XdbyIR6F4qoR9Z1JCWTgunVcTJjS9p2Th+v4wYs4ME+ZdLC4tuKKmRgYg3YdSIWCn1CBfIgdI6wqETSf7H6Njw==} engines: {node: '>=18'} '@sentry/bundler-plugin-core@2.22.7': @@ -1128,12 +1137,12 @@ packages: engines: {node: '>= 10'} hasBin: true - '@sentry/core@9.9.0': - resolution: {integrity: sha512-GxKvx8PSgoWhLLS+/WBGIXy7rsFcnJBPDqFXIfcAGy89k2j06d9IP0kiIc63qBGStSUkh5FFJLPTakZ5RXiFXA==} + '@sentry/core@10.29.0': + resolution: {integrity: sha512-olQ2DU9dA/Bwsz3PtA9KNXRMqBWRQSkPw+MxwWEoU1K1qtiM9L0j6lbEFb5iSY3d7WYD5MB+1d5COugjSBrHtw==} engines: {node: '>=18'} - '@sentry/react@9.9.0': - resolution: {integrity: sha512-7BE2Lx5CNtHtlNSS7Z9HxKquohC0xhdFceO3NlMXlx+dZuVCMoQmLISB8SQEcHw+2VO24MvtP3LPEzdeNbkIfg==} + '@sentry/react@10.29.0': + resolution: {integrity: sha512-YGaEUXubzil7qssD1koh1fyt0aS8tHB61/6+oNShJ6xZPg03AB42bNMr2/y8fIFx36kb3MiCA5sFoH/ubF0LnQ==} engines: {node: '>=18'} peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x @@ -2759,6 +2768,7 @@ packages: got-fetch@5.1.10: resolution: {integrity: sha512-Gwj/A2htjvLEcY07PKDItv0WCPEs3dV2vWeZ+9TVBSKSTuWEZ4oXaMD0ZAOsajwx2orahQWN4HI0MfRyWSZsbg==} engines: {node: '>=14.0.0'} + deprecated: please use built-in fetch in nodejs peerDependencies: got: ^12.0.0 @@ -5448,6 +5458,12 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + optional: true + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -5458,19 +5474,28 @@ snapshots: '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.6': + '@jridgewell/source-map@0.3.11': dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 optional: true '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.5': + optional: true + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + optional: true + '@mediapipe/tasks-vision@0.10.8': {} '@mgit-at/typescript-flatbuffers-codegen@0.1.3': @@ -5755,33 +5780,33 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@sentry-internal/browser-utils@9.9.0': + '@sentry-internal/browser-utils@10.29.0': dependencies: - '@sentry/core': 9.9.0 + '@sentry/core': 10.29.0 - '@sentry-internal/feedback@9.9.0': + '@sentry-internal/feedback@10.29.0': dependencies: - '@sentry/core': 9.9.0 + '@sentry/core': 10.29.0 - '@sentry-internal/replay-canvas@9.9.0': + '@sentry-internal/replay-canvas@10.29.0': dependencies: - '@sentry-internal/replay': 9.9.0 - '@sentry/core': 9.9.0 + '@sentry-internal/replay': 10.29.0 + '@sentry/core': 10.29.0 - '@sentry-internal/replay@9.9.0': + '@sentry-internal/replay@10.29.0': dependencies: - '@sentry-internal/browser-utils': 9.9.0 - '@sentry/core': 9.9.0 + '@sentry-internal/browser-utils': 10.29.0 + '@sentry/core': 10.29.0 '@sentry/babel-plugin-component-annotate@2.22.7': {} - '@sentry/browser@9.9.0': + '@sentry/browser@10.29.0': dependencies: - '@sentry-internal/browser-utils': 9.9.0 - '@sentry-internal/feedback': 9.9.0 - '@sentry-internal/replay': 9.9.0 - '@sentry-internal/replay-canvas': 9.9.0 - '@sentry/core': 9.9.0 + '@sentry-internal/browser-utils': 10.29.0 + '@sentry-internal/feedback': 10.29.0 + '@sentry-internal/replay': 10.29.0 + '@sentry-internal/replay-canvas': 10.29.0 + '@sentry/core': 10.29.0 '@sentry/bundler-plugin-core@2.22.7': dependencies: @@ -5837,12 +5862,12 @@ snapshots: - encoding - supports-color - '@sentry/core@9.9.0': {} + '@sentry/core@10.29.0': {} - '@sentry/react@9.9.0(react@18.3.1)': + '@sentry/react@10.29.0(react@18.3.1)': dependencies: - '@sentry/browser': 9.9.0 - '@sentry/core': 9.9.0 + '@sentry/browser': 10.29.0 + '@sentry/core': 10.29.0 hoist-non-react-statics: 3.3.2 react: 18.3.1 @@ -9774,7 +9799,7 @@ snapshots: terser@5.31.1: dependencies: - '@jridgewell/source-map': 0.3.6 + '@jridgewell/source-map': 0.3.11 acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21