From a0ef684b41b81119109742af9bb5cf360da6be19 Mon Sep 17 00:00:00 2001 From: Dylan Audius Date: Tue, 19 May 2026 19:27:35 -0700 Subject: [PATCH 1/2] Remove FingerprintJS from all systems Removes FingerprintJS visitor identification end-to-end: web/mobile clients no longer fingerprint sign-in, identity service no longer bypasses OTP for "trusted" devices (all new devices now require OTP, which was the intended behavior), and the AAO no longer factors fingerprint device counts into user scores. Co-Authored-By: Claude Opus 4.7 (1M context) --- package-lock.json | 49 -------- packages/common/package.json | 1 - .../common/src/services/auth/authService.ts | 3 - packages/common/src/services/env.ts | 2 - .../services/fingerprint/FingerprintClient.ts | 61 ---------- .../common/src/services/fingerprint/index.ts | 1 - packages/common/src/services/index.ts | 1 - packages/common/src/store/storeContext.ts | 2 - .../apps/anti-abuse-oracle/src/actionLog.ts | 6 +- .../apps/anti-abuse-oracle/src/identity.ts | 44 ------- .../apps/anti-abuse-oracle/src/server.tsx | 44 +------ packages/identity-service/package.json | 1 - .../20260519000000-drop-fingerprints.js | 41 +++++++ packages/identity-service/src/app.js | 3 - packages/identity-service/src/config.js | 6 - packages/identity-service/src/fpClient.js | 22 ---- .../src/models/fingerprint.js | 34 ------ .../src/routes/authentication.js | 14 +-- packages/identity-service/src/routes/fp.js | 53 --------- .../identity-service/src/routes/idSignals.js | 62 +++++----- .../identity-service/src/utils/fpHelpers.js | 107 ------------------ packages/identity-service/src/utils/otp.js | 29 +---- .../test/authenticationTest.js | 79 ------------- packages/identity-service/test/lib/app.js | 18 --- packages/libs/src/api/Account.ts | 8 +- .../src/services/identity/IdentityService.ts | 1 - .../mobile/examples/auth-sign-in/README.md | 2 +- packages/mobile/package.json | 1 - .../screens/ConfirmEmailScreen.tsx | 4 +- .../sign-on-screen/screens/SignInScreen.tsx | 4 +- packages/mobile/src/services/env/env.dev.ts | 2 - packages/mobile/src/services/env/env.prod.ts | 2 - packages/mobile/src/services/fingerprint.ts | 20 ---- packages/mobile/src/store/storeContext.ts | 2 - packages/web/package.json | 1 - .../web/src/common/store/backend/sagas.ts | 5 - .../src/common/store/pages/signon/actions.ts | 10 +- .../src/common/store/pages/signon/sagas.ts | 20 +--- .../pages/oauth-login-page/OAuthLoginPage.tsx | 3 - packages/web/src/services/env/env.dev.ts | 2 - packages/web/src/services/env/env.prod.ts | 2 - packages/web/src/services/fingerprint.ts | 23 ---- packages/web/src/store/storeContext.ts | 2 - packages/web/src/test/vitest-setup.ts | 3 - 44 files changed, 83 insertions(+), 717 deletions(-) delete mode 100644 packages/common/src/services/fingerprint/FingerprintClient.ts delete mode 100644 packages/common/src/services/fingerprint/index.ts create mode 100644 packages/identity-service/sequelize/migrations/20260519000000-drop-fingerprints.js delete mode 100644 packages/identity-service/src/fpClient.js delete mode 100644 packages/identity-service/src/models/fingerprint.js delete mode 100644 packages/identity-service/src/routes/fp.js delete mode 100644 packages/identity-service/src/utils/fpHelpers.js delete mode 100644 packages/mobile/src/services/fingerprint.ts delete mode 100644 packages/web/src/services/fingerprint.ts diff --git a/package-lock.json b/package-lock.json index 8acc1252e08..fc98c4f29d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12601,51 +12601,6 @@ "node": ">=14" } }, - "node_modules/@fingerprintjs/fingerprintjs": { - "version": "3.3.3", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - } - }, - "node_modules/@fingerprintjs/fingerprintjs-pro": { - "version": "3.5.6", - "dependencies": { - "@fingerprintjs/fingerprintjs": "3.3.3", - "tslib": "^2.0.1" - } - }, - "node_modules/@fingerprintjs/fingerprintjs-pro-react-native": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-react-native/-/fingerprintjs-pro-react-native-3.9.0.tgz", - "integrity": "sha512-eu8AkyILtV7MU+70aVO8Prn0nEe9gKi9yohE8//hunOv6B0F4QbwJEFp9r6BW9isxw1LKGvjVq640XvR+iUbCw==", - "license": "MIT", - "peerDependencies": { - "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.2", - "expo": ">=51.0.0", - "react": "*", - "react-dom": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "@fingerprintjs/fingerprintjs-pro-spa": { - "optional": true - }, - "expo": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/@fingerprintjs/fingerprintjs-pro-server-api": { - "version": "4.1.2", - "license": "MIT", - "engines": { - "node": ">=18.17.0" - } - }, "node_modules/@floating-ui/core": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", @@ -109923,7 +109878,6 @@ "@audius/fetch-nft": "0.2.8", "@audius/fixed-decimal": "*", "@audius/sdk": "*", - "@fingerprintjs/fingerprintjs-pro": "3.5.6", "@jup-ag/api": "6.0.48", "@metaplex-foundation/mpl-token-metadata": "2.5.2", "@optimizely/optimizely-sdk": "4.0.0", @@ -125803,7 +125757,6 @@ "@audius/sdk-legacy": "*", "@audius/spl": "*", "@certusone/wormhole-sdk": "0.1.1", - "@fingerprintjs/fingerprintjs-pro-server-api": "4.1.2", "@improbable-eng/grpc-web-node-http-transport": "0.15.0", "@opentelemetry/api": "1.3.0", "@opentelemetry/instrumentation": "0.31.0", @@ -128668,7 +128621,6 @@ "@ebay/nice-modal-react": "^1.2.13", "@emotion/native": "^11.11.0", "@emotion/react": "11.14.0", - "@fingerprintjs/fingerprintjs-pro-react-native": "3.9.0", "@gorhom/bottom-sheet": "5.2.8", "@gorhom/portal": "1.0.14", "@hcaptcha/react-native-hcaptcha": "1.6.0", @@ -138120,7 +138072,6 @@ "@emotion/react": "11.14.0", "@emotion/server": "11.11.0", "@emotion/styled": "11.14.0", - "@fingerprintjs/fingerprintjs-pro": "3.5.6", "@google/model-viewer": "3.3.0", "@hcaptcha/react-hcaptcha": "0.3.6", "@juggle/resize-observer": "^3.3.1", diff --git a/packages/common/package.json b/packages/common/package.json index 690a0e80356..02e9851fb96 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -38,7 +38,6 @@ "@audius/fetch-nft": "0.2.8", "@audius/fixed-decimal": "*", "@audius/sdk": "*", - "@fingerprintjs/fingerprintjs-pro": "3.5.6", "@jup-ag/api": "6.0.48", "@metaplex-foundation/mpl-token-metadata": "2.5.2", "@optimizely/optimizely-sdk": "4.0.0", diff --git a/packages/common/src/services/auth/authService.ts b/packages/common/src/services/auth/authService.ts index 60599c615b4..d061f70ed71 100644 --- a/packages/common/src/services/auth/authService.ts +++ b/packages/common/src/services/auth/authService.ts @@ -31,7 +31,6 @@ export type AuthService = { signIn: ( email: string, password: string, - visitorId?: string, otp?: string ) => Promise signOut: () => Promise @@ -65,14 +64,12 @@ export const createAuthService = ({ const signIn = async ( email: string, password: string, - visitorId?: string, otp?: string ) => { const wallet = await hedgehogInstance.login({ email, username: email, password, - visitorId, otp }) diff --git a/packages/common/src/services/env.ts b/packages/common/src/services/env.ts index eac4c2418e4..fd130b09955 100644 --- a/packages/common/src/services/env.ts +++ b/packages/common/src/services/env.ts @@ -34,8 +34,6 @@ export type Env = { ETH_TOKEN_BRIDGE_ADDRESS: Nullable EXPLORE_CONTENT_URL: string FCM_PUSH_PUBLIC_KEY: Nullable - FINGERPRINT_ENDPOINT: Nullable - FINGERPRINT_PUBLIC_API_KEY: Nullable GA_HOSTNAME: string GA_MEASUREMENT_ID: string HCAPTCHA_BASE_URL: string diff --git a/packages/common/src/services/fingerprint/FingerprintClient.ts b/packages/common/src/services/fingerprint/FingerprintClient.ts deleted file mode 100644 index debb38a4fed..00000000000 --- a/packages/common/src/services/fingerprint/FingerprintClient.ts +++ /dev/null @@ -1,61 +0,0 @@ -type FingerprintClientConfig = { - apiKey: string - endpoint: string - identityService: string - initFingerprint: ( - apiKey: string, - endpoint: string - ) => Promise - getFingerprint: ( - client: TFingerprintClient, - options: { linkedId: string; tag: any } - ) => Promise -} - -export class FingerprintClient { - private apiKey: string - private fingerprint: TFingerprintClient | null - private endpoint: string - private initFingerprint: ( - apiKey: string, - endpoint: string - ) => Promise - - private getFingerprint: ( - client: TFingerprintClient, - options: { linkedId: string; tag: any } - ) => Promise - - constructor(config: FingerprintClientConfig) { - const { apiKey, endpoint, initFingerprint, getFingerprint } = config - this.apiKey = apiKey - this.fingerprint = null - this.endpoint = endpoint - this.initFingerprint = initFingerprint - this.getFingerprint = getFingerprint - } - - async init() { - try { - const fp = await this.initFingerprint(this.apiKey, this.endpoint) - this.fingerprint = fp - } catch (e) { - console.error(`Error initializing fingerprint client: ${e}`) - } - } - - async identify(email: string, clientOrigin: 'desktop' | 'mobile' | 'web') { - if (!this.fingerprint) { - console.warn('Fingerprint client not yet initted') - return - } - try { - return await this.getFingerprint(this.fingerprint, { - linkedId: email, - tag: { origin: clientOrigin } - }) - } catch (e) { - console.error(`Error identifying fingerprint client: ${e}`) - } - } -} diff --git a/packages/common/src/services/fingerprint/index.ts b/packages/common/src/services/fingerprint/index.ts deleted file mode 100644 index 6b6f35379e5..00000000000 --- a/packages/common/src/services/fingerprint/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './FingerprintClient' diff --git a/packages/common/src/services/index.ts b/packages/common/src/services/index.ts index bd4e3390c15..ff4b4a86eea 100644 --- a/packages/common/src/services/index.ts +++ b/packages/common/src/services/index.ts @@ -2,7 +2,6 @@ export * from './auth' export * from './remote-config' export * from './RandomImage' export * from './audius-backend' -export * from './fingerprint' export * from './local-storage' export * from './wallet-client' export * from './env' diff --git a/packages/common/src/store/storeContext.ts b/packages/common/src/store/storeContext.ts index 92a01c3625d..ba70451c9fe 100644 --- a/packages/common/src/store/storeContext.ts +++ b/packages/common/src/store/storeContext.ts @@ -19,7 +19,6 @@ import { AudioPlayer } from '../services/audio-player' import { AudiusBackend } from '../services/audius-backend' import { Env } from '../services/env' import { Explore } from '../services/explore' -import { FingerprintClient } from '../services/fingerprint' import { LocalStorage } from '../services/local-storage' import { FeatureFlags, RemoteConfigInstance } from '../services/remote-config' import { TrackDownload } from '../services/track-download' @@ -53,7 +52,6 @@ export type CommonStoreContext = { getHostUrl: () => string remoteConfigInstance: RemoteConfigInstance audiusBackendInstance: AudiusBackend - fingerprintClient: FingerprintClient walletClient: WalletClient localStorage: LocalStorage isNativeMobile: boolean diff --git a/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/actionLog.ts b/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/actionLog.ts index c82979cfb80..bbebec34ed3 100644 --- a/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/actionLog.ts +++ b/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/actionLog.ts @@ -2,7 +2,7 @@ import 'dotenv/config' import postgres from 'postgres' import fetch from 'cross-fetch' -import { useEmailDeliverable, useFingerprintDeviceCount } from './identity' +import { useEmailDeliverable } from './identity' export const sql = postgres(process.env.audius_db_url || '') @@ -157,8 +157,7 @@ export async function getUserNormalizedScore(userId: number, wallet: string) { // Convert values to numbers const shadowbanScore = Number(shadowban_score) - const numberOfUserWithFingerprint = (await useFingerprintDeviceCount(userId))! - let overallScore = shadowbanScore - numberOfUserWithFingerprint + let overallScore = shadowbanScore const isEmailDeliverable = await useEmailDeliverable(wallet) if (!isEmailDeliverable) { @@ -184,7 +183,6 @@ export async function getUserNormalizedScore(userId: number, wallet: string) { challengeCount: challenge_count, followingCount: following_count, chatBlockCount: chat_block_count, - fingerprintCount: numberOfUserWithFingerprint, isAudiusImpersonator: is_audius_impersonator, hasProfilePicture: has_profile_picture, isEmailDeliverable, diff --git a/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/identity.ts b/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/identity.ts index 174108e8c66..a788b552950 100644 --- a/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/identity.ts +++ b/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/identity.ts @@ -4,50 +4,6 @@ import postgres from 'postgres' export const sql = postgres(process.env.IDENTITY_DB_URL || '') -type FingerprintCount = { - fingerprint: string - userCount: number - userIds: number[] -} - -export async function userFingerprints(userId: number) { - const rows: FingerprintCount[] = await sql` - select - "visitorId" as "fingerprint", - count(distinct "userId") as "userCount", - array_agg("userId") as "userIds" - from "Fingerprints" - where "visitorId" in ( - select "visitorId" from "Fingerprints" where "userId" = ${userId} - ) - group by 1 order by 2 desc limit 90; - ` - - for (const row of rows) { - row.userIds.sort() - } - - return rows -} - -export async function useFingerprintDeviceCount(userId: number) { - const rows = await sql` - SELECT - MAX("userCount") AS "maxUserCount" - FROM ( - SELECT - "visitorId", - COUNT(DISTINCT "userId") AS "userCount" - FROM "Fingerprints" - WHERE "visitorId" IN ( - SELECT "visitorId" FROM "Fingerprints" WHERE "userId" = ${userId} - ) - GROUP BY "visitorId" - ) t; - ` - return rows[0].maxUserCount ?? 0 -} - export async function useEmailDeliverable(wallet: string) { const rows = await sql` select "isEmailDeliverable" from "Users" where "walletAddress" = ${wallet} diff --git a/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/server.tsx b/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/server.tsx index 35646db4418..37685038dee 100644 --- a/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/server.tsx +++ b/packages/discovery-provider/plugins/pedalboard/apps/anti-abuse-oracle/src/server.tsx @@ -11,15 +11,14 @@ import { sql, type ActionRow, type TrackDetails, - type UserDetails, - queryUsers + type UserDetails } from './actionLog' import { logger } from 'hono/logger' import { config } from './config' import { HashId } from '@audius/sdk' import { SolanaUtils, Utils } from '@audius/sdk-legacy' import bn from 'bn.js' -import { useEmail, userFingerprints } from './identity' +import { useEmail } from './identity' import { cors } from 'hono/cors' import { getAudiusSdk } from './sdk' @@ -359,11 +358,6 @@ app.get('/attestation/ui/user', async (c) => { if (!signals) return c.text(`user id not found: ${idOrHandle}`, 404) - const fingerprints = await userFingerprints(user.id) - const fingerprintUsers = await queryUsers({ - ids: fingerprints.flatMap((f) => f.userIds) - }) - let lastDate = '' function dateHeader(timestamp: Date) { const d = timestamp?.toDateString() @@ -489,16 +483,12 @@ app.get('/attestation/ui/user', async (c) => { - - @@ -560,36 +550,6 @@ app.get('/attestation/ui/user', async (c) => {
Fingerprint Count Deliverable Email Override Overall Score
0 ? 'text-red-500' : ''}> - {userScore.fingerprintCount} - {userScore.isEmailDeliverable.toString()}
-

Fingerprints

- - - - - - - - - - {fingerprints.map((f) => ( - - - - - - ))} - -
FingerprintUser CountUsers
{f.fingerprint}{f.userCount} - {f.userIds - .slice(0, 20) - .map((id) => fingerprintUsers.find((u) => u.id == id)) - .filter(Boolean) - .map((u) => ( - - {u!.handle} - - ))} -
-

Actions

{rows.map((r) => ( diff --git a/packages/identity-service/package.json b/packages/identity-service/package.json index c4c15bef374..b4a5f5c40ab 100644 --- a/packages/identity-service/package.json +++ b/packages/identity-service/package.json @@ -29,7 +29,6 @@ "@audius/sdk-legacy": "*", "@audius/spl": "*", "@certusone/wormhole-sdk": "0.1.1", - "@fingerprintjs/fingerprintjs-pro-server-api": "4.1.2", "@improbable-eng/grpc-web-node-http-transport": "0.15.0", "@opentelemetry/api": "1.3.0", "@opentelemetry/instrumentation": "0.31.0", diff --git a/packages/identity-service/sequelize/migrations/20260519000000-drop-fingerprints.js b/packages/identity-service/sequelize/migrations/20260519000000-drop-fingerprints.js new file mode 100644 index 00000000000..2e8b8f732b5 --- /dev/null +++ b/packages/identity-service/sequelize/migrations/20260519000000-drop-fingerprints.js @@ -0,0 +1,41 @@ +'use strict' + +module.exports = { + up: (queryInterface) => { + return queryInterface.dropTable('Fingerprints') + }, + + down: (queryInterface, Sequelize) => { + return queryInterface + .createTable('Fingerprints', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false + }, + visitorId: { + type: Sequelize.STRING, + allowNull: false + }, + origin: { + type: Sequelize.ENUM('web', 'mobile', 'desktop'), + allowNull: false + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }) + .then(() => queryInterface.addIndex('Fingerprints', ['userId'])) + .then(() => queryInterface.addIndex('Fingerprints', ['visitorId'])) + } +} diff --git a/packages/identity-service/src/app.js b/packages/identity-service/src/app.js index 31727758958..1f0ed4b5c01 100644 --- a/packages/identity-service/src/app.js +++ b/packages/identity-service/src/app.js @@ -4,7 +4,6 @@ const cookieParser = require('cookie-parser') const sgMail = require('@sendgrid/mail') const sgClient = require('@sendgrid/client') const { redisClient, Lock } = require('./redis') -const { createFpClient } = require('./fpClient') const optimizelySDK = require('@optimizely/optimizely-sdk') const cluster = require('cluster') const config = require('./config.js') @@ -35,7 +34,6 @@ class App { this.port = port this.express = express() this.redisClient = redisClient - this.fpClient = createFpClient(config.get('fpServerApiKey')) this.configureSendGrid() this.optimizelyPromise = null @@ -138,7 +136,6 @@ class App { server.headersTimeout = config.get('headersTimeout') this.express.set('redis', this.redisClient) - this.express.set('fpClient', this.fpClient) logger.info(`Listening on port ${this.port}...`) return { app: this.express, server } diff --git a/packages/identity-service/src/config.js b/packages/identity-service/src/config.js index 50bc37da610..4ef9c60c7b5 100644 --- a/packages/identity-service/src/config.js +++ b/packages/identity-service/src/config.js @@ -827,12 +827,6 @@ const config = convict({ env: 'solanaUSDCMintAddress', default: '' }, - fpServerApiKey: { - doc: 'API key for requesting visitorId information', - format: String, - env: 'fpServerApiKey', - default: '' - }, useDiscoveryListens: { doc: 'Forward listen requests to discovery', format: Boolean, diff --git a/packages/identity-service/src/fpClient.js b/packages/identity-service/src/fpClient.js deleted file mode 100644 index facd6dcab82..00000000000 --- a/packages/identity-service/src/fpClient.js +++ /dev/null @@ -1,22 +0,0 @@ -const { - FingerprintJsServerApiClient, - Region -} = require('@fingerprintjs/fingerprintjs-pro-server-api') - -const { logger } = require('./logging') - -const createFpClient = (apiKey) => { - if (!apiKey) { - logger.warn('API Key not set for fpClient') - return null - } else { - return new FingerprintJsServerApiClient({ - apiKey, - region: Region.Global - }) - } -} - -module.exports = { - createFpClient -} diff --git a/packages/identity-service/src/models/fingerprint.js b/packages/identity-service/src/models/fingerprint.js deleted file mode 100644 index 6a3a62e11ed..00000000000 --- a/packages/identity-service/src/models/fingerprint.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict' - -module.exports = (sequelize, DataTypes) => { - const Fingerprints = sequelize.define( - 'Fingerprints', - { - id: { - type: DataTypes.INTEGER, - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - userId: { - type: DataTypes.INTEGER, - allowNull: false, - index: true - }, - visitorId: { - type: DataTypes.STRING, - allowNull: false, - index: true - }, - origin: { - type: DataTypes.ENUM({ - values: ['web', 'mobile', 'desktop'], - allowNull: false - }) - } - }, - {} - ) - - return Fingerprints -} diff --git a/packages/identity-service/src/routes/authentication.js b/packages/identity-service/src/routes/authentication.js index 62828cbc1c6..712a7fc6de9 100644 --- a/packages/identity-service/src/routes/authentication.js +++ b/packages/identity-service/src/routes/authentication.js @@ -17,7 +17,6 @@ const { getWalletAssociatedEmail, associateWalletAddressWithUser } = require('../utils/walletAssociation') -const { validateFingerprint } = require('../utils/fpHelpers') const authMiddleware = require('../authMiddleware') const EncodedDataMessageHeader = 'encoded-data-message' @@ -227,13 +226,7 @@ module.exports = function (app) { app.get( '/authentication', handleResponse(async (req, res, next) => { - const { - lookupKey, - email: emailParam, - username, - visitorId, - otp - } = req.query + const { lookupKey, email: emailParam, username, otp } = req.query let email = emailParam ?? username if (!lookupKey) { return errorResponseBadRequest('Missing lookupKey') @@ -258,7 +251,7 @@ module.exports = function (app) { req.logger.error('Missing sendgrid api key') } - const otpRequired = await requiresOtp({ email, visitorId }) + const otpRequired = await requiresOtp({ email }) if (!otpRequired) { return successResponse(existingUser) } else if (!otp) { @@ -292,9 +285,6 @@ module.exports = function (app) { return errorResponseBadRequest('Invalid credentials') } - // async - validateFingerprint({ req, email, visitorId }) - if (existingUser.walletAddress === null) { await associateWalletAddressWithUser({ req, diff --git a/packages/identity-service/src/routes/fp.js b/packages/identity-service/src/routes/fp.js deleted file mode 100644 index 6e3cdd4589a..00000000000 --- a/packages/identity-service/src/routes/fp.js +++ /dev/null @@ -1,53 +0,0 @@ -const { - handleResponse, - successResponse, - errorResponseBadRequest, - errorResponse -} = require('../apiHelpers') -const models = require('../models') -const { logger } = require('../logging') -const { getDeviceIDCountForUserId } = require('../utils/fpHelpers') - -module.exports = function (app) { - app.get( - '/fp', - handleResponse(async (req) => { - const { userId, origin } = req.query - if (!userId || !origin || !['web', 'mobile', 'desktop'].includes(origin)) - return errorResponseBadRequest() - - try { - const count = ( - await models.Fingerprints.findAll({ - where: { - userId, - origin - } - }) - ).length - return successResponse({ count }) - } catch (e) { - return errorResponse( - `Something went wrong fetching fingerprint for user ${userId}: ${JSON.stringify( - e - )}` - ) - } - }) - ) - - app.get( - '/fp/counts/:userId', - handleResponse(async (req) => { - const userId = req.params.userId - try { - const counts = await getDeviceIDCountForUserId(userId) - return successResponse({ counts }) - } catch (e) { - return errorResponse( - `Something went wrong fetching fp counts: ${JSON.stringify(e)}` - ) - } - }) - ) -} diff --git a/packages/identity-service/src/routes/idSignals.js b/packages/identity-service/src/routes/idSignals.js index e55d6ddb5ce..a0adca05bfe 100644 --- a/packages/identity-service/src/routes/idSignals.js +++ b/packages/identity-service/src/routes/idSignals.js @@ -10,7 +10,6 @@ const models = require('../models') const { QueryTypes } = require('sequelize') const userHandleMiddleware = require('../userHandleMiddleware') const authMiddleware = require('../authMiddleware') -const { getDeviceIDCountForUserId } = require('../utils/fpHelpers') const { getIP, recordIP } = require('../utils/antiAbuse') module.exports = function (app) { @@ -25,53 +24,46 @@ module.exports = function (app) { const handle = req.query.handle if (!handle) return errorResponseBadRequest('Please provide handle') - const [ - captchaScores, - cognitoFlowScores, - deviceUserCount, - userIPRecord, - handleSimilarity - ] = await Promise.all([ - models.sequelize.query( - `select "Users"."blockchainUserId" as "userId", "BotScores"."recaptchaScore" as "score", "BotScores"."recaptchaContext" as "context", "BotScores"."updatedAt" as "updatedAt" + const [captchaScores, cognitoFlowScores, userIPRecord, handleSimilarity] = + await Promise.all([ + models.sequelize.query( + `select "Users"."blockchainUserId" as "userId", "BotScores"."recaptchaScore" as "score", "BotScores"."recaptchaContext" as "context", "BotScores"."updatedAt" as "updatedAt" from "Users" inner join "BotScores" on "Users"."walletAddress" = "BotScores"."walletAddress" where "Users"."handle" = :handle`, - { - replacements: { handle }, - type: QueryTypes.SELECT - } - ), - models.sequelize.query( - `select "Users"."blockchainUserId" as "userId", "CognitoFlows"."score" as "score" + { + replacements: { handle }, + type: QueryTypes.SELECT + } + ), + models.sequelize.query( + `select "Users"."blockchainUserId" as "userId", "CognitoFlows"."score" as "score" from "Users" inner join "CognitoFlows" on "Users"."handle" = "CognitoFlows"."handle" where "Users"."handle" = :handle`, - { - replacements: { handle }, - type: QueryTypes.SELECT - } - ), - getDeviceIDCountForUserId(req.user.blockchainUserId), - models.UserIPs.findOne({ where: { handle } }), - models.sequelize.query( - `select count(*) from "Users" where "handle" SIMILAR TO :handle;`, - { - replacements: { - handle: `[0-9]*${handle.replace(/(^\d*|\d*$)/g, '')}[0-9]*` - }, - type: QueryTypes.SELECT - } - ) - ]) + { + replacements: { handle }, + type: QueryTypes.SELECT + } + ), + models.UserIPs.findOne({ where: { handle } }), + models.sequelize.query( + `select count(*) from "Users" where "handle" SIMILAR TO :handle;`, + { + replacements: { + handle: `[0-9]*${handle.replace(/(^\d*|\d*$)/g, '')}[0-9]*` + }, + type: QueryTypes.SELECT + } + ) + ]) const response = { captchaScores, cognitoFlowScores, socialSignals: {}, - deviceUserCount, userIP: userIPRecord && userIPRecord.userIP, emailAddress: req.user.email, handleSimilarity: handleSimilarity[0]?.count ?? 0 diff --git a/packages/identity-service/src/utils/fpHelpers.js b/packages/identity-service/src/utils/fpHelpers.js deleted file mode 100644 index d755c67ea98..00000000000 --- a/packages/identity-service/src/utils/fpHelpers.js +++ /dev/null @@ -1,107 +0,0 @@ -const { QueryTypes } = require('sequelize') -const models = require('../models') -const FP_REDIS_PREFIX = 'fp' -const FP_CONFIDENCE_THRESHOLD = 0.7 -const TEN_MINUTES_IN_MS = 10 * 60 * 1000 - -const getDeviceIDCountForUserId = async (userId) => { - // Get the # of users sharing any visitorID - // associated with `userId` on any platform - const res = await models.sequelize.query( - `select "Fingerprints"."userId" - from "Fingerprints" - where "visitorId" in ( - select distinct "visitorId" - from "Fingerprints" - where "userId" = :userId - ) group by "Fingerprints"."userId"`, - { - replacements: { - userId - }, - type: QueryTypes.SELECT - } - ) - return res.length -} - -const validateFingerprint = async ({ req, email, visitorId }) => { - if (!visitorId) { - req.logger.info( - `Fingerprint not validated for ${email}: no visitorId provided` - ) - return - } - - const { blockchainUserId: userId } = await models.User.findOne({ - where: { email } - }) - if (!userId) { - req.logger.info( - `Fingerprint not validated for ${email}: no matching userId found` - ) - return - } - - let latestVisit - try { - const fpResponse = await req.app - .get('fpClient') - .getVisitorHistory(visitorId) - latestVisit = fpResponse.visits && fpResponse.visits[0] - } catch (e) { - req.logger.error(`Could not validate fingerprint for ${email}`, e) - return - } - - const now = Date.now() - if ( - !latestVisit || - now - new Date(latestVisit.timestamp) > TEN_MINUTES_IN_MS - ) { - req.logger.info( - `Fingerprint not validated for ${email}: no recent visit for id ${visitorId}` - ) - return - } - - // don't validate fingerprints that don't provide enough identifying signals - if ( - latestVisit.confidence && - latestVisit.confidence.score < FP_CONFIDENCE_THRESHOLD - ) { - req.logger.info( - `Fingerprint not validated for ${email}: confidence score ${latestVisit.confidence.score} below threshold` - ) - return - } - - const origin = latestVisit.tag?.origin - if (!origin) { - req.logger.info( - `Fingerprint not validated for ${email}: no origin tag found` - ) - return - } - - const [fp, created] = await models.Fingerprints.findOrCreate({ - where: { - userId, - visitorId, - origin - }, - defaults: { - createdAt: now, - updatedAt: now - } - }) - if (!created) { - fp.updatedAt = now - await fp.save() - } -} - -module.exports = { - getDeviceIDCountForUserId, - validateFingerprint -} diff --git a/packages/identity-service/src/utils/otp.js b/packages/identity-service/src/utils/otp.js index a062c757871..1377ed33104 100644 --- a/packages/identity-service/src/utils/otp.js +++ b/packages/identity-service/src/utils/otp.js @@ -1,6 +1,4 @@ const { getOtpEmail } = require('../notifications/emails/otp') -const { Op } = require('sequelize') -const models = require('../models') const OTP_CHARS = '0123456789' const OTP_REDIS_PREFIX = 'otp' @@ -13,31 +11,8 @@ const OTP_BYPASS_EMAILS = new Set([ 'fb@audius.co' ]) -const requiresOtp = async ({ email, visitorId }) => { - if (OTP_BYPASS_EMAILS.has(email)) { - return false - } else if (!visitorId) { - return true - } else { - const userRecord = await models.User.findOne({ - where: { email } - }) - if (!userRecord || userRecord.blockchainUserId === null) { - return true - } - const sixMonthsAgo = new Date() - sixMonthsAgo.setDate(-180) - const verifiedFp = await models.Fingerprints.findOne({ - where: { - userId: userRecord.blockchainUserId, - visitorId, - updatedAt: { - [Op.gt]: sixMonthsAgo - } - } - }) - return !verifiedFp - } +const requiresOtp = async ({ email }) => { + return !OTP_BYPASS_EMAILS.has(email) } const generateOtp = () => { diff --git a/packages/identity-service/test/authenticationTest.js b/packages/identity-service/test/authenticationTest.js index a002560d7c7..70b0ad650c0 100644 --- a/packages/identity-service/test/authenticationTest.js +++ b/packages/identity-service/test/authenticationTest.js @@ -607,83 +607,4 @@ describe('test authentication routes', function () { }) .expect(400) }) - - it('skips otp for recognized devices', async function () { - const redis = app.get('redis') - const visitorId = 'abc123' - await signUpUser() - const userRecord = await models.User.findOne({ - where: { email: 'dheeraj@audius.co' } - }) - await userRecord.update({ blockchainUserId: 1 }) - - await request(app) - .get('/authentication') - .query({ - lookupKey: - '9bdc91e1bb7ef60177131690b18349625778c14656dc17814945b52a3f07ac77', - username: 'dheeraj@audius.co', - visitorId - }) - .expect(403) - - let fpRecord = await models.Fingerprints.findOne({ where: { visitorId } }) - assert.strictEqual(fpRecord, null) - - const otp = await redis.get('otp:dheeraj@audius.co') - - await request(app) - .get('/authentication') - .query({ - lookupKey: - '9bdc91e1bb7ef60177131690b18349625778c14656dc17814945b52a3f07ac77', - username: 'dheeraj@audius.co', - visitorId, - otp - }) - .expect(200) - - // validateFingerprint is called asynchronously and not awaited. - // This should be plenty of time since the dependency is mocked in test/lib/app.js - await new Promise((resolve) => setTimeout(resolve, 100)) - - await request(app) - .get('/authentication') - .query({ - lookupKey: - '9bdc91e1bb7ef60177131690b18349625778c14656dc17814945b52a3f07ac77', - username: 'dheeraj@audius.co', - visitorId - }) - .expect(200) - - // a valid visitorId should not allow login with an invalid email - await request(app) - .get('/authentication') - .query({ - lookupKey: - '9bdc91e1bb7ef60177131690b18349625778c14656dc17814945b52a3f07ac77', - username: 'wrongemail@audius.co', - visitorId - }) - .expect(400) - - // a valid visitorId should not allow login with an invalid email, even with otp present - await request(app) - .get('/authentication') - .query({ - lookupKey: - '9bdc91e1bb7ef60177131690b18349625778c14656dc17814945b52a3f07ac77', - username: 'wrongemail@audius.co', - visitorId, - otp - }) - .expect(400) - - fpRecord = await models.Fingerprints.findOne({ where: { visitorId } }) - assert.ok(fpRecord) - assert.strictEqual(fpRecord.visitorId, visitorId) - - await fpRecord.destroy() - }) }) diff --git a/packages/identity-service/test/lib/app.js b/packages/identity-service/test/lib/app.js index 6dc16c06cb5..650c8b15b86 100644 --- a/packages/identity-service/test/lib/app.js +++ b/packages/identity-service/test/lib/app.js @@ -25,25 +25,7 @@ async function getApp() { } const audiusLibs = { captcha, solanaWeb3Manager } - const fpClient = { - getVisitorHistory: async (visitorId) => { - return { - visitorId, - visits: [ - { - confidence: { score: 0.8 }, // arbitrary non-perfect score - timestamp: Date.now(), - tag: { - origin: 'web' - } - } - ] - } - } - } - server.app.set('audiusLibs', audiusLibs) - server.app.set('fpClient', fpClient) // run all migrations before each test await clearDatabase() diff --git a/packages/libs/src/api/Account.ts b/packages/libs/src/api/Account.ts index ea5576c633b..fd1788bf65e 100644 --- a/packages/libs/src/api/Account.ts +++ b/packages/libs/src/api/Account.ts @@ -48,12 +48,7 @@ export class Account extends Base { /** * Logs a user into Audius */ - async login( - email: string, - password: string, - visitorId?: string, - otp?: string - ) { + async login(email: string, password: string, otp?: string) { const phases = { FIND_WALLET: 'FIND_WALLET', FIND_USER: 'FIND_USER' @@ -69,7 +64,6 @@ export class Account extends Base { email, username: email, password, - visitorId, otp }) this.web3Manager.setOwnerWallet(ownerWallet) diff --git a/packages/libs/src/services/identity/IdentityService.ts b/packages/libs/src/services/identity/IdentityService.ts index bd4fc86b318..a5bfd34e819 100644 --- a/packages/libs/src/services/identity/IdentityService.ts +++ b/packages/libs/src/services/identity/IdentityService.ts @@ -117,7 +117,6 @@ export class IdentityService { async getFn(params: { lookupKey: string username: string - visitorId?: string otp?: string }): Promise<{ iv: string; cipherText: string }> { return await this._makeRequest({ diff --git a/packages/mobile/examples/auth-sign-in/README.md b/packages/mobile/examples/auth-sign-in/README.md index a741eaa606b..af33102f40f 100644 --- a/packages/mobile/examples/auth-sign-in/README.md +++ b/packages/mobile/examples/auth-sign-in/README.md @@ -61,7 +61,7 @@ No extra setup; the app uses staging identity by default (see `packages/mobile/. |--------|----------| | Auth service (mobile) | `packages/mobile/src/services/sdk/auth.ts` – creates `authService` via `createAuthService`, wires `localStorage`, identity endpoint, key creation; exports `authService`, `getAudiusWalletClient`, `solanaWalletService`. | | Sign-on UI (screens, stack) | `packages/mobile/src/screens/sign-on-screen/` – `SignOnStack.tsx`, `SignOnScreen`, `CreatePasswordScreen`, `PickHandleScreen`, `FinishProfileScreen`, `ConfirmEmailScreen`, etc. | -| Auth service (shared API) | `packages/common/src/services/auth/authService.ts` – `createAuthService`, `signIn(email, password, visitorId?, otp?)`, `signOut`, `resetPassword`, `getWallet`, `confirmCredentials`, `changeCredentials`. | +| Auth service (shared API) | `packages/common/src/services/auth/authService.ts` – `createAuthService`, `signIn(email, password, otp?)`, `signOut`, `resetPassword`, `getWallet`, `confirmCredentials`, `changeCredentials`. | | Hedgehog / identity | `packages/common/src/services/auth/hedgehog.ts`, `identity.ts` – low-level Hedgehog instance and identity service integration. | | Sign-in validation | `packages/common/src/schemas/sign-on/signInSchema.ts` – Zod schema for sign-in form. | diff --git a/packages/mobile/package.json b/packages/mobile/package.json index fc9f5c20e93..75375c80a93 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -53,7 +53,6 @@ "@ebay/nice-modal-react": "^1.2.13", "@emotion/native": "^11.11.0", "@emotion/react": "11.14.0", - "@fingerprintjs/fingerprintjs-pro-react-native": "3.9.0", "@gorhom/bottom-sheet": "5.2.8", "@gorhom/portal": "1.0.14", "@hcaptcha/react-native-hcaptcha": "1.6.0", diff --git a/packages/mobile/src/screens/sign-on-screen/screens/ConfirmEmailScreen.tsx b/packages/mobile/src/screens/sign-on-screen/screens/ConfirmEmailScreen.tsx index 0b03849d9a3..3a8f84f7250 100644 --- a/packages/mobile/src/screens/sign-on-screen/screens/ConfirmEmailScreen.tsx +++ b/packages/mobile/src/screens/sign-on-screen/screens/ConfirmEmailScreen.tsx @@ -20,7 +20,6 @@ import { toFormikValidationSchema } from 'zod-formik-adapter' import { Text, TextLink } from '@audius/harmony-native' import { HarmonyTextField } from 'app/components/fields' import { useToast } from 'app/hooks/useToast' -import { fingerprintClient } from 'app/services/fingerprint' import { Heading, Page, PageFooter } from '../components/layout' import { useTrackScreen } from '../utils/useTrackScreen' @@ -50,8 +49,7 @@ export const ConfirmEmailScreen = () => { const { otp } = values const sanitizedOtp = otp.replace(/\s/g, '') dispatch(setValueField('otp', sanitizedOtp)) - const visitorId = await fingerprintClient.identify(email, 'mobile') - dispatch(signIn(email, password, visitorId, sanitizedOtp)) + dispatch(signIn(email, password, sanitizedOtp)) }, [dispatch, email, password] ) diff --git a/packages/mobile/src/screens/sign-on-screen/screens/SignInScreen.tsx b/packages/mobile/src/screens/sign-on-screen/screens/SignInScreen.tsx index 1b575d5406b..6a0f9bf9f4f 100644 --- a/packages/mobile/src/screens/sign-on-screen/screens/SignInScreen.tsx +++ b/packages/mobile/src/screens/sign-on-screen/screens/SignInScreen.tsx @@ -23,7 +23,6 @@ import { Button, Flex, IconArrowRight, TextLink } from '@audius/harmony-native' import { PasswordField } from 'app/components/fields' import { useDrawer } from 'app/hooks/useDrawer' import { useNavigation } from 'app/hooks/useNavigation' -import { fingerprintClient } from 'app/services/fingerprint' import { EmailField } from '../components/EmailField' import { GuestEmailHint } from '../components/GuestEmailHint' @@ -70,10 +69,9 @@ export const SignInScreen = () => { const handleSubmit = useCallback( async (values: SignInValues) => { const { email, password } = values - const visitorId = await fingerprintClient.identify(email, 'mobile') dispatch(setValueField('email', email)) dispatch(setValueField('password', password)) - dispatch(signIn(email, password, visitorId)) + dispatch(signIn(email, password)) }, [dispatch] ) diff --git a/packages/mobile/src/services/env/env.dev.ts b/packages/mobile/src/services/env/env.dev.ts index e9075beb3fa..ebd1a8021b4 100644 --- a/packages/mobile/src/services/env/env.dev.ts +++ b/packages/mobile/src/services/env/env.dev.ts @@ -35,8 +35,6 @@ export const env: Env = { EXPLORE_CONTENT_URL: 'https://download.audius.co/static-resources/explore-content.json', FCM_PUSH_PUBLIC_KEY: null, - FINGERPRINT_ENDPOINT: null, - FINGERPRINT_PUBLIC_API_KEY: null, GA_HOSTNAME: 'audius.co', GA_MEASUREMENT_ID: 'G-XXXXX', HCAPTCHA_BASE_URL: 'https://audius.co', diff --git a/packages/mobile/src/services/env/env.prod.ts b/packages/mobile/src/services/env/env.prod.ts index 40ef040d25a..1e30fbec222 100644 --- a/packages/mobile/src/services/env/env.prod.ts +++ b/packages/mobile/src/services/env/env.prod.ts @@ -36,8 +36,6 @@ export const env: Env = { EXPLORE_CONTENT_URL: 'https://download.audius.co/static-resources/explore-content.json', FCM_PUSH_PUBLIC_KEY: null, - FINGERPRINT_ENDPOINT: 'https://fp.audius.co', - FINGERPRINT_PUBLIC_API_KEY: 'MNtDQ4NCsNSP7YOkOiQT', GA_HOSTNAME: 'audius.co', GA_MEASUREMENT_ID: 'UA-120325397-2', HCAPTCHA_BASE_URL: 'https://audius.co', diff --git a/packages/mobile/src/services/fingerprint.ts b/packages/mobile/src/services/fingerprint.ts deleted file mode 100644 index 6827fd8467b..00000000000 --- a/packages/mobile/src/services/fingerprint.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { FingerprintClient } from '@audius/common/services' -import { FingerprintJsProAgent } from '@fingerprintjs/fingerprintjs-pro-react-native' - -import { env } from 'app/services/env' - -const apiKey = env.FINGERPRINT_PUBLIC_API_KEY || '' -const endpoint = env.FINGERPRINT_ENDPOINT || '' -const identityService = env.IDENTITY_SERVICE || '' - -export const fingerprintClient = new FingerprintClient({ - apiKey, - endpoint, - identityService, - initFingerprint: async (apiKey, endpoint) => { - return new FingerprintJsProAgent({ apiKey, endpointUrl: endpoint }) - }, - getFingerprint: (client, { tag, linkedId }) => { - return client.getVisitorId(tag, linkedId) - } -}) diff --git a/packages/mobile/src/store/storeContext.ts b/packages/mobile/src/store/storeContext.ts index b8e9b69df7d..47a51048ea8 100644 --- a/packages/mobile/src/store/storeContext.ts +++ b/packages/mobile/src/store/storeContext.ts @@ -6,7 +6,6 @@ import { audioPlayer } from 'app/services/audio-player' import { audiusBackendInstance } from 'app/services/audius-backend-instance' import { env } from 'app/services/env' import { explore } from 'app/services/explore' -import { fingerprintClient } from 'app/services/fingerprint' import { localStorage } from 'app/services/local-storage' import { queryClient } from 'app/services/query-client' import { @@ -36,7 +35,6 @@ export const storeContext: CommonStoreContext = { analytics, remoteConfigInstance, audiusBackendInstance, - fingerprintClient, walletClient, localStorage, isNativeMobile: true, diff --git a/packages/web/package.json b/packages/web/package.json index 766c62a2444..ff5ade839ff 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -80,7 +80,6 @@ "@emotion/react": "11.14.0", "@emotion/server": "11.11.0", "@emotion/styled": "11.14.0", - "@fingerprintjs/fingerprintjs-pro": "3.5.6", "@google/model-viewer": "3.3.0", "@hcaptcha/react-hcaptcha": "0.3.6", "@juggle/resize-observer": "^3.3.1", diff --git a/packages/web/src/common/store/backend/sagas.ts b/packages/web/src/common/store/backend/sagas.ts index 957cc0c1485..446b61a88d6 100644 --- a/packages/web/src/common/store/backend/sagas.ts +++ b/packages/web/src/common/store/backend/sagas.ts @@ -72,11 +72,6 @@ function* setupBackend() { console.info('Reconnected') } - const fingerprintClient = yield* getContext('fingerprintClient') - - // Fire-and-forget init fp - fingerprintClient.init() - // Start remote account fetch while we setup backend // Avoid setting the account as loading here since we already pulled the local account yield* put(accountActions.fetchAccount({ shouldMarkAccountAsLoading: false })) diff --git a/packages/web/src/common/store/pages/signon/actions.ts b/packages/web/src/common/store/pages/signon/actions.ts index 174e0f5fb7c..739256ef991 100644 --- a/packages/web/src/common/store/pages/signon/actions.ts +++ b/packages/web/src/common/store/pages/signon/actions.ts @@ -220,16 +220,10 @@ export const signUpFailed = ({ * Attemp sign-in to the account * @param email account email * @param password account password - * @param? visitorId fingerprint ID * @param? otp account otp */ -export function signIn( - email: string, - password: string, - visitorId?: string, - otp?: string -) { - return { type: SIGN_IN, email, password, visitorId, otp } +export function signIn(email: string, password: string, otp?: string) { + return { type: SIGN_IN, email, password, otp } } export const signInSucceeded = () => ({ type: SIGN_IN_SUCCEEDED }) diff --git a/packages/web/src/common/store/pages/signon/sagas.ts b/packages/web/src/common/store/pages/signon/sagas.ts index 868b5ef274b..0a51baf0775 100644 --- a/packages/web/src/common/store/pages/signon/sagas.ts +++ b/packages/web/src/common/store/pages/signon/sagas.ts @@ -720,34 +720,17 @@ function* signUp() { } function* signIn(action: ReturnType) { - const { email, password, visitorId, otp } = action + const { email, password, otp } = action yield* put(make(Name.SIGN_IN_START, {})) - const fingerprintClient = yield* getContext('fingerprintClient') const audiusBackendInstance = yield* getContext('audiusBackendInstance') const sdk = yield* getSDK() const authService = yield* getContext('authService') - const isNativeMobile = yield* getContext('isNativeMobile') - const isElectron = yield* getContext('isElectron') const queryClient = yield* getContext('queryClient') - const clientOrigin = isNativeMobile - ? 'mobile' - : isElectron - ? 'desktop' - : 'web' yield* call(waitForRead) try { const signOn = yield* select(getSignOn) - const isGuest = select(getIsGuest) - - const fpResponse = isGuest - ? undefined // guest account should not use fingerprint - : yield* call( - [fingerprintClient, fingerprintClient.identify], - email ?? signOn.email.value, - clientOrigin - ) let signInResponse: SignInResponse try { @@ -755,7 +738,6 @@ function* signIn(action: ReturnType) { authService.signIn, email ?? signOn.email.value, password ?? signOn.password.value, - visitorId ?? fpResponse?.visitorId, otp ?? signOn.otp.value ) } catch (err) { diff --git a/packages/web/src/pages/oauth-login-page/OAuthLoginPage.tsx b/packages/web/src/pages/oauth-login-page/OAuthLoginPage.tsx index 12fb69f98ff..6e6491cc3fa 100644 --- a/packages/web/src/pages/oauth-login-page/OAuthLoginPage.tsx +++ b/packages/web/src/pages/oauth-login-page/OAuthLoginPage.tsx @@ -33,7 +33,6 @@ import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' import { AccountListContent } from 'components/nav/desktop/AccountSwitcher/AccountListContent' import { ProfileInfo } from 'components/profile-info/ProfileInfo' import { audiusSdk, authService } from 'services/audius-sdk' -import { fingerprintClient } from 'services/fingerprint' import styles from './OAuthLoginPage.module.css' import { ApproveTransactionScreen } from './components/ApproveTransactionScreen' @@ -188,12 +187,10 @@ export const OAuthLoginPage = () => { setIsSubmitting(true) let signInResponse: SignInResponse try { - const fpResponse = await fingerprintClient.identify(emailInput, 'web') const sanitizedOtp = otpInput ? otpInput.replace(/\s/g, '') : undefined signInResponse = await authService.signIn( emailInput, passwordInput, - fpResponse?.visitorId, sanitizedOtp ) diff --git a/packages/web/src/services/env/env.dev.ts b/packages/web/src/services/env/env.dev.ts index 75d0c6493b8..b8b9925965f 100644 --- a/packages/web/src/services/env/env.dev.ts +++ b/packages/web/src/services/env/env.dev.ts @@ -34,8 +34,6 @@ export const env: Env = { EXPLORE_CONTENT_URL: 'https://download.audius.co/static-resources/explore-content.json', FCM_PUSH_PUBLIC_KEY: null, - FINGERPRINT_ENDPOINT: null, - FINGERPRINT_PUBLIC_API_KEY: null, GA_HOSTNAME: 'audius.co', GA_MEASUREMENT_ID: 'G-XXXXX', HCAPTCHA_BASE_URL: 'https://audius.co', diff --git a/packages/web/src/services/env/env.prod.ts b/packages/web/src/services/env/env.prod.ts index 487232a541e..c75332381a1 100644 --- a/packages/web/src/services/env/env.prod.ts +++ b/packages/web/src/services/env/env.prod.ts @@ -36,8 +36,6 @@ export const env: Env = { 'https://download.audius.co/static-resources/explore-content.json', FCM_PUSH_PUBLIC_KEY: 'BJlfnnPuZoLzcrS_K_NOJvqu_wFhguRuUDH8qPE_X-STh0CmWUuZHNPxMTr0YIHmuhKydiaSE2J0C1IAqA6YBFw', - FINGERPRINT_ENDPOINT: 'https://fp.audius.co', - FINGERPRINT_PUBLIC_API_KEY: 'MNtDQ4NCsNSP7YOkOiQT', GA_HOSTNAME: 'audius.co', GA_MEASUREMENT_ID: 'G-V6N1ZTVGS5', HCAPTCHA_BASE_URL: 'https://audius.co', diff --git a/packages/web/src/services/fingerprint.ts b/packages/web/src/services/fingerprint.ts deleted file mode 100644 index b7fad01a93e..00000000000 --- a/packages/web/src/services/fingerprint.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { FingerprintClient } from '@audius/common/services' -import FingerprintJS, { Agent } from '@fingerprintjs/fingerprintjs-pro' - -import { env } from './env' - -const apiKey = env.FINGERPRINT_PUBLIC_API_KEY || '' -const endpoint = env.FINGERPRINT_ENDPOINT || '' -const identityService = env.IDENTITY_SERVICE || '' - -export const fingerprintClient = new FingerprintClient({ - apiKey, - endpoint, - identityService, - initFingerprint: (apiKey, endpoint) => { - return FingerprintJS.load({ - apiKey, - endpoint - }) - }, - getFingerprint: (client, { tag, linkedId }) => { - return client.get({ tag, linkedId }) - } -}) diff --git a/packages/web/src/store/storeContext.ts b/packages/web/src/store/storeContext.ts index 720ff5c082b..8ee95307064 100644 --- a/packages/web/src/store/storeContext.ts +++ b/packages/web/src/store/storeContext.ts @@ -12,7 +12,6 @@ import { import { identityService } from 'services/audius-sdk/identity' import { env } from 'services/env' import { explore } from 'services/explore' -import { fingerprintClient } from 'services/fingerprint' import { localStorage } from 'services/local-storage' import { queryClient } from 'services/query-client' import { getFeatureEnabled } from 'services/remote-config/featureFlagHelpers' @@ -48,7 +47,6 @@ export const buildStoreContext = ({ analytics, remoteConfigInstance, audiusBackendInstance, - fingerprintClient, walletClient, localStorage, isNativeMobile: false, diff --git a/packages/web/src/test/vitest-setup.ts b/packages/web/src/test/vitest-setup.ts index 836794c797a..428135218f5 100644 --- a/packages/web/src/test/vitest-setup.ts +++ b/packages/web/src/test/vitest-setup.ts @@ -16,9 +16,6 @@ console.error = (...args) => { ) { return } - if (args[0].includes('Error initializing fingerprint client')) { - return - } } originalError.call(console, ...args) } From 8c02b5ba0f27b9b7c04a38dbf2d146558ab0a583 Mon Sep 17 00:00:00 2001 From: Dylan Audius Date: Tue, 19 May 2026 21:13:42 -0700 Subject: [PATCH 2/2] fix(web): restore isGuest/isNativeMobile usage and drop stale visitorId arg Removing FingerprintJS dropped isGuest/isNativeMobile declarations in the signIn saga and a visitorId parameter from the signIn action, but missed three downstream references and one caller still passing visitorId. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/web/src/common/store/pages/signon/sagas.ts | 2 ++ packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/web/src/common/store/pages/signon/sagas.ts b/packages/web/src/common/store/pages/signon/sagas.ts index 0a51baf0775..416a22826cb 100644 --- a/packages/web/src/common/store/pages/signon/sagas.ts +++ b/packages/web/src/common/store/pages/signon/sagas.ts @@ -726,11 +726,13 @@ function* signIn(action: ReturnType) { const audiusBackendInstance = yield* getContext('audiusBackendInstance') const sdk = yield* getSDK() const authService = yield* getContext('authService') + const isNativeMobile = yield* getContext('isNativeMobile') const queryClient = yield* getContext('queryClient') yield* call(waitForRead) try { const signOn = yield* select(getSignOn) + const isGuest = yield* select(getIsGuest) let signInResponse: SignInResponse try { diff --git a/packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx b/packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx index d380209273b..ccf4db781a2 100644 --- a/packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx +++ b/packages/web/src/pages/sign-in-page/ConfirmEmailPage.tsx @@ -52,7 +52,7 @@ export const ConfirmEmailPage = () => { dispatch(setValueField('otp', sanitizedOtp)) dispatch(setValueField('email', email)) dispatch(startSignUp()) - dispatch(signIn(email, password, undefined, sanitizedOtp)) + dispatch(signIn(email, password, sanitizedOtp)) }, [dispatch, email, password] )