UNPKG

@kanadi/core

Version:

Multi-Layer CAPTCHA Framework with customizable validators and challenge bundles

171 lines (156 loc) 4.25 kB
import { sql } from "bun"; export interface KanadiValidatorSession { id: string; bundle_session_id?: string; validator_id: string; session_id?: string; solve_id?: string; result?: string; score?: number; confidence?: number; processing_time?: number; data: any; evidence?: any; decrypted_data?: any; created_at: Date; updated_at: Date; } export class ValidatorSessionRepository { async create(data: { bundleSessionId?: string; validatorId: string; sessionId?: string; solveId?: string; result?: string; score?: number; confidence?: number; processingTime?: number; evidence?: any; decryptedData?: any; }): Promise<KanadiValidatorSession> { const result = await sql` INSERT INTO kanadi_validator_sessions ( bundle_session_id, validator_id, session_id, solve_id, result, score, confidence, processing_time, evidence, decrypted_data ) VALUES ( ${data.bundleSessionId || null}, ${data.validatorId}, ${data.sessionId || null}, ${data.solveId || null}, ${data.result || null}, ${data.score || null}, ${data.confidence || null}, ${data.processingTime || null}, ${data.evidence ? JSON.stringify(data.evidence) : null}, ${data.decryptedData ? JSON.stringify(data.decryptedData) : null} ) RETURNING * `; return result[0] as KanadiValidatorSession; } async findBySolveId(solveId: string): Promise<KanadiValidatorSession[]> { const result = await sql` SELECT * FROM kanadi_validator_sessions WHERE solve_id = ${solveId} ORDER BY created_at DESC `; return result as KanadiValidatorSession[]; } async findBySessionId(sessionId: string): Promise<KanadiValidatorSession[]> { const result = await sql` SELECT * FROM kanadi_validator_sessions WHERE session_id = ${sessionId} ORDER BY created_at DESC `; return result as KanadiValidatorSession[]; } async findByValidatorId( validatorId: string, limit: number = 100, ): Promise<KanadiValidatorSession[]> { const result = await sql` SELECT * FROM kanadi_validator_sessions WHERE validator_id = ${validatorId} ORDER BY created_at DESC LIMIT ${limit} `; return result as KanadiValidatorSession[]; } async getStats(): Promise<{ total: number; byResult: { pass: number; fail: number; suspicious: number }; byValidator: Record<string, number>; avgScore: number; avgConfidence: number; }> { const totalResult = await sql` SELECT COUNT(*) as count FROM kanadi_validator_sessions `; const byResultResult = await sql` SELECT result, COUNT(*) as count FROM kanadi_validator_sessions WHERE result IS NOT NULL GROUP BY result `; const byValidatorResult = await sql` SELECT validator_id, COUNT(*) as count FROM kanadi_validator_sessions GROUP BY validator_id `; const avgResult = await sql` SELECT AVG(score) as avg_score, AVG(confidence) as avg_confidence FROM kanadi_validator_sessions WHERE score IS NOT NULL AND confidence IS NOT NULL `; const byResult = { pass: 0, fail: 0, suspicious: 0, }; for (const row of byResultResult) { const result = (row as any).result?.toLowerCase(); const count = Number((row as any).count || 0); if (result === "pass") byResult.pass = count; else if (result === "fail") byResult.fail = count; else if (result === "suspicious") byResult.suspicious = count; } const byValidator: Record<string, number> = {}; for (const row of byValidatorResult) { const validatorId = (row as any).validator_id; const count = Number((row as any).count || 0); byValidator[validatorId] = count; } return { total: Number(totalResult[0]?.count || 0), byResult, byValidator, avgScore: Number(avgResult[0]?.avg_score || 0), avgConfidence: Number(avgResult[0]?.avg_confidence || 0), }; } async findSuspiciousActivity(days: number = 7): Promise<KanadiValidatorSession[]> { const result = await sql` SELECT * FROM kanadi_validator_sessions WHERE result IN ('FAIL', 'SUSPICIOUS') AND created_at >= CURRENT_TIMESTAMP - INTERVAL '${sql.raw(days.toString())} days' ORDER BY created_at DESC LIMIT 1000 `; return result as KanadiValidatorSession[]; } }