adacam-api/adacam_api/routes/wigle.py

148 lines
5.1 KiB
Python

"""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=['POST'])
@require_auth
def 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