@kanadi/core
Version:
Multi-Layer CAPTCHA Framework with customizable validators and challenge bundles
73 lines (64 loc) • 1.89 kB
text/typescript
import { Injectable } from "@nestjs/common";
import {
BanRule,
BanDecision,
type IBanRule,
type BanContext,
type BanCheckResult,
} from "../";
import { BundleSessionRepository } from "../../models/bundle-session.repository";
()
({
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;
}
}