feat: bearer token auth, pairing, wifi config, ssh toggle, remove /cmd
This commit is contained in:
parent
37aefb84c8
commit
eaf49841f0
3 changed files with 126 additions and 3 deletions
|
|
@ -1,6 +1,8 @@
|
|||
"""Flask app factory."""
|
||||
from flask import Flask
|
||||
import subprocess
|
||||
from flask import Flask, request, jsonify
|
||||
from . import config, db, forwarder
|
||||
from .auth import get_device_serial, get_api_token, require_auth
|
||||
from .routes import landmarks, gnss, status, frames
|
||||
|
||||
|
||||
|
|
@ -18,6 +20,95 @@ def create_app():
|
|||
app.register_blueprint(status.bp)
|
||||
app.register_blueprint(frames.bp)
|
||||
|
||||
# ── PAIRING ENDPOINT ─────────────────────────────────────────────────────
|
||||
@app.route('/pair')
|
||||
@app.route('/api/1/pair')
|
||||
def pair():
|
||||
"""Pairing info for Varroa app."""
|
||||
serial = get_device_serial()
|
||||
return jsonify({
|
||||
'serial': serial,
|
||||
'version': '1.0',
|
||||
'ap_ip': '10.77.0.1',
|
||||
'api_port': 5000
|
||||
})
|
||||
|
||||
# ── DEVICE INFO ──────────────────────────────────────────────────────────
|
||||
@app.route('/api/1/info')
|
||||
def device_info():
|
||||
"""Device identity (unauthenticated)."""
|
||||
serial = get_device_serial()
|
||||
return jsonify({
|
||||
'device_id': serial,
|
||||
'version': '1.0',
|
||||
'firmware': 'adacam',
|
||||
'ap_ip': '10.77.0.1'
|
||||
})
|
||||
|
||||
# ── WIFI STATUS/CONNECT ──────────────────────────────────────────────────
|
||||
@app.route('/api/1/wifi/status')
|
||||
def wifi_status():
|
||||
"""Get WiFi client interface status (unauthenticated)."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['wpa_cli', '-i', 'wlp1s0f1', 'status'],
|
||||
capture_output=True, text=True, timeout=5
|
||||
)
|
||||
lines = dict(
|
||||
l.split('=', 1) for l in result.stdout.strip().split('\n') if '=' in l
|
||||
)
|
||||
return jsonify({
|
||||
'ssid': lines.get('ssid', ''),
|
||||
'ip': lines.get('ip_address', ''),
|
||||
'state': lines.get('wpa_state', 'DISCONNECTED'),
|
||||
'connected': lines.get('wpa_state') == 'COMPLETED'
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e), 'connected': False})
|
||||
|
||||
@app.route('/api/1/wifi/connect', methods=['POST'])
|
||||
@require_auth
|
||||
def wifi_connect():
|
||||
"""Connect to a WiFi network (authenticated)."""
|
||||
data = request.get_json()
|
||||
ssid = data.get('ssid', '').strip()
|
||||
password = data.get('password', '').strip()
|
||||
if not ssid or not password:
|
||||
return jsonify({'error': 'ssid and password required'}), 400
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['/usr/local/bin/adacam-wifi-connect', ssid, password],
|
||||
capture_output=True, text=True, timeout=15
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return jsonify({'ok': True, 'message': f'Connecting to {ssid}'})
|
||||
else:
|
||||
return jsonify({'error': result.stderr or 'Failed'}), 500
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
# ── SSH CONTROL ──────────────────────────────────────────────────────────
|
||||
@app.route('/api/1/ssh/status')
|
||||
def ssh_status():
|
||||
"""Get SSH daemon status (unauthenticated)."""
|
||||
result = subprocess.run(
|
||||
['systemctl', 'is-active', 'sshd'],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
return jsonify({'active': result.stdout.strip() == 'active'})
|
||||
|
||||
@app.route('/api/1/ssh/toggle', methods=['POST'])
|
||||
@require_auth
|
||||
def ssh_toggle():
|
||||
"""Enable/disable SSH (authenticated)."""
|
||||
data = request.get_json()
|
||||
enable = data.get('enable', True)
|
||||
subprocess.run(
|
||||
['systemctl', 'start' if enable else 'stop', 'sshd'],
|
||||
timeout=5
|
||||
)
|
||||
return jsonify({'ok': True, 'ssh_enabled': enable})
|
||||
|
||||
# Start background forwarder thread
|
||||
forwarder.start_retry_thread()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue