From 9d86c37e53585057ee1c39445a97a8cdc2bf25d7 Mon Sep 17 00:00:00 2001 From: mantikoros Date: Tue, 18 Jan 2022 16:32:02 -0600 Subject: [PATCH] createUser: create private user; detect multiple signups --- functions/src/create-user.ts | 47 +++++++++++++++++++++++++++++++++--- web/lib/firebase/api-call.ts | 12 +++++++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/functions/src/create-user.ts b/functions/src/create-user.ts index aba7b8e8..d50f017b 100644 --- a/functions/src/create-user.ts +++ b/functions/src/create-user.ts @@ -1,13 +1,18 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' -import { STARTING_BALANCE, User } from '../../common/user' +import { + PrivateUser, + STARTING_BALANCE, + SUS_STARTING_BALANCE, + User, +} from '../../common/user' import { getUser, getUserByUsername } from './utils' import { randomString } from '../../common/util/random' export const createUser = functions .runWith({ minInstances: 1 }) - .https.onCall(async (_, context) => { + .https.onCall(async (data: { deviceToken?: string }, context) => { const userId = context?.auth?.uid if (!userId) return { status: 'error', message: 'Not authorized' } @@ -34,12 +39,22 @@ export const createUser = functions const avatarUrl = fbUser.photoURL + const { deviceToken } = data + const deviceUsedBefore = + !deviceToken || (await isPrivateUserWithDeviceToken(deviceToken)) + + const ipAddress = context.rawRequest.ip + const ipCount = ipAddress ? await numberUsersWithIp(ipAddress) : 0 + + const balance = + deviceUsedBefore || ipCount > 2 ? SUS_STARTING_BALANCE : STARTING_BALANCE + const user: User = { id: userId, name, username, avatarUrl, - balance: STARTING_BALANCE, + balance, createdTime: Date.now(), totalPnLCached: 0, creatorVolumeCached: 0, @@ -48,6 +63,14 @@ export const createUser = functions await firestore.collection('users').doc(userId).create(user) console.log('created user', username, 'firebase id:', userId) + const privateUser: PrivateUser = { + email, + initialIpAddress: ipAddress, + initialDeviceToken: deviceToken, + } + + await firestore.collection('private-users').doc(userId).create(privateUser) + return { status: 'success', user } }) @@ -60,3 +83,21 @@ const cleanUsername = (name: string) => { } const firestore = admin.firestore() + +const isPrivateUserWithDeviceToken = async (deviceToken: string) => { + const snap = await firestore + .collection('private-users') + .where('initialDeviceToken', '==', deviceToken) + .get() + + return !snap.empty +} + +const numberUsersWithIp = async (ipAddress: string) => { + const snap = await firestore + .collection('private-users') + .where('initialIpAddress', '==', ipAddress) + .get() + + return snap.docs.length +} diff --git a/web/lib/firebase/api-call.ts b/web/lib/firebase/api-call.ts index a5d80200..6c5e98ab 100644 --- a/web/lib/firebase/api-call.ts +++ b/web/lib/firebase/api-call.ts @@ -1,5 +1,6 @@ import { getFunctions, httpsCallable } from 'firebase/functions' import { User } from '../../../common/user' +import { randomString } from '../../../common/util/random' const functions = getFunctions() @@ -13,7 +14,14 @@ export const resolveMarket = cloudFunction('resolveMarket') export const sellBet = cloudFunction('sellBet') -export const createUser: () => Promise = () => - cloudFunction('createUser')({}) +export const createUser: () => Promise = () => { + let deviceToken = window.localStorage.getItem('device-token') + if (!deviceToken) { + deviceToken = randomString() + window.localStorage.setItem('device-token', deviceToken) + } + + return cloudFunction('createUser')({ deviceToken }) .then((r) => (r.data as any)?.user || null) .catch(() => null) +}