mirror of
https://github.com/smittix/intercept.git
synced 2026-04-25 07:10:00 -07:00
Add comprehensive BLE tracker detection with signature engine
Implement reliable tracker detection for AirTag, Tile, Samsung SmartTag, and other BLE trackers based on manufacturer data patterns, service UUIDs, and advertising payload analysis. Key changes: - Add TrackerSignatureEngine with signatures for major tracker brands - Device fingerprinting to track devices across MAC randomization - Suspicious presence heuristics (persistence, following patterns) - New API endpoints: /api/bluetooth/trackers, /diagnostics - UI updates with tracker badges, confidence, and evidence display - TSCM integration updated to use v2 tracker detection data - Unit tests and smoke test scripts for validation Detection is heuristic-based with confidence scoring (high/medium/low) and evidence transparency. Backwards compatible with existing APIs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,11 @@ from .models import BTObservation, BTDeviceAggregate
|
||||
from .device_key import generate_device_key, is_randomized_mac
|
||||
from .distance import DistanceEstimator, get_distance_estimator
|
||||
from .ring_buffer import RingBuffer, get_ring_buffer
|
||||
from .tracker_signatures import (
|
||||
TrackerSignatureEngine,
|
||||
get_tracker_engine,
|
||||
TrackerDetectionResult,
|
||||
)
|
||||
|
||||
|
||||
class DeviceAggregator:
|
||||
@@ -60,9 +65,15 @@ class DeviceAggregator:
|
||||
self._distance_estimator = get_distance_estimator()
|
||||
self._ring_buffer = get_ring_buffer()
|
||||
|
||||
# Tracker detection engine
|
||||
self._tracker_engine = get_tracker_engine()
|
||||
|
||||
# Device key mapping (device_id -> device_key)
|
||||
self._device_keys: dict[str, str] = {}
|
||||
|
||||
# Fingerprint mapping for cross-MAC tracking
|
||||
self._fingerprint_to_devices: dict[str, set[str]] = {}
|
||||
|
||||
def ingest(self, observation: BTObservation) -> BTDeviceAggregate:
|
||||
"""
|
||||
Ingest a new observation and update the device aggregate.
|
||||
@@ -166,6 +177,12 @@ class DeviceAggregator:
|
||||
# Estimate distance and proximity band
|
||||
self._update_proximity(device)
|
||||
|
||||
# Run tracker detection
|
||||
self._update_tracker_detection(device, observation)
|
||||
|
||||
# Evaluate suspicious presence heuristics
|
||||
self._update_risk_analysis(device)
|
||||
|
||||
return device
|
||||
|
||||
def _infer_protocol(self, observation: BTObservation) -> str:
|
||||
@@ -291,6 +308,77 @@ class DeviceAggregator:
|
||||
)
|
||||
device.proximity_band = str(band)
|
||||
|
||||
def _update_tracker_detection(
|
||||
self,
|
||||
device: BTDeviceAggregate,
|
||||
observation: BTObservation,
|
||||
) -> None:
|
||||
"""Run tracker signature detection on a device."""
|
||||
# Prepare service data from observation if available
|
||||
service_data = observation.service_data if observation.service_data else {}
|
||||
|
||||
# Store service data on device for investigation
|
||||
for uuid, data in service_data.items():
|
||||
device.service_data[uuid] = data
|
||||
|
||||
# Run tracker detection
|
||||
result = self._tracker_engine.detect_tracker(
|
||||
address=device.address,
|
||||
address_type=device.address_type,
|
||||
name=device.name,
|
||||
manufacturer_id=device.manufacturer_id,
|
||||
manufacturer_data=device.manufacturer_bytes,
|
||||
service_uuids=device.service_uuids,
|
||||
service_data=service_data,
|
||||
tx_power=device.tx_power,
|
||||
)
|
||||
|
||||
# Update device with detection results
|
||||
device.is_tracker = result.is_tracker
|
||||
device.tracker_type = result.tracker_type.value if result.tracker_type else None
|
||||
device.tracker_name = result.tracker_name
|
||||
device.tracker_confidence = result.confidence.value if result.confidence else None
|
||||
device.tracker_confidence_score = result.confidence_score
|
||||
device.tracker_evidence = result.evidence
|
||||
|
||||
# Generate and store payload fingerprint
|
||||
fingerprint = self._tracker_engine.generate_device_fingerprint(
|
||||
manufacturer_id=device.manufacturer_id,
|
||||
manufacturer_data=device.manufacturer_bytes,
|
||||
service_uuids=device.service_uuids,
|
||||
service_data=service_data,
|
||||
tx_power=device.tx_power,
|
||||
name=device.name,
|
||||
)
|
||||
device.payload_fingerprint_id = fingerprint.fingerprint_id
|
||||
device.payload_fingerprint_stability = fingerprint.stability_confidence
|
||||
|
||||
# Track fingerprint to device mapping
|
||||
if fingerprint.fingerprint_id not in self._fingerprint_to_devices:
|
||||
self._fingerprint_to_devices[fingerprint.fingerprint_id] = set()
|
||||
self._fingerprint_to_devices[fingerprint.fingerprint_id].add(device.device_id)
|
||||
|
||||
# Record sighting for persistence tracking
|
||||
self._tracker_engine.record_sighting(fingerprint.fingerprint_id)
|
||||
|
||||
def _update_risk_analysis(self, device: BTDeviceAggregate) -> None:
|
||||
"""Evaluate suspicious presence heuristics for a device."""
|
||||
if not device.payload_fingerprint_id:
|
||||
return
|
||||
|
||||
risk_score, risk_factors = self._tracker_engine.evaluate_suspicious_presence(
|
||||
fingerprint_id=device.payload_fingerprint_id,
|
||||
is_tracker=device.is_tracker,
|
||||
seen_count=device.seen_count,
|
||||
duration_seconds=device.duration_seconds,
|
||||
seen_rate=device.seen_rate,
|
||||
rssi_variance=device.rssi_variance,
|
||||
is_new=device.is_new,
|
||||
)
|
||||
|
||||
device.risk_score = risk_score
|
||||
device.risk_factors = risk_factors
|
||||
|
||||
def _merge_device_info(self, device: BTDeviceAggregate, observation: BTObservation) -> None:
|
||||
"""Merge observation data into device aggregate (prefer non-None values)."""
|
||||
# Name (prefer longer names as they're usually more complete)
|
||||
|
||||
Reference in New Issue
Block a user