UNPKG

@kanadi/core

Version:

Multi-Layer CAPTCHA Framework with customizable validators and challenge bundles

73 lines (64 loc) 1.89 kB
import { Injectable } from "@nestjs/common"; import { BanRule, BanDecision, type IBanRule, type BanContext, type BanCheckResult, } from "../"; import { BundleSessionRepository } from "../../models/bundle-session.repository"; @Injectable() @BanRule({ id: "suspicious_pattern", name: "Suspicious Pattern Detection", priority: 8, enabled: true, category: "pattern", description: "Detects suspicious device behavior patterns", }) export class SuspiciousPatternRule implements IBanRule { private bundleRepo = new BundleSessionRepository(); async check(context: BanContext): Promise<BanCheckResult> { const timeWindow = 5; const patterns = await this.bundleRepo.findSuspiciousPatterns(timeWindow); const suspiciousDevice = patterns.find( (p) => p.device_id === context.deviceId, ); if (suspiciousDevice && suspiciousDevice.sessions > this.getThreshold(context)) { const severity = suspiciousDevice.sessions > 10 ? BanDecision.BAN : BanDecision.WARN; return { decision: severity, ruleId: "suspicious_pattern", ruleName: "Suspicious Pattern Detection", confidence: 0.8, reason: `Unusual session pattern: ${suspiciousDevice.sessions} sessions from ${suspiciousDevice.ips.length} different IPs`, evidence: { sessionCount: suspiciousDevice.sessions, totalBundles: suspiciousDevice.total_bundles, uniqueIPs: suspiciousDevice.ips, timeWindow, }, expiresAt: new Date(Date.now() + 30 * 60 * 1000), shouldCache: true, }; } return { decision: BanDecision.ALLOW, ruleId: "suspicious_pattern", ruleName: "Suspicious Pattern Detection", confidence: 1.0, reason: "Normal session pattern", evidence: {}, shouldCache: false, }; } canExecute(context: BanContext): boolean { return !!context.deviceId; } getThreshold(context: BanContext): number { return 5; } }