Phase 3 Complete: Web Interface MVP
Major Achievements: - ✅ Full web interface (1,520+ lines of frontend code) - ✅ Interactive Leaflet.js map with marker clustering - ✅ Drag-and-drop upload system with GPS input - ✅ Search & filter UI with multi-criteria - ✅ Statistics dashboard with Chart.js - ✅ Responsive mobile-friendly design Backend: - ✅ FastAPI static file serving - ✅ Simplified server mode (main_simple.py) - ✅ Improved startup script with port auto-selection - ✅ PostgreSQL schema ready (requires setup) Database: - ✅ SQLite populated with 85 Flipper Zero signatures - ✅ Device matching system operational - ✅ Frequency-based search working Documentation: - ✅ PHASE_3_COMPLETE.md - Technical summary - ✅ WEB_INTERFACE_README.md - User guide - ✅ WEBAPP_STARTUP_GUIDE.md - Troubleshooting - ✅ POSTGRESQL_SETUP_EXPLANATION.md - DB setup guide - ✅ DATABASE_POPULATION_SUCCESS.md - Import report - ✅ DEVICE_IDENTIFICATION_REPORT.md - Matching analysis Files Created: - templates/index.html (260 lines) - static/css/main.css (500 lines) - static/js/*.js (760 lines total) - src/api/main_simple.py (simplified server) - start_web.sh (auto port selection) Status: Production MVP Ready Next: Phase 4 - API & Integration 🛰️ Generated with Claude Code https://claude.com/claude-code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Executable
+156
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Analyze Flipper Zero signature database
|
||||
|
||||
Parses all Flipper Zero .sub files and creates a comprehensive device signature database
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List
|
||||
|
||||
# Add project root to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from src.parser.sub_parser import SubFileParser
|
||||
|
||||
|
||||
def analyze_flipper_database(flipper_dir: Path):
|
||||
"""Analyze all Flipper Zero .sub files"""
|
||||
|
||||
print("="*80)
|
||||
print("FLIPPER ZERO SIGNATURE DATABASE ANALYSIS")
|
||||
print("="*80)
|
||||
print()
|
||||
|
||||
parser = SubFileParser()
|
||||
|
||||
# Find all .sub files
|
||||
sub_files = list(flipper_dir.glob('**/*.sub'))
|
||||
print(f"Found {len(sub_files)} Flipper Zero .sub files\n")
|
||||
|
||||
# Parse all files
|
||||
signatures = []
|
||||
parse_errors = []
|
||||
|
||||
for sub_file in sub_files:
|
||||
try:
|
||||
metadata = parser.parse(str(sub_file))
|
||||
|
||||
# Extract device name from path
|
||||
device_name = sub_file.stem
|
||||
|
||||
signatures.append({
|
||||
'filename': sub_file.name,
|
||||
'device_name': device_name,
|
||||
'path': str(sub_file.relative_to(flipper_dir)),
|
||||
'frequency': metadata.frequency,
|
||||
'protocol': metadata.protocol,
|
||||
'file_format': metadata.file_format,
|
||||
'modulation': metadata.modulation,
|
||||
'bit_length': metadata.bit_length,
|
||||
'has_raw_data': bool(metadata.raw_data),
|
||||
'raw_samples': len(metadata.raw_data) if metadata.raw_data else 0
|
||||
})
|
||||
except Exception as e:
|
||||
parse_errors.append((sub_file.name, str(e)))
|
||||
|
||||
print(f"Successfully parsed: {len(signatures)} files")
|
||||
print(f"Parse errors: {len(parse_errors)} files\n")
|
||||
|
||||
# Analyze by frequency
|
||||
print("-"*80)
|
||||
print("FREQUENCY DISTRIBUTION")
|
||||
print("-"*80)
|
||||
|
||||
freq_groups = defaultdict(list)
|
||||
for sig in signatures:
|
||||
freq_mhz = sig['frequency'] / 1e6 if sig['frequency'] else 0
|
||||
freq_groups[freq_mhz].append(sig)
|
||||
|
||||
for freq in sorted(freq_groups.keys()):
|
||||
if freq > 0:
|
||||
count = len(freq_groups[freq])
|
||||
print(f"{freq:8.2f} MHz: {count:3d} devices")
|
||||
|
||||
# Analyze by protocol
|
||||
print(f"\n{'-'*80}")
|
||||
print("PROTOCOL DISTRIBUTION")
|
||||
print("-"*80)
|
||||
|
||||
protocol_groups = defaultdict(list)
|
||||
for sig in signatures:
|
||||
proto = sig['protocol'] or 'RAW'
|
||||
protocol_groups[proto].append(sig)
|
||||
|
||||
for proto in sorted(protocol_groups.keys(), key=lambda x: len(protocol_groups[x]), reverse=True)[:15]:
|
||||
count = len(protocol_groups[proto])
|
||||
print(f"{proto:30s}: {count:3d} devices")
|
||||
|
||||
# Analyze by format
|
||||
print(f"\n{'-'*80}")
|
||||
print("FILE FORMAT DISTRIBUTION")
|
||||
print("-"*80)
|
||||
|
||||
format_groups = defaultdict(list)
|
||||
for sig in signatures:
|
||||
format_groups[sig['file_format']].append(sig)
|
||||
|
||||
for fmt in sorted(format_groups.keys()):
|
||||
count = len(format_groups[fmt])
|
||||
print(f"{fmt:10s}: {count:3d} files")
|
||||
|
||||
# Show sample devices by frequency band
|
||||
print(f"\n{'-'*80}")
|
||||
print("SAMPLE DEVICES BY FREQUENCY BAND")
|
||||
print("-"*80)
|
||||
|
||||
# Group into common RF bands
|
||||
bands = {
|
||||
'300-350 MHz (Garage/Gate)': (300, 350),
|
||||
'400-450 MHz (Key Fobs/Remotes)': (400, 450),
|
||||
'800-900 MHz (Sensors/Utility)': (800, 900),
|
||||
'900-930 MHz (ISM Band - US)': (900, 930)
|
||||
}
|
||||
|
||||
for band_name, (min_freq, max_freq) in bands.items():
|
||||
matching = [s for s in signatures
|
||||
if min_freq <= (s['frequency']/1e6) <= max_freq]
|
||||
|
||||
print(f"\n{band_name}: {len(matching)} devices")
|
||||
|
||||
# Show first 10
|
||||
for sig in matching[:10]:
|
||||
print(f" - {sig['device_name']:40s} {sig['frequency']/1e6:7.2f} MHz {sig['protocol'] or 'RAW'}")
|
||||
|
||||
return signatures, parse_errors
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
|
||||
flipper_dir = Path(__file__).parent.parent / 'signatures' / 'flipperzero-firmware'
|
||||
|
||||
if not flipper_dir.exists():
|
||||
print(f"❌ Flipper Zero directory not found: {flipper_dir}")
|
||||
print("Run: git clone https://github.com/flipperdevices/flipperzero-firmware.git")
|
||||
return 1
|
||||
|
||||
signatures, errors = analyze_flipper_database(flipper_dir)
|
||||
|
||||
# Summary
|
||||
print(f"\n{'='*80}")
|
||||
print("SUMMARY")
|
||||
print(f"{'='*80}")
|
||||
print(f"Total signatures: {len(signatures)}")
|
||||
print(f"Parse errors: {len(errors)}")
|
||||
print(f"\nThese signatures can now be imported into GigLez database")
|
||||
print(f"for device matching against wardriving captures.")
|
||||
print("="*80)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user