mirror of
https://github.com/ruvnet/RuView
synced 2026-07-22 17:23:19 +00:00
499cec7914
RuView's `/api/v1/*` is gated today by `RUVIEW_API_TOKEN`: one shared secret, no expiry, no per-user attribution. This adds the verifier half of replacing that with Cognitum identity — RuView as an OAuth **resource server**, so a user signs in to their own sensing server with their Cognitum account. Note the direction: RuView does not call Cognitum. It never obtains a token for its own use; it verifies tokens users present. Every other Cognitum OAuth integration in the org (meta-proxy, musica, metaharness, the dashboard CLI) is the client side of a plane RuView doesn't have. The one existing resource-server verifier is `meta-llm/src/auth/oauthBearer.ts`, and this crate is a port of its accept-rule — divergence would be a bug, not a preference: a token meta-llm rejects must not be one RuView accepts. Verification is OFFLINE, and that is a requirement rather than an optimisation. RuView runs on Pi-class hardware that loses WAN, and identity publishes no introspection endpoint even when the network is up. So: ES256 over identity's published JWKS, cached by `kid`. What it accepts, mirroring oauthBearer.ts: typ == "access" AND NOT setup AND NOT workload AND account_id non-empty AND exp in the future AND iss matches verbatim AND the required scope is held. Long-lived setup (365-day) and workload credentials are refused outright for identity's own stated reason: their revocation lives in `oauth_setup_tokens`, and RuView — like meta-llm — has no database to check it. A 15-minute access token needs no revocation round-trip because it expires faster than revocation propagates; a 365-day one does. Scope is the capability boundary, and it has to be. Cognitum access tokens carry no `aud`, and `client_id` cannot substitute because clients borrow each other's registrations (musica ships DEFAULT_CLIENT_ID = "meta-proxy"). `sensing:read` covers streams and inference; `sensing:admin` covers training, model delete and recording delete. No hierarchy — admin does not imply read; consent means what it said. Registered in identity migration 0016 (cognitum-one/dashboard#116). Design notes: - `ureq`, not `reqwest`: the sensing server deliberately chose ureq as "the smallest" HTTP client, and pulling reqwest in here would reverse that for the whole graph. Transport sits behind a `JwksFetcher` trait, so a host can supply its own and take no HTTP dependency at all (feature `ureq-transport`, default). - A JWKS refetch failure is survivable while a key set is already cached: a key that verified a minute ago has not stopped being valid because the network blipped, and failing closed there logs every user out of their own sensing server whenever their internet wobbles. We fail closed in exactly one case — no key set has ever been fetched. - Unknown `kid` forces one refetch so rotation is picked up without waiting out the TTL, rate-limited so junk-kid tokens can't become a request amplifier aimed at identity. - Expiry is reported distinctly from a bad signature: on an RTC-less Pi that is usually a clock-sync fault, and an operator must be able to tell them apart. - Test keypairs are generated at runtime, never committed. This repo tracks zero `.pem` files and committed key material shouldn't start here — it also means no fixture can drift out of sync with the JWKS it's served by. Tests: 41 green (19 unit + 21 matrix + 1 doctest) under BOTH `cargo test --no-default-features` (the repo's canonical gate) and default features. The matrix signs real ES256 tokens rather than asserting on strings, and covers alg:none, forged signature, spliced payload, unknown kid, expired, leeway boundaries both sides, wrong issuer, issuer differing only by a trailing slash, missing/!=access typ, setup and workload smuggled onto typ=access, missing and empty account_id, and scope escalation. The highest-value case is `g2_a_genuinely_valid_token_from_another_cognitum_ product_cannot_reach_the_sensing_surface`: a correctly signed, unexpired, right-issuer, right-typ token with client_id=meta-proxy and scope=inference is rejected. Nothing about its signature or identity claims distinguishes it — only scope does. A naive verifier accepts it, and an `inference` token becomes a key to someone's home sensor. No wiring into the sensing server yet; this crate is verification only, with no login flow and no outbound Cognitum calls. Co-Authored-By: Ruflo & AQE
WiFi-DensePose Rust Crates
See through walls with WiFi. No cameras. No wearables. Just radio waves.
A modular Rust workspace for WiFi-based human pose estimation, vital sign monitoring, and disaster response using Channel State Information (CSI). Built on RuVector graph algorithms and the WiFi-DensePose research platform by rUv.
Performance
| Operation | Python v1 | Rust v2 | Speedup |
|---|---|---|---|
| CSI Preprocessing | ~5 ms | 5.19 us | ~1000x |
| Phase Sanitization | ~3 ms | 3.84 us | ~780x |
| Feature Extraction | ~8 ms | 9.03 us | ~890x |
| Motion Detection | ~1 ms | 186 ns | ~5400x |
| Full Pipeline | ~15 ms | 18.47 us | ~810x |
| Vital Signs | N/A | 86 us (11,665 fps) | -- |
Crate Overview
Core Foundation
| Crate | Description | crates.io |
|---|---|---|
wifi-densepose-core |
Types, traits, and utilities (CsiFrame, PoseEstimate, SignalProcessor) |
|
wifi-densepose-config |
Configuration management (env, TOML, YAML) | |
wifi-densepose-db |
Database persistence (PostgreSQL, SQLite, Redis) |
Signal Processing & Sensing
| Crate | Description | RuVector Integration | crates.io |
|---|---|---|---|
wifi-densepose-signal |
SOTA CSI signal processing (6 algorithms from SpotFi, FarSense, Widar 3.0) | ruvector-mincut, ruvector-attn-mincut, ruvector-attention, ruvector-solver |
|
wifi-densepose-vitals |
Vital sign extraction: breathing (6-30 BPM) and heart rate (40-120 BPM) | -- | |
wifi-densepose-wifiscan |
Multi-BSSID WiFi scanning for Windows-enhanced sensing | -- |
Neural Network & Training
| Crate | Description | RuVector Integration | crates.io |
|---|---|---|---|
wifi-densepose-nn |
Multi-backend inference (ONNX, PyTorch, Candle) with DensePose head (24 body parts) | -- | |
wifi-densepose-train |
Training pipeline with MM-Fi dataset, 114->56 subcarrier interpolation | All 5 crates |
Disaster Response
| Crate | Description | RuVector Integration | crates.io |
|---|---|---|---|
wifi-densepose-mat |
Mass Casualty Assessment Tool -- survivor detection, triage, multi-AP localization | ruvector-solver, ruvector-temporal-tensor |
Hardware & Deployment
| Crate | Description | crates.io |
|---|---|---|
wifi-densepose-hardware |
ESP32, Intel 5300, Atheros CSI sensor interfaces (pure Rust, no FFI) | |
wifi-densepose-wasm |
WebAssembly bindings for browser-based disaster dashboard | |
wifi-densepose-sensing-server |
Axum server: ESP32 UDP ingestion, WebSocket broadcast, sensing UI |
Applications
| Crate | Description | crates.io |
|---|---|---|
wifi-densepose-api |
REST + WebSocket API layer | |
wifi-densepose-cli |
Command-line tool for MAT disaster scanning |
Architecture
wifi-densepose-core
(types, traits, errors)
|
+-------------------+-------------------+
| | |
wifi-densepose-signal wifi-densepose-nn wifi-densepose-hardware
(CSI processing) (inference) (ESP32, Intel 5300)
+ ruvector-mincut + ONNX Runtime |
+ ruvector-attn-mincut + PyTorch (tch) wifi-densepose-vitals
+ ruvector-attention + Candle (breathing, heart rate)
+ ruvector-solver |
| | wifi-densepose-wifiscan
+--------+---------+ (BSSID scanning)
|
+------------+------------+
| |
wifi-densepose-train wifi-densepose-mat
(training pipeline) (disaster response)
+ ALL 5 ruvector + ruvector-solver
+ ruvector-temporal-tensor
|
+-----------------+-----------------+
| | |
wifi-densepose-api wifi-densepose-wasm wifi-densepose-cli
(REST/WS) (browser WASM) (CLI tool)
|
wifi-densepose-sensing-server
(Axum + WebSocket)
RuVector Integration
All RuVector crates at v2.0.4 from crates.io:
| RuVector Crate | Used In | Purpose |
|---|---|---|
ruvector-mincut |
signal, train | Dynamic min-cut for subcarrier selection & person matching |
ruvector-attn-mincut |
signal, train | Attention-weighted min-cut for antenna gating & spectrograms |
ruvector-temporal-tensor |
train, mat | Tiered temporal compression (4-10x memory reduction) |
ruvector-solver |
signal, train, mat | Sparse Neumann solver for interpolation & triangulation |
ruvector-attention |
signal, train | Scaled dot-product attention for spatial features & BVP |
Signal Processing Algorithms
Six state-of-the-art algorithms implemented in wifi-densepose-signal:
| Algorithm | Paper | Year | Module |
|---|---|---|---|
| Conjugate Multiplication | SpotFi (SIGCOMM) | 2015 | csi_ratio.rs |
| Hampel Filter | WiGest | 2015 | hampel.rs |
| Fresnel Zone Model | FarSense (MobiCom) | 2019 | fresnel.rs |
| CSI Spectrogram | Standard STFT | 2018+ | spectrogram.rs |
| Subcarrier Selection | WiDance (MobiCom) | 2017 | subcarrier_selection.rs |
| Body Velocity Profile | Widar 3.0 (MobiSys) | 2019 | bvp.rs |
Quick Start
As a Library
use wifi_densepose_core::{CsiFrame, CsiMetadata, SignalProcessor};
use wifi_densepose_signal::{CsiProcessor, CsiProcessorConfig};
// Configure the CSI processor
let config = CsiProcessorConfig::default();
let processor = CsiProcessor::new(config);
// Process a CSI frame
let frame = CsiFrame { /* ... */ };
let processed = processor.process(&frame)?;
Vital Sign Monitoring
use wifi_densepose_vitals::{
CsiVitalPreprocessor, BreathingExtractor, HeartRateExtractor,
VitalAnomalyDetector,
};
let mut preprocessor = CsiVitalPreprocessor::new(56); // 56 subcarriers
let mut breathing = BreathingExtractor::new(100.0); // 100 Hz sample rate
let mut heartrate = HeartRateExtractor::new(100.0);
// Feed CSI frames and extract vitals
for frame in csi_stream {
let residuals = preprocessor.update(&frame.amplitudes);
if let Some(bpm) = breathing.push_residuals(&residuals) {
println!("Breathing: {:.1} BPM", bpm);
}
}
Disaster Response (MAT)
use wifi_densepose_mat::{DisasterResponse, DisasterConfig, DisasterType};
let config = DisasterConfig {
disaster_type: DisasterType::Earthquake,
max_scan_zones: 16,
..Default::default()
};
let mut responder = DisasterResponse::new(config);
responder.add_scan_zone(zone)?;
responder.start_continuous_scan().await?;
Hardware (ESP32)
use wifi_densepose_hardware::{Esp32CsiParser, CsiFrame};
let parser = Esp32CsiParser::new();
let raw_bytes: &[u8] = /* UDP packet from ESP32 */;
let frame: CsiFrame = parser.parse(raw_bytes)?;
println!("RSSI: {} dBm, {} subcarriers", frame.metadata.rssi, frame.subcarriers.len());
Training
# Check training crate (no GPU needed)
cargo check -p wifi-densepose-train --no-default-features
# Run training with GPU (requires tch/libtorch)
cargo run -p wifi-densepose-train --features tch-backend --bin train -- \
--config training.toml --dataset /path/to/mmfi
# Verify deterministic training proof
cargo run -p wifi-densepose-train --features tch-backend --bin verify-training
Building
# Clone the repository
git clone https://github.com/ruvnet/wifi-densepose.git
cd wifi-densepose/v2
# Check workspace (no GPU dependencies)
cargo check --workspace --no-default-features
# Run all tests
cargo test --workspace --no-default-features
# Build release
cargo build --release --workspace
Feature Flags
| Crate | Feature | Description |
|---|---|---|
wifi-densepose-nn |
onnx (default) |
ONNX Runtime backend |
wifi-densepose-nn |
tch-backend |
PyTorch (libtorch) backend |
wifi-densepose-nn |
candle-backend |
Candle (pure Rust) backend |
wifi-densepose-nn |
cuda |
CUDA GPU acceleration |
wifi-densepose-train |
tch-backend |
Enable GPU training modules |
wifi-densepose-mat |
ruvector (default) |
RuVector graph algorithms |
wifi-densepose-mat |
api (default) |
REST + WebSocket API |
wifi-densepose-mat |
distributed |
Multi-node coordination |
wifi-densepose-mat |
drone |
Drone-mounted scanning |
wifi-densepose-hardware |
esp32 |
ESP32 protocol support |
wifi-densepose-hardware |
intel5300 |
Intel 5300 CSI Tool |
wifi-densepose-hardware |
linux-wifi |
Linux commodity WiFi |
wifi-densepose-wifiscan |
wlanapi |
Windows WLAN API async scanning |
wifi-densepose-core |
serde |
Serialization support |
wifi-densepose-core |
async |
Async trait support |
Testing
# Unit tests (all crates)
cargo test --workspace --no-default-features
# Signal processing benchmarks
cargo bench -p wifi-densepose-signal
# Training benchmarks
cargo bench -p wifi-densepose-train --no-default-features
# Detection benchmarks
cargo bench -p wifi-densepose-mat
Supported Hardware
| Hardware | Crate Feature | CSI Subcarriers | Cost |
|---|---|---|---|
| ESP32-S3 Mesh (3-6 nodes) | hardware/esp32 |
52-56 | ~$54 |
| Intel 5300 NIC | hardware/intel5300 |
30 | ~$50 |
| Atheros AR9580 | hardware/linux-wifi |
56 | ~$100 |
| Any WiFi (Windows/Linux) | wifiscan |
RSSI-only | $0 |
Architecture Decision Records
Key design decisions documented in docs/adr/:
| ADR | Title | Status |
|---|---|---|
| ADR-014 | SOTA Signal Processing | Accepted |
| ADR-015 | MM-Fi + Wi-Pose Training Datasets | Accepted |
| ADR-016 | RuVector Training Pipeline | Accepted (Complete) |
| ADR-017 | RuVector Signal + MAT Integration | Accepted |
| ADR-021 | Vital Sign Detection Pipeline | Accepted |
| ADR-022 | Windows WiFi Enhanced Sensing | Accepted |
| ADR-024 | Contrastive CSI Embedding Model | Accepted |
Related Projects
- WiFi-DensePose -- Main repository (Python v1 + Rust v2)
- RuVector -- Graph algorithms for neural networks (5 crates, v2.0.4)
- rUv -- Creator and maintainer
License
All crates are dual-licensed under MIT OR Apache-2.0.
Copyright (c) 2024 rUv