mirror of
https://github.com/ruvnet/RuView
synced 2026-08-11 20:41:44 +00:00
6ce50d5158
Browser sign-in was the newest security surface in this PR and had no
executable evidence behind it: browser_session.rs was 534 lines with 13 tests,
every one of which hit a private helper (sign, unsign, cookie, read_cookie,
is_live, has_scope). No test called issue, from_cookie_header, begin,
verifier_for_callback or is_configured, and no test anywhere presented a session
cookie to the gate.
+10 tests in browser_session, +6 in bearer_auth. Three mutants the adversarial
review named, each now verified dead by actually applying the mutation:
(a) delete the `state` comparison in verifier_for_callback
-> a_callback_whose_state_does_not_match_is_refused FAILED
Without it the callback accepts a code from a flow the user never
started: login CSRF, victim silently lands in the attacker's session.
(b) `session.is_live().then_some(session)` -> `Some(session)`
-> an_expired_session_cookie_does_not_authenticate FAILED
-> an_expired_browser_session_is_refused FAILED
`is_live` was already unit-tested; nothing asserted the CALLER consults
it. Same "tested in isolation, call site untested" shape as the earlier
refresh-never-invoked defect.
(c) `session.has_scope(required)` -> `true`
-> a_read_scoped_browser_session_cannot_delete_or_train FAILED
Without it any browser session could delete models and start training.
Mutant (c) initially appeared to SURVIVE. It did not — there are two
has_scope call sites and the first substitution only hit one. Mutating the
one in `session_or_unauthorized` kills the test. That accident confirmed a
separate finding: the cookie branch inside require_bearer is unreachable when
an Authorization header is present, because the OAuth step returns on both
arms. It fails closed, so it is not a hole, but "try the next credential" is
what the code reads like. Pinned by
a_bad_bearer_beats_a_good_cookie_rather_than_falling_back.
Adds two crate-internal test seams (init_secret_for_tests, test_cookie_value).
test_cookie_value signs through the same path as `issue`, so tests presenting a
cookie exercise real verification rather than a test-only bypass.
ADR-271:
- The "browser cannot obtain an OAuth token" section asserted
`grep -ril "oauth|cognitum|pkce" ui/` returns nothing. It now returns three
files, invalidated by commits in this same PR. Marked superseded, original
retained under a fold, replaced with what actually ships.
- Records the two deferred decisions with designs rather than patches: P1 the
blocking JWKS fetch on a tokio worker (whose rate limiter is bypassed on
exactly the stale path that matters, because fetched_at updates only on
success — so after the TTL every request fetches, and a Pi that loses WAN
stalls itself with no attacker present); P2 the 12-hour session from a
15-minute token, with three costed options. Capping the session to
sensing:read was considered and rejected: the dashboard genuinely issues
DELETE /api/v1/models/{id}.
- P3 records that dropping `__Host-` costs origin-integrity, not just Secure —
read_cookie takes the FIRST match and cookies are not port-scoped, so a
same-host writer can shadow a session. Forgery was never the threat that
prefix addresses.
- Documents redirect_uri's hardcoded default and the unconsumed CLI credential
as known-incomplete, per decision to leave both as-is.
ADR-272: corrected a claim that would mislead users into a 401. It stated the
Python client DOES send Authorization: Bearer on the handshake; ws.py passes no
headers at all (zero occurrences of extra_headers or Authorization), so every
published client 401s once auth is enabled. Server-side decision unchanged.
Verified: sensing-server 566 + 179 + 7 + 5 + 8 + 4 + 16 pass under CI flags,
ruview-auth 61 + 25 + 2 with --all-features, auth_wiring 7.
Co-Authored-By: Ruflo & AQE
wifi-densepose-sensing-server
Lightweight Axum server for real-time WiFi sensing with RuVector signal processing.
Overview
wifi-densepose-sensing-server is the operational backend for WiFi-DensePose. It receives raw CSI
frames from ESP32 hardware over UDP, runs them through the RuVector-powered signal processing
pipeline, and broadcasts processed sensing updates to browser clients via WebSocket. A built-in
static file server hosts the sensing UI on the same port.
The crate ships both a library (wifi_densepose_sensing_server) exposing the training and inference
modules, and a binary (sensing-server) that starts the full server stack.
Integrates wifi-densepose-wifiscan for multi-BSSID WiFi scanning per ADR-022 Phase 3.
Features
- UDP CSI ingestion -- Receives ESP32 CSI frames on port 5005 and parses them into the internal
CsiFramerepresentation. - Vital sign detection -- Pure-Rust FFT-based breathing rate (0.1--0.5 Hz) and heart rate (0.67--2.0 Hz) estimation from CSI amplitude time series (ADR-021).
- RVF container -- Standalone binary container format for packaging model weights, metadata, and
configuration into a single
.rvffile with 64-byte aligned segments. - RVF pipeline -- Progressive model loading with streaming segment decoding.
- Graph Transformer -- Cross-attention bottleneck between antenna-space CSI features and the
COCO 17-keypoint body graph, followed by GCN message passing (ADR-023 Phase 2). Pure
std, no ML dependencies. - SONA adaptation -- LoRA + EWC++ online adaptation for environment drift without catastrophic forgetting (ADR-023 Phase 5).
- Contrastive CSI embeddings -- Self-supervised SimCLR-style pretraining with InfoNCE loss, projection head, fingerprint indexing, and cross-modal pose alignment (ADR-024).
- Sparse inference -- Activation profiling, sparse matrix-vector multiply, INT8/FP16 quantization, and a full sparse inference engine for edge deployment (ADR-023 Phase 6).
- Dataset pipeline -- Training dataset loading and batching.
- Multi-BSSID scanning -- Windows
netshintegration for BSSID discovery viawifi-densepose-wifiscan(ADR-022). - WebSocket broadcast -- Real-time sensing updates pushed to all connected clients at
ws://localhost:8765/ws/sensing. - Static file serving -- Hosts the sensing UI on port 8080 with CORS headers.
Modules
| Module | Description |
|---|---|
vital_signs |
Breathing and heart rate extraction via FFT spectral analysis |
rvf_container |
RVF binary format builder and reader |
rvf_pipeline |
Progressive model loading from RVF containers |
graph_transformer |
Graph Transformer + GCN for CSI-to-pose estimation |
trainer |
Training loop orchestration |
dataset |
Training data loading and batching |
sona |
LoRA adapters and EWC++ continual learning |
sparse_inference |
Neuron profiling, sparse matmul, INT8/FP16 quantization |
embedding |
Contrastive CSI embedding model and fingerprint index |
Quick Start
# Build the server
cargo build -p wifi-densepose-sensing-server
# Run with default settings (HTTP :8080, UDP :5005, WS :8765)
cargo run -p wifi-densepose-sensing-server
# Run with custom ports
cargo run -p wifi-densepose-sensing-server -- \
--http-port 9000 \
--udp-port 5005 \
--static-dir ./ui
Using as a library
use wifi_densepose_sensing_server::vital_signs::VitalSignDetector;
// Create a detector with 20 Hz sample rate
let mut detector = VitalSignDetector::new(20.0);
// Feed CSI amplitude samples
for amplitude in csi_amplitudes.iter() {
detector.push_sample(*amplitude);
}
// Extract vital signs
if let Some(vitals) = detector.detect() {
println!("Breathing: {:.1} BPM", vitals.breathing_rate_bpm);
println!("Heart rate: {:.0} BPM", vitals.heart_rate_bpm);
}
Architecture
ESP32 ──UDP:5005──> [ CSI Receiver ]
|
[ Signal Pipeline ]
(vital_signs, graph_transformer, sona)
|
[ WebSocket Broadcast ]
|
Browser <──WS:8765── [ Axum Server :8080 ] ──> Static UI files
Related Crates
| Crate | Role |
|---|---|
wifi-densepose-wifiscan |
Multi-BSSID WiFi scanning (ADR-022) |
wifi-densepose-core |
Shared types and traits |
wifi-densepose-signal |
CSI signal processing algorithms |
wifi-densepose-hardware |
ESP32 hardware interfaces |
wifi-densepose-wasm |
Browser WASM bindings for the sensing UI |
wifi-densepose-train |
Full training pipeline with ruvector |
wifi-densepose-mat |
Disaster detection module |
License
MIT OR Apache-2.0