"""WiGLE wardriving status and config endpoints.""" import os import sqlite3 import subprocess import time from flask import Blueprint, jsonify, request from ..auth import require_auth bp = Blueprint('wigle', __name__, url_prefix='/api/1/wigle') WIGLE_DB = '/data/adacam/wigle.db' def _get_db(): """Get SQLite connection to wigle.db, create tables if needed.""" os.makedirs(os.path.dirname(WIGLE_DB), exist_ok=True) conn = sqlite3.connect(WIGLE_DB) conn.execute('''CREATE TABLE IF NOT EXISTS wigle_records ( id INTEGER PRIMARY KEY AUTOINCREMENT, bssid TEXT NOT NULL, ssid TEXT, auth_mode TEXT, first_seen TEXT, channel INTEGER, rssi INTEGER, lat REAL, lon REAL, alt REAL, accuracy REAL, uploaded INTEGER DEFAULT 0, created_at INTEGER)''') conn.execute('''CREATE TABLE IF NOT EXISTS wigle_config (key TEXT PRIMARY KEY, value TEXT)''') return conn def _get_config(conn): cur = conn.execute('SELECT key, value FROM wigle_config') return dict(cur.fetchall()) def _mask_api_name(api_name: str) -> str: """Mask API name showing only first 4 chars.""" if not api_name or len(api_name) < 4: return '●●●●●●●●' if api_name else '' return api_name[:4] + '●●●●●●●●' @bp.route('/status') def wigle_status(): """Get WiGLE service status (unauthenticated).""" try: conn = _get_db() cfg = _get_config(conn) total = conn.execute('SELECT COUNT(*) FROM wigle_records').fetchone()[0] pending = conn.execute('SELECT COUNT(*) FROM wigle_records WHERE uploaded=0').fetchone()[0] last_scan = cfg.get('last_scan') last_upload = cfg.get('last_upload') conn.close() return jsonify({ 'enabled': cfg.get('enabled', '0') == '1', 'api_name': _mask_api_name(cfg.get('api_name', '')), 'total_networks': total, 'pending_upload': pending, 'last_scan': int(last_scan) if last_scan else None, 'last_upload': int(last_upload) if last_upload else None }) except Exception as e: return jsonify({'error': str(e), 'enabled': False, 'total_networks': 0, 'pending_upload': 0}) @bp.route('/stats') def wigle_stats(): """Get WiGLE statistics (unauthenticated).""" try: conn = _get_db() total = conn.execute('SELECT COUNT(*) FROM wigle_records').fetchone()[0] uploaded = conn.execute('SELECT COUNT(*) FROM wigle_records WHERE uploaded=1').fetchone()[0] pending = conn.execute('SELECT COUNT(*) FROM wigle_records WHERE uploaded=0').fetchone()[0] # Scans today (records created in last 24h) day_ago = int(time.time()) - 86400 scans_today = conn.execute( 'SELECT COUNT(DISTINCT first_seen) FROM wigle_records WHERE created_at > ?', (day_ago,) ).fetchone()[0] conn.close() return jsonify({ 'total_networks': total, 'uploaded_networks': uploaded, 'pending_upload': pending, 'scans_today': scans_today }) except Exception as e: return jsonify({'error': str(e), 'total_networks': 0, 'uploaded_networks': 0, 'pending_upload': 0, 'scans_today': 0}) @bp.route('/config', methods=['GET']) def get_wigle_config(): """Get WiGLE configuration (unauthenticated, tokens masked).""" try: conn = _get_db() cfg = _get_config(conn) conn.close() return jsonify({ 'enabled': cfg.get('enabled', '0') == '1', 'api_name': cfg.get('api_name', ''), 'api_token_set': bool(cfg.get('api_token')), 'scan_interval_seconds': int(cfg.get('scan_interval_seconds', '30')), 'upload_interval_seconds': int(cfg.get('upload_interval_seconds', '300')), }) except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/config', methods=['POST']) @require_auth def set_wigle_config(): """Set WiGLE configuration (authenticated).""" data = request.get_json() or {} try: conn = _get_db() # Update enabled status if 'enabled' in data: conn.execute( 'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)', ('enabled', '1' if data['enabled'] else '0') ) # Update API credentials if 'api_name' in data: conn.execute( 'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)', ('api_name', data['api_name']) ) if 'api_token' in data: conn.execute( 'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)', ('api_token', data['api_token']) ) # Optional: scan/upload intervals if 'scan_interval_seconds' in data: conn.execute( 'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)', ('scan_interval_seconds', str(data['scan_interval_seconds'])) ) if 'upload_interval_seconds' in data: conn.execute( 'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)', ('upload_interval_seconds', str(data['upload_interval_seconds'])) ) conn.commit() conn.close() # Restart the wigle service to pick up config changes try: subprocess.run(['systemctl', 'restart', 'adacam-wigle'], timeout=10) except Exception: pass # Service may not exist yet return jsonify({'ok': True, 'message': 'WiGLE configuration updated'}) except Exception as e: return jsonify({'error': str(e)}), 500