Spaces:
Sleeping
Sleeping
updloads
Browse files- app/core/config.py +0 -0
- app/core/engine.py +73 -0
- app/core/security.py +0 -0
app/core/config.py
ADDED
|
File without changes
|
app/core/engine.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from typing import List
|
| 3 |
+
from app.api.schemas.telemetry import KeystrokeData
|
| 4 |
+
from fastapi import HTTPException
|
| 5 |
+
|
| 6 |
+
class DECI_Engine:
|
| 7 |
+
def __init__(self):
|
| 8 |
+
self.MIN_KEYSTROKES = 25 # [cite: 5, 52]
|
| 9 |
+
self.WEIGHTS = {"entropy": 0.35, "cv": 0.30, "mean": 0.15, "corrections": 0.20} # [cite: 5, 101]
|
| 10 |
+
|
| 11 |
+
def process_session(self, events: List[KeystrokeData]) -> dict:
|
| 12 |
+
if len(events) < self.MIN_KEYSTROKES:
|
| 13 |
+
return {"verdict": "INCONCLUSIVE", "reason": f"Need {self.MIN_KEYSTROKES} keys"}
|
| 14 |
+
|
| 15 |
+
# Extraer intervalos compatibles con v2.0 [cite: 5, 111]
|
| 16 |
+
timestamps = np.array([float(e.timestamp) for e in events])
|
| 17 |
+
intervals = np.diff(timestamps)
|
| 18 |
+
intervals = intervals[intervals > 0]
|
| 19 |
+
|
| 20 |
+
# 1. Shannon Entropy Normalizada (Fixed by Claude) [cite: 5, 111]
|
| 21 |
+
entropy = self._compute_shannon_entropy(intervals)
|
| 22 |
+
|
| 23 |
+
# 2. Coeficiente de Variación (CV) [cite: 5, 111]
|
| 24 |
+
cv = np.std(intervals) / np.mean(intervals) if len(intervals) > 0 else 0
|
| 25 |
+
|
| 26 |
+
# 3. Burst Correction Ratio [cite: 5, 59]
|
| 27 |
+
burst_ratio = self._compute_burst_ratio(events)
|
| 28 |
+
|
| 29 |
+
# ── Scoring Multi-señal (Vertex Elite Logic) ──
|
| 30 |
+
# Entropy Goldilocks Zone [cite: 5, 59]
|
| 31 |
+
s_entropy = 1.0 if 0.50 <= entropy <= 0.85 else (0.5 if 0.35 <= entropy <= 0.95 else 0.05)
|
| 32 |
+
s_cv = 1.0 if cv > 0.50 else (0.6 if cv > 0.30 else 0.1)
|
| 33 |
+
|
| 34 |
+
# Mean IKL Scoring
|
| 35 |
+
mean_ms = np.mean(intervals)
|
| 36 |
+
s_mean = 1.0 if 60 <= mean_ms <= 500 else 0.2
|
| 37 |
+
|
| 38 |
+
# Correction Scoring con Bonus de Ráfaga [cite: 5, 59]
|
| 39 |
+
corr_rate = sum(1 for e in events if e.key == 'Backspace') / len(events)
|
| 40 |
+
s_corrections = (0.5 + burst_ratio * 0.5) if 0.02 <= corr_rate <= 0.15 else 0.2
|
| 41 |
+
|
| 42 |
+
# Weighted Final Score
|
| 43 |
+
final_score = float(np.clip(
|
| 44 |
+
s_entropy * self.WEIGHTS["entropy"] +
|
| 45 |
+
s_cv * self.WEIGHTS["cv"] +
|
| 46 |
+
s_mean * self.WEIGHTS["mean"] +
|
| 47 |
+
s_corrections * self.WEIGHTS["corrections"], 0.0, 1.0
|
| 48 |
+
))
|
| 49 |
+
|
| 50 |
+
return {
|
| 51 |
+
"score": round(final_score, 4),
|
| 52 |
+
"verdict": "HUMAN" if final_score >= 0.65 else ("SUSPECT" if final_score >= 0.40 else "BOT"), #
|
| 53 |
+
"is_human": final_score >= 0.65,
|
| 54 |
+
"breakdown": {"entropy": round(entropy, 4), "cv": round(cv, 4), "burst": round(burst_ratio, 4)}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
def _compute_shannon_entropy(self, intervals, bins=20):
|
| 58 |
+
hist, _ = np.histogram(intervals, bins=bins, density=True)
|
| 59 |
+
hist += 1e-10
|
| 60 |
+
raw_entropy = -np.sum(hist * np.log2(hist)) * (intervals.max() - intervals.min()) / bins
|
| 61 |
+
return float(np.clip(raw_entropy / np.log2(bins), 0.0, 1.0))
|
| 62 |
+
|
| 63 |
+
def _compute_burst_ratio(self, events):
|
| 64 |
+
# Detecta ráfagas de 3+ correcciones (comportamiento humano) [cite: 5, 59]
|
| 65 |
+
streak = burst = total = 0
|
| 66 |
+
for e in events:
|
| 67 |
+
if e.key == 'Backspace':
|
| 68 |
+
streak += 1
|
| 69 |
+
total += 1
|
| 70 |
+
else:
|
| 71 |
+
if streak >= 3: burst += streak
|
| 72 |
+
streak = 0
|
| 73 |
+
return float(burst / max(total, 1))
|
app/core/security.py
ADDED
|
File without changes
|