Skip to content

Commit

Permalink
Collector to send to mongodb for dev environments only (#1078)
Browse files Browse the repository at this point in the history
* refactor of logTouchEvent

* Adding correct collecter logic

* Env tempaltes updated

* Onhuman updates and linting

* Cypress test and env fix

* Vite frontend config fix

* Let mongo cause provider to fall over
  • Loading branch information
HughParry authored Mar 13, 2024
1 parent ff3c045 commit 937a8ec
Show file tree
Hide file tree
Showing 14 changed files with 56 additions and 61 deletions.
2 changes: 2 additions & 0 deletions demos/client-example-server/env.development
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ PROSOPO_SITE_PRIVATE_KEY=//Bob
PROSOPO_SERVER_PORT=9228
PROSOPO_DEFAULT_ENVIRONMENT=development
PROSOPO_DEFAULT_NETWORK=development
PROSOPO_MONGO_EVENTS_URI=mongodb+srv://<MONGO_URI_HERE>/frictionless_events
_DEV_ONLY_WATCH_EVENTS=false
2 changes: 2 additions & 0 deletions demos/client-example/env.development
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ PROSOPO_SERVER_URL=http://localhost:9228
PROSOPO_PORT=9230
PROSOPO_DEFAULT_NETWORK=development
PROSOPO_DEFAULT_ENVIRONMENT=development
PROSOPO_MONGO_EVENTS_URI=mongodb+srv://<MONGO_URI_HERE>/frictionless_events
_DEV_ONLY_WATCH_EVENTS=false
7 changes: 4 additions & 3 deletions demos/client-example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import {
ApiParams,
EnvironmentTypes,
EnvironmentTypesSchema,
ProcaptchaConfigSchema,
ProcaptchaOutput,
ProsopoClientConfigSchema,
} from '@prosopo/types'
import { ExtensionAccountSelect, Procaptcha } from '@prosopo/procaptcha-react'
import { useState } from 'react'
Expand All @@ -40,7 +40,7 @@ function App() {
// the result of the captcha process. Submit this to your backend server to verify the user is human on the backend
const [procaptchaOutput, setProcaptchaOutput] = useState<ProcaptchaOutput | undefined>(undefined)

const config = ProsopoClientConfigSchema.parse({
const config = ProcaptchaConfigSchema.parse({
userAccountAddress: account,
account: {
address: process.env.PROSOPO_SITE_KEY || '',
Expand All @@ -50,7 +50,8 @@ function App() {
defaultEnvironment:
(process.env.PROSOPO_DEFAULT_ENVIRONMENT as EnvironmentTypes) || EnvironmentTypesSchema.enum.development,
serverUrl: process.env.PROSOPO_SERVER_URL || '',
atlasUri: process.env._DEV_ONLY_WATCH_EVENTS === 'true' || false,
mongoAtlasUri: process.env.PROSOPO_MONGO_EVENTS_URI || '',
devOnlyWatchEvents: process.env._DEV_ONLY_WATCH_EVENTS === 'true' || false,
})

const label = isLogin ? 'Login' : 'Sign up'
Expand Down
1 change: 1 addition & 0 deletions dev/config/src/vite/vite.frontend.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export default async function (
'process.env.PROSOPO_DEFAULT_NETWORK': JSON.stringify(process.env.PROSOPO_DEFAULT_NETWORK),
'process.env.PROSOPO_SERVER_URL': JSON.stringify(process.env.PROSOPO_SERVER_URL),
'process.env._DEV_ONLY_WATCH_EVENTS': JSON.stringify(process.env._DEV_ONLY_WATCH_EVENTS),
'process.env.PROSOPO_MONGO_EVENTS_URI': JSON.stringify(process.env.PROSOPO_MONGO_EVENTS_URI),
'process.env.PROSOPO_CONTRACT_ADDRESS': JSON.stringify(process.env.PROSOPO_CONTRACT_ADDRESS),
// only needed if bundling with a site key
'process.env.PROSOPO_SITE_KEY': JSON.stringify(process.env.PROSOPO_SITE_KEY),
Expand Down
2 changes: 2 additions & 0 deletions dev/scripts/env.development
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ NODE_ENV=development
PROSOPO_LOG_LEVEL=debug
PROSOPO_DEFAULT_ENVIRONMENT=development
PROSOPO_DEFAULT_NETWORK=development
PROSOPO_MONGO_EVENTS_URI=mongodb+srv://<MONGO_URI_HERE>/frictionless_events
_DEV_ONLY_WATCH_EVENTS=false
2 changes: 2 additions & 0 deletions packages/cli/src/prosopo.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,7 @@ export default function getConfig(
captchaSolutions: captchaSolutionsConfig,
batchCommit: batchCommitConfig,
captchas: captchaServeConfig,
devOnlyWatchEvents: process.env._DEV_ONLY_WATCH_EVENTS === 'true',
mongoEventsUri: process.env.PROSOPO_MONGO_EVENTS_URI || '',
} as ProsopoConfigInput)
}
49 changes: 8 additions & 41 deletions packages/database/src/eventsDatabase/eventsDatabase.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ProsopoDBError, getLoggerDefault } from '@prosopo/common'
import { StoredEventRecord, StoredEvents } from '@prosopo/types'
import { getLoggerDefault } from '@prosopo/common'
import mongoose, { Model } from 'mongoose'
const logger = getLoggerDefault()
const MAX_RETRIES = 3
Expand Down Expand Up @@ -36,47 +36,14 @@ try {
CaptchaEvent = mongoose.model('CaptchaEvent', captchaEventSchema)
}

const addCaptchaEventRecord = async (record: StoredEventRecord): Promise<void> => {
try {
const newRecord = new CaptchaEvent(record)
await newRecord.save()
logger.info('Record added successfully')
} catch (error) {
logger.error('Error adding record to the database:', error)
}
}

export const saveCaptchaEvent = async (events: StoredEvents, accountId: string, atlasUri: string) => {
return new Promise((resolve, reject) => {
const connection = mongoose.createConnection(atlasUri)
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
connection.once('open', resolve).on('error', (e) => {
logger.warn(`Mongoose connection error`)
logger.error(e)
await mongoose.connect(atlasUri).then(() => console.log('Connected to MongoDB Atlas'))

// Only reject on the last attempt, otherwise handle the retry logic
if (attempt === MAX_RETRIES) {
reject(
new ProsopoDBError('DATABASE.CONNECT_ERROR', {
context: { failedFuncName: saveCaptchaEvent.name, db: 'events database' },
logger: logger,
})
)
} else {
// Remove the error listener to avoid accumulated listeners on retries
connection?.removeAllListeners('error')
}
})
}

const captchaEventData = {
...events,
accountId,
}
const captchaEventData = {
...events,
accountId,
}

addCaptchaEventRecord(captchaEventData)
.then(() => logger.info('Captcha event data saved'))
.catch((error) => logger.error('Error saving captcha event data:', error))
.finally(() => connection.close())
})
const saved = await CaptchaEvent.create(captchaEventData)
console.log('Mongo Saved Event', saved)
}
3 changes: 2 additions & 1 deletion packages/procaptcha-bundle/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ const getConfig = (siteKey?: string) => {
address: siteKey,
},
serverUrl: process.env.PROSOPO_SERVER_URL || '',
mongoAtlasUri: process.env._DEV_ONLY_WATCH_EVENTS === 'true' || false,
mongoAtlasUri: process.env.PROSOPO_MONGO_EVENTS_URI || '',
devOnlyWatchEvents: process.env._DEV_ONLY_WATCH_EVENTS === 'true' || false,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ const ProcaptchaWidget = (props: ProcaptchaProps) => {
</div>
</div>
{config.devOnlyWatchEvents && (
<Collector onProcessData={manager.exportData} sendData={state.showModal}></Collector>
<Collector onProcessData={manager.exportData} sendData={state.sendData}></Collector>
)}
</div>
)
Expand Down
27 changes: 24 additions & 3 deletions packages/procaptcha/src/modules/Manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ export function Manager(
},
onOpen: () => {
console.log('onOpen event triggered')
updateState({ sendData: !state.sendData })
},
onClose: () => {
console.log('onClose event triggered')
Expand Down Expand Up @@ -597,12 +596,34 @@ export function Manager(
}

const exportData = async (events: StoredEvents) => {
const providerUrlFromStorage = storage.getProviderUrl()
let providerApi: ProviderApi

if (providerUrlFromStorage) {
providerApi = await loadProviderApi(providerUrlFromStorage)
} else {
const contract = await loadContract()
const getRandomProviderResponse: RandomProvider = await wrapQuery(
contract.query.getRandomActiveProvider,
contract.query
)(getAccount().account.address, getDappAccount())
const providerUrl = trimProviderUrl(getRandomProviderResponse.provider.url.toString())
providerApi = await loadProviderApi(providerUrl)
}

const providerUrl = storage.getProviderUrl() || state.captchaApi?.provider.provider.url.toString()
if (!providerUrl) {
return
}
const providerApi = await loadProviderApi(providerUrl)
await providerApi.submitUserEvents(events, getAccount().account.address)
console.log('Submitting events to provider', events)

let account = ''
try {
account = getAccount().account.address
} catch (e) {
console.error(e)
}
await providerApi.submitUserEvents(events, account)
}

return {
Expand Down
9 changes: 2 additions & 7 deletions packages/procaptcha/src/modules/collector.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ProsopoKeyboardEvent, ProsopoMouseEvent, ProsopoTouchEvent } from '@prosopo/types'

const COLLECTOR_LIMIT = 1000
const COLLECTOR_LIMIT = 10000

type SetStateAction<T> = T | ((prevState: T) => T)
type SetStateEvent<T> = (setValueFunc: SetStateAction<T[]>) => void
Expand Down Expand Up @@ -38,12 +38,7 @@ const logKeyboardEvent = (event: globalThis.KeyboardEvent, setKeyboardEvent: Set
}

const logTouchEvent = (event: globalThis.TouchEvent, setTouchEvent: SetTouchEvent) => {
// Iterate over the TouchList (map doesn't work on TouchList)
for (let i = 0; i < event.touches.length; i++) {
const touch = event.touches[i]
if (!touch) {
continue
}
for (const touch of Array.from(event.touches)) {
storeLog({ x: touch.clientX, y: touch.clientY, timestamp: event.timeStamp }, setTouchEvent)
}
}
Expand Down
5 changes: 3 additions & 2 deletions packages/provider/src/tasks/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -711,9 +711,10 @@ export class Tasks {
}

async saveCaptchaEvent(events: StoredEvents, accountId: string) {
if (!this.config.mongoAtlasUri) {
if (!this.config.devOnlyWatchEvents || !this.config.mongoEventsUri) {
console.log('Dev watch events not set to true, not saving events')
return
}
await saveCaptchaEvent(events, accountId, this.config.mongoAtlasUri)
await saveCaptchaEvent(events, accountId, this.config.mongoEventsUri)
}
}
4 changes: 2 additions & 2 deletions packages/types/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export const ProsopoBasicConfigSchema = ProsopoBaseConfigSchema.merge(
object({
networks: ProsopoNetworksSchema.default(networks),
database: DatabaseConfigSchema.optional(),
devOnlyWatchEvents: boolean().optional(),
})
)
export type ProsopoNetworksSchemaInput = input<typeof ProsopoNetworksSchema>
Expand Down Expand Up @@ -145,7 +146,6 @@ export const ProcaptchaConfigSchema = ProsopoClientConfigSchema.and(
accountCreator: AccountCreatorConfigSchema.optional(),
theme: ThemeType.optional(),
challengeValidLength: number().positive().optional(),
devOnlyWatchEvents: boolean().optional(),
})
)

Expand All @@ -168,7 +168,7 @@ export const ProsopoConfigSchema = ProsopoBasicConfigSchema.merge(
maxBatchExtrinsicPercentage: 59,
}),
server: ProsopoImageServerConfigSchema,
mongoAtlasUri: string().optional(),
mongoEventsUri: string().optional(),
})
)

Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/procaptcha/collector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ export type StoredEvents = {
}

export interface StoredEventRecord extends StoredEvents {
accountId: string
accountId?: string
}

0 comments on commit 937a8ec

Please sign in to comment.