48fcb00241
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>
282 lines
12 KiB
HTML
282 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>GigLez - IoT RF Device Mapping Platform</title>
|
|
|
|
<!-- Leaflet CSS -->
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css" />
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css" />
|
|
|
|
<!-- Custom CSS -->
|
|
<link rel="stylesheet" href="/static/css/main.css">
|
|
</head>
|
|
<body>
|
|
<!-- Header -->
|
|
<header>
|
|
<div class="container">
|
|
<div class="logo">
|
|
<h1>🛰️ GigLez</h1>
|
|
<p>IoT RF Device Mapping Platform</p>
|
|
</div>
|
|
<nav>
|
|
<a href="#map" class="nav-link active">Map</a>
|
|
<a href="#upload" class="nav-link">Upload</a>
|
|
<a href="#search" class="nav-link">Search</a>
|
|
<a href="#stats" class="nav-link">Statistics</a>
|
|
<a href="/docs" class="nav-link" target="_blank">API Docs</a>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Main Content -->
|
|
<main>
|
|
<!-- Map View -->
|
|
<section id="map-section" class="section active">
|
|
<div class="map-controls">
|
|
<div class="control-group">
|
|
<label>
|
|
<input type="checkbox" id="cluster-toggle" checked>
|
|
Cluster Markers
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" id="heatmap-toggle">
|
|
Heatmap View
|
|
</label>
|
|
</div>
|
|
<div class="control-group">
|
|
<label>Filter by Frequency:</label>
|
|
<select id="frequency-filter">
|
|
<option value="">All Frequencies</option>
|
|
<option value="315">315 MHz</option>
|
|
<option value="433">433 MHz</option>
|
|
<option value="868">868 MHz</option>
|
|
<option value="915">915 MHz</option>
|
|
</select>
|
|
</div>
|
|
<div class="stats-summary">
|
|
<span>Total Captures: <strong id="total-captures">0</strong></span>
|
|
<span>Unique Devices: <strong id="unique-devices">0</strong></span>
|
|
</div>
|
|
</div>
|
|
<div id="map"></div>
|
|
</section>
|
|
|
|
<!-- Upload View -->
|
|
<section id="upload-section" class="section">
|
|
<div class="container">
|
|
<h2>Upload RF Captures</h2>
|
|
<p class="subtitle">Upload .sub files with GPS coordinates from your wardriving session</p>
|
|
|
|
<!-- Upload Form -->
|
|
<div class="upload-container">
|
|
<!-- Drop Zone -->
|
|
<div id="drop-zone" class="drop-zone">
|
|
<div class="drop-zone-content">
|
|
<svg class="upload-icon" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
<polyline points="17 8 12 3 7 8"></polyline>
|
|
<line x1="12" y1="3" x2="12" y2="15"></line>
|
|
</svg>
|
|
<h3>Drop .sub files here</h3>
|
|
<p>or click to browse</p>
|
|
<button type="button" class="btn btn-primary" onclick="document.getElementById('file-input').click()">
|
|
Select Files
|
|
</button>
|
|
<input type="file" id="file-input" multiple accept=".sub" style="display: none;">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- GPS Manifest Form -->
|
|
<div class="manifest-form">
|
|
<h3>GPS Coordinates</h3>
|
|
<p>Provide GPS data for your captures</p>
|
|
|
|
<div class="form-group">
|
|
<label>Session UUID (optional)</label>
|
|
<input type="text" id="session-uuid" placeholder="Auto-generated if not provided">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Default GPS Coordinates</label>
|
|
<div class="gps-inputs">
|
|
<input type="number" id="default-lat" placeholder="Latitude" step="0.000001" min="-90" max="90">
|
|
<input type="number" id="default-lon" placeholder="Longitude" step="0.000001" min="-180" max="180">
|
|
</div>
|
|
<small>Applied to all files. Individual coordinates can be set below.</small>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>GPS Accuracy (meters)</label>
|
|
<input type="number" id="default-accuracy" placeholder="5.0" step="0.1" min="0" value="5.0">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Altitude (meters)</label>
|
|
<input type="number" id="default-altitude" placeholder="Optional" step="0.1">
|
|
</div>
|
|
|
|
<button type="button" class="btn btn-secondary" onclick="useCurrentLocation()">
|
|
Use Current Location
|
|
</button>
|
|
</div>
|
|
|
|
<!-- File List -->
|
|
<div id="file-list" class="file-list" style="display: none;">
|
|
<h3>Files to Upload</h3>
|
|
<div id="files-container"></div>
|
|
<div class="upload-actions">
|
|
<button type="button" class="btn btn-primary btn-large" onclick="uploadFiles()">
|
|
Upload All Files
|
|
</button>
|
|
<button type="button" class="btn btn-secondary" onclick="clearFiles()">
|
|
Clear All
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Upload Progress -->
|
|
<div id="upload-progress" class="upload-progress" style="display: none;">
|
|
<h3>Uploading...</h3>
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" id="progress-fill"></div>
|
|
</div>
|
|
<p id="progress-text">Preparing upload...</p>
|
|
</div>
|
|
|
|
<!-- Upload Results -->
|
|
<div id="upload-results" class="upload-results" style="display: none;">
|
|
<h3>Upload Complete</h3>
|
|
<div id="results-container"></div>
|
|
<button type="button" class="btn btn-primary" onclick="resetUpload()">
|
|
Upload More Files
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Search View -->
|
|
<section id="search-section" class="section">
|
|
<div class="container">
|
|
<h2>Search Captures</h2>
|
|
<div class="search-form">
|
|
<div class="form-group">
|
|
<label>Search Query</label>
|
|
<input type="text" id="search-query" placeholder="Device name, protocol, or frequency">
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label>Frequency (MHz)</label>
|
|
<select id="search-frequency">
|
|
<option value="">All</option>
|
|
<option value="315">315</option>
|
|
<option value="433">433</option>
|
|
<option value="868">868</option>
|
|
<option value="915">915</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Protocol</label>
|
|
<select id="search-protocol">
|
|
<option value="">All</option>
|
|
<option value="RAW">RAW</option>
|
|
<option value="Princeton">Princeton</option>
|
|
<option value="KeeLoq">KeeLoq</option>
|
|
<option value="MegaCode">MegaCode</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Date Range</label>
|
|
<input type="date" id="search-date-start">
|
|
<input type="date" id="search-date-end">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Geographic Search</label>
|
|
<div class="gps-inputs">
|
|
<input type="number" id="search-lat" placeholder="Latitude" step="0.000001">
|
|
<input type="number" id="search-lon" placeholder="Longitude" step="0.000001">
|
|
<input type="number" id="search-radius" placeholder="Radius (km)" step="0.1" min="0.1">
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" class="btn btn-primary" onclick="searchCaptures()">
|
|
Search
|
|
</button>
|
|
</div>
|
|
|
|
<div id="search-results" class="search-results" style="display: none;">
|
|
<h3>Search Results</h3>
|
|
<div id="results-list"></div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Statistics View -->
|
|
<section id="stats-section" class="section">
|
|
<div class="container">
|
|
<h2>Platform Statistics</h2>
|
|
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<h3>Total Captures</h3>
|
|
<p class="stat-value" id="stat-captures">-</p>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Unique Devices</h3>
|
|
<p class="stat-value" id="stat-devices">-</p>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Coverage Area</h3>
|
|
<p class="stat-value" id="stat-coverage">-</p>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Contributors</h3>
|
|
<p class="stat-value" id="stat-contributors">-</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="chart-container">
|
|
<h3>Frequency Distribution</h3>
|
|
<canvas id="frequency-chart"></canvas>
|
|
</div>
|
|
|
|
<div class="chart-container">
|
|
<h3>Captures Over Time</h3>
|
|
<canvas id="timeline-chart"></canvas>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<!-- Footer -->
|
|
<footer>
|
|
<div class="container">
|
|
<p>© 2026 GigLez - IoT RF Device Mapping Platform</p>
|
|
<p>Wigle for Sub-GHz Signals</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- Leaflet JS -->
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
<script src="https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js"></script>
|
|
|
|
<!-- Chart.js -->
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
|
|
|
<!-- Custom JS -->
|
|
<script src="/static/js/map.js"></script>
|
|
<script src="/static/js/upload.js"></script>
|
|
<script src="/static/js/search.js"></script>
|
|
<script src="/static/js/stats.js"></script>
|
|
<script src="/static/js/main.js"></script>
|
|
</body>
|
|
</html>
|