Attack logs endpoint - Log and retrieve attack action outputs GET: Retrieve attack logs (optionally filtered by IP, action type, or timeframe) POST: Log a new attack output
()
| 7189 | # Add explicit captive portal route |
| 7190 | @app.route('/portal') |
| 7191 | def captive_portal(): |
| 7192 | """Explicit captive portal route""" |
| 7193 | return send_from_directory('web', 'captive_portal.html') |
| 7194 | |
| 7195 | # WiFi configuration page route |
| 7196 | @app.route('/wifi-config') |
| 7197 | def wifi_config_page(): |
| 7198 | """Serve the Wi-Fi configuration page for AP clients and regular users""" |
| 7199 | return send_from_directory('web', 'wifi_config.html') |
| 7200 | |
| 7201 | # Alternative routes for WiFi config (for compatibility) |
| 7202 | @app.route('/wifi') |
| 7203 | @app.route('/setup') |
| 7204 | def wifi_config_alt(): |
| 7205 | """Alternative routes for Wi-Fi configuration""" |
| 7206 | return send_from_directory('web', 'wifi_config.html') |
| 7207 | |
| 7208 | |
| 7209 | # Captive portal detection routes for mobile devices |
| 7210 | @app.route('/generate_204') |
| 7211 | @app.route('/gen_204') |
| 7212 | @app.route('/connecttest.txt') |
| 7213 | @app.route('/success.txt') |
| 7214 | @app.route('/ncsi.txt') |
| 7215 | def captive_portal_detection(): |
| 7216 | """Handle captive portal detection requests from mobile devices""" |
| 7217 | if is_ap_client_request(): |
| 7218 | # Redirect to captive portal for AP clients |
| 7219 | return '''<html><head><meta http-equiv="refresh" content="0; url=/portal"></head><body><a href="/portal">Click here for WiFi setup</a></body></html>''', 302 |
| 7220 | else: |
| 7221 | # Return success for non-AP clients |
| 7222 | return "Success", 204 |
| 7223 | |
| 7224 | |
| 7225 | @app.route('/<path:filename>') |
| 7226 | def serve_static(filename): |
| 7227 | """Serve static files from web directory""" |
| 7228 | resp = make_response(send_from_directory('web', filename)) |
| 7229 | # Keep the manifest and top-level HTML fresh so rebrands (title/PWA name) |
| 7230 | # aren't pinned by a stale browser or installed-PWA cache. |
| 7231 | if filename == 'manifest.json' or filename.endswith('.html'): |
| 7232 | return _no_store(resp) |
| 7233 | return resp |
| 7234 | |
| 7235 | |
| 7236 | @app.route('/api/system/headless') |
| 7237 | def get_system_headless(): |
| 7238 | """Expose headless mode flag for UI to hide display-only features.""" |
| 7239 | try: |
| 7240 | is_headless = safe_bool(getattr(shared_data, 'headless_mode', False)) |
| 7241 | return jsonify({'success': True, 'headless': is_headless, 'is_headless': is_headless}) |
| 7242 | except Exception as exc: |
| 7243 | logger.error(f"Failed to read headless state: {exc}") |
| 7244 | return jsonify({'success': False, 'headless': False, 'error': str(exc)}), 500 |
| 7245 | |
| 7246 | |
| 7247 | # ============================================================================ |
| 7248 | # API ENDPOINTS |
nothing calls this directly
no test coverage detected