Add comprehensive documentation for v0.2.0
- README.md: full project overview with features, install extras, CLI reference, web UI routes, config table, architecture diagrams, security model, /health API, and development setup - CLAUDE.md: updated for monorepo — reflects inlined subpackages, new import patterns, pip extras, and added modules - docs/deployment.md: practical RPi deployment guide covering hardware, OS setup, security hardening (swap/coredumps/firewall), installation, systemd service, config reference, fieldkit setup, key management, operational security limitations, troubleshooting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b9a541efdb
commit
b7d4cbe286
91
CLAUDE.md
91
CLAUDE.md
@ -1,16 +1,14 @@
|
||||
# SooSeF — Claude Code Project Guide
|
||||
|
||||
SooSeF (Soo Security Fieldkit) is an offline-first security toolkit for journalists, NGOs,
|
||||
and at-risk organizations. Part of the Soo Suite alongside Stegasoo and Verisoo.
|
||||
and at-risk organizations. Monorepo consolidating Stegasoo and Verisoo as subpackages.
|
||||
|
||||
Version 0.1.0 · Python >=3.11 · MIT License
|
||||
Version 0.2.0 · Python >=3.11 · MIT License
|
||||
|
||||
## Quick commands
|
||||
|
||||
```bash
|
||||
# Development install (requires stegasoo and verisoo installed first)
|
||||
pip install -e /path/to/stegasoo[web,dct,audio]
|
||||
pip install -e /path/to/verisoo[cli]
|
||||
# Development install (single command — stegasoo and verisoo are inlined subpackages)
|
||||
pip install -e ".[dev]"
|
||||
|
||||
pytest # Run tests
|
||||
@ -19,18 +17,74 @@ ruff check src/ tests/ frontends/ --fix # Lint
|
||||
mypy src/ # Type check
|
||||
```
|
||||
|
||||
### Pip extras
|
||||
|
||||
`stego-dct`, `stego-audio`, `stego-compression`, `attest`, `cli`, `web`, `api`,
|
||||
`fieldkit`, `federation`, `rpi`, `all`, `dev`
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
src/soosef/ Core library
|
||||
__init__.py Package init, __version__
|
||||
_availability.py Runtime checks for optional subpackages (has_stegasoo, has_verisoo)
|
||||
api.py Optional unified FastAPI app (uvicorn soosef.api:app)
|
||||
audit.py Audit logging
|
||||
cli.py Click CLI entry point (soosef command)
|
||||
paths.py All ~/.soosef/* path constants (single source of truth)
|
||||
config.py Unified config loader
|
||||
exceptions.py SoosefError base exception
|
||||
|
||||
stegasoo/ Steganography engine (inlined from stegasoo)
|
||||
encode.py / decode.py Core encode/decode API
|
||||
generate.py Cover image generation
|
||||
crypto.py AES-256-GCM encryption
|
||||
channel.py Channel key derivation
|
||||
steganography.py LSB steganography core
|
||||
dct_steganography.py DCT-domain JPEG steganography
|
||||
spread_steganography.py MDCT spread-spectrum audio steganography
|
||||
audio_steganography.py Audio stego pipeline
|
||||
video_steganography.py Video stego pipeline
|
||||
backends/ Pluggable stego backend registry (lsb, dct, protocol)
|
||||
batch.py Batch operations
|
||||
compression.py Payload compression (zstd, lz4)
|
||||
steganalysis.py Detection resistance analysis
|
||||
validation.py Input validation
|
||||
models.py Data models
|
||||
constants.py Magic bytes, version constants
|
||||
cli.py Stegasoo-specific CLI commands
|
||||
api.py / api_auth.py Stegasoo REST API + auth
|
||||
image_utils.py / audio_utils.py / video_utils.py
|
||||
keygen.py / qr_utils.py / recovery.py / debug.py / utils.py
|
||||
platform_presets.py Social-media-aware encoding presets
|
||||
|
||||
verisoo/ Provenance attestation engine (inlined from verisoo)
|
||||
attestation.py Core attestation creation
|
||||
verification.py Attestation verification
|
||||
crypto.py Ed25519 signing
|
||||
hashing.py Perceptual + cryptographic hashing
|
||||
embed.py Attestation embedding in images
|
||||
merkle.py Merkle tree for batch attestation
|
||||
binlog.py Binary attestation log
|
||||
lmdb_store.py LMDB-backed trust store
|
||||
storage.py Attestation storage abstraction
|
||||
federation.py Federated attestation exchange
|
||||
models.py Attestation, Verification dataclasses
|
||||
exceptions.py Verisoo-specific exceptions
|
||||
cli.py Verisoo-specific CLI commands
|
||||
api.py Verisoo REST API
|
||||
|
||||
federation/ Federated attestation chain system
|
||||
chain.py Hash chain construction
|
||||
entropy.py Entropy source for chain seeds
|
||||
models.py ChainEntry, ChainState dataclasses
|
||||
serialization.py CBOR chain serialization + export
|
||||
|
||||
keystore/ Unified key management
|
||||
manager.py Owns all key material (channel keys + Ed25519 identity)
|
||||
models.py KeyBundle, IdentityBundle dataclasses
|
||||
export.py Encrypted key bundle export/import
|
||||
|
||||
fieldkit/ Field security features
|
||||
killswitch.py Emergency data destruction
|
||||
deadman.py Dead man's switch
|
||||
@ -40,27 +94,30 @@ src/soosef/ Core library
|
||||
|
||||
frontends/web/ Unified Flask web UI
|
||||
app.py App factory (create_app())
|
||||
auth.py SQLite3 multi-user auth (from stegasoo)
|
||||
auth.py SQLite3 multi-user auth
|
||||
temp_storage.py File-based temp storage with expiry
|
||||
subprocess_stego.py Crash-safe subprocess isolation for stegasoo
|
||||
stego_worker.py Background stego processing
|
||||
stego_routes.py Stego route helpers
|
||||
ssl_utils.py Self-signed HTTPS cert generation
|
||||
blueprints/
|
||||
stego.py /encode, /decode, /generate (from stegasoo)
|
||||
attest.py /attest, /verify (wraps verisoo)
|
||||
stego.py /encode, /decode, /generate
|
||||
attest.py /attest, /verify
|
||||
fieldkit.py /fieldkit/* (killswitch, deadman, status)
|
||||
keys.py /keys/* (unified key management)
|
||||
admin.py /admin/* (user management)
|
||||
|
||||
frontends/cli/ CLI entry point
|
||||
main.py Click CLI wrapping stegasoo + verisoo + soosef commands
|
||||
frontends/cli/ CLI package init (main entry point is src/soosef/cli.py)
|
||||
```
|
||||
|
||||
## Dependency model
|
||||
|
||||
Stegasoo and Verisoo are pip dependencies, not forks:
|
||||
- `import stegasoo` for steganography
|
||||
- `import verisoo` for provenance attestation
|
||||
- SooSeF adds: unified web UI, key management, fieldkit features
|
||||
Stegasoo and Verisoo are inlined subpackages, not separate pip packages:
|
||||
- `from soosef.stegasoo import encode` for steganography
|
||||
- `from soosef.verisoo import Attestation` for provenance attestation
|
||||
- Never `import stegasoo` or `import verisoo` directly
|
||||
- `_availability.py` provides `has_stegasoo()` / `has_verisoo()` for graceful degradation
|
||||
when optional extras are not installed
|
||||
|
||||
## Key design decisions
|
||||
|
||||
@ -70,7 +127,11 @@ Stegasoo and Verisoo are pip dependencies, not forks:
|
||||
- **All state under ~/.soosef/** — one directory to back up, one to destroy
|
||||
- **Offline-first**: All static assets vendored, no CDN. pip wheels bundled for airgap install
|
||||
- **Flask blueprints**: stego, attest, fieldkit, keys, admin — clean route separation
|
||||
- **Flask-WTF**: CSRF protection on all form endpoints
|
||||
- **Waitress**: Production WSGI server (replaces dev-only Flask server)
|
||||
- **FastAPI option**: `soosef.api` provides a REST API alternative to the Flask web UI
|
||||
- **Pluggable backends**: Stego backends (LSB, DCT) registered via `backends/registry.py`
|
||||
|
||||
## Code conventions
|
||||
|
||||
Same as stegasoo: Black (100-char), Ruff, mypy, imperative commit messages.
|
||||
Black (100-char), Ruff, mypy, imperative commit messages.
|
||||
|
||||
422
README.md
422
README.md
@ -1,27 +1,417 @@
|
||||
# SooSeF — Soo Security Fieldkit
|
||||
# SooSeF -- Soo Security Fieldkit
|
||||
|
||||
Offline-first security toolkit for journalists, NGOs, and at-risk organizations.
|
||||
**Offline-first security toolkit for journalists, NGOs, and at-risk organizations.**
|
||||
|
||||
Part of the **Soo Suite**:
|
||||
- **Stegasoo** — hide encrypted messages in media (steganography)
|
||||
- **Verisoo** — prove image provenance and authenticity (attestation)
|
||||
- **SooSeF** — unified fieldkit with killswitch, dead man's switch, and key management
|
||||
<!-- badges -->
|
||||

|
||||

|
||||

|
||||
|
||||
## Status
|
||||
---
|
||||
|
||||
Pre-alpha. Phase 1 scaffolding complete.
|
||||
## What is SooSeF?
|
||||
|
||||
## Install (development)
|
||||
SooSeF combines steganography, provenance attestation, and field security tools into a
|
||||
single package designed for airgapped and resource-constrained environments. It lets you:
|
||||
|
||||
```bash
|
||||
pip install -e /path/to/stegasoo[web,dct,audio,cli]
|
||||
pip install -e /path/to/verisoo[cli]
|
||||
pip install -e ".[web,cli]"
|
||||
```
|
||||
- **Hide messages** in images, audio, and video using multiple steganographic techniques
|
||||
- **Prove authenticity** of photos and documents with Ed25519 signatures and Merkle trees
|
||||
- **Protect data in the field** with a killswitch, dead man's switch, tamper detection, USB device whitelisting, and GPS geofencing
|
||||
- **Manage cryptographic keys** with identity rotation, channel key generation, and encrypted key bundle export/import
|
||||
|
||||
Stegasoo (steganography, v4.3.0) and Verisoo (attestation, v0.1.0) are included as
|
||||
subpackages (`import soosef.stegasoo`, `import soosef.verisoo`). Everything ships as one
|
||||
install: `pip install soosef`.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
soosef init # Generate identity + channel key, create ~/.soosef/
|
||||
soosef serve # Start the web UI
|
||||
pip install "soosef[web,cli]"
|
||||
soosef init
|
||||
soosef serve
|
||||
```
|
||||
|
||||
This creates the `~/.soosef/` directory structure, generates an Ed25519 identity and
|
||||
channel key, writes a default config, and starts an HTTPS web UI on
|
||||
`https://127.0.0.1:5000`.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Steganography (Stegasoo)
|
||||
|
||||
- **LSB encoding** -- bit-level message hiding in PNG images
|
||||
- **DCT encoding** -- frequency-domain hiding in JPEG images (requires `stego-dct` extra)
|
||||
- **Audio steganography** -- hide data in WAV/FLAC audio (requires `stego-audio` extra)
|
||||
- **Video steganography** -- frame-level encoding
|
||||
- AES-256-GCM encryption with Argon2id key derivation
|
||||
- EXIF stripping on encode to prevent metadata leakage
|
||||
- Compression support (zstandard, optional LZ4)
|
||||
|
||||
### Attestation (Verisoo)
|
||||
|
||||
- Ed25519 digital signatures for images and files
|
||||
- Perceptual hashing (ImageHash) for tamper-evident photo attestation
|
||||
- LMDB-backed attestation storage
|
||||
- Append-only hash chain (CBOR-encoded) with Merkle tree verification
|
||||
- Batch attestation for directories
|
||||
|
||||
### Fieldkit
|
||||
|
||||
- **Killswitch** -- emergency destruction of all data under `~/.soosef/`
|
||||
- **Dead man's switch** -- automated purge if check-in is missed
|
||||
- **Tamper detection** -- file integrity monitoring with baseline snapshots
|
||||
- **USB whitelist** -- block or alert on unauthorized USB devices (Linux/pyudev)
|
||||
- **Geofence** -- GPS boundary enforcement with configurable radius
|
||||
|
||||
### Key Management
|
||||
|
||||
- Two separate key domains: AES-256-GCM channel keys (stego) and Ed25519 identity keys (attestation)
|
||||
- Key rotation for both identity and channel keys
|
||||
- Encrypted key bundle export/import for secure backup and transfer
|
||||
- QR code generation for key sharing
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Basic install (core library only)
|
||||
|
||||
```bash
|
||||
pip install soosef
|
||||
```
|
||||
|
||||
### With extras
|
||||
|
||||
```bash
|
||||
pip install "soosef[web,cli]" # Web UI + CLI (most common)
|
||||
pip install "soosef[all]" # Everything except dev tools
|
||||
pip install "soosef[dev]" # All + pytest, black, ruff, mypy
|
||||
```
|
||||
|
||||
### Available extras
|
||||
|
||||
| Extra | What it adds |
|
||||
|---|---|
|
||||
| `stego-dct` | DCT steganography (numpy, scipy, jpeglib, reedsolo) |
|
||||
| `stego-audio` | Audio steganography (pydub, soundfile, reedsolo) |
|
||||
| `stego-compression` | LZ4 compression support |
|
||||
| `attest` | Attestation features (imagehash, lmdb, exifread) |
|
||||
| `cli` | Click CLI with rich output and QR code support |
|
||||
| `web` | Flask web UI with Waitress/Gunicorn, includes attest + stego-dct |
|
||||
| `api` | FastAPI REST API with uvicorn, includes stego-dct |
|
||||
| `fieldkit` | Tamper monitoring (watchdog) and USB whitelist (pyudev) |
|
||||
| `federation` | Peer-to-peer attestation federation (aiohttp) |
|
||||
| `rpi` | Raspberry Pi deployment (web + cli + fieldkit + gpiozero) |
|
||||
| `all` | All of the above |
|
||||
| `dev` | All + pytest, pytest-cov, black, ruff, mypy |
|
||||
|
||||
### Airgapped / Raspberry Pi install
|
||||
|
||||
Bundle wheels on a networked machine, then install offline:
|
||||
|
||||
```bash
|
||||
# On networked machine
|
||||
pip download "soosef[rpi]" -d ./wheels
|
||||
|
||||
# Transfer ./wheels to target via USB
|
||||
# On airgapped machine
|
||||
pip install --no-index --find-links=./wheels "soosef[rpi]"
|
||||
soosef init
|
||||
soosef serve --host 0.0.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CLI Reference
|
||||
|
||||
All commands accept `--data-dir PATH` to override the default `~/.soosef` directory,
|
||||
and `--json` for machine-readable output.
|
||||
|
||||
```
|
||||
soosef [--data-dir PATH] [--json] COMMAND
|
||||
```
|
||||
|
||||
### Core commands
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `soosef init` | Create directory structure, generate identity + channel key, write default config |
|
||||
| `soosef serve` | Start the web UI (default: `https://127.0.0.1:5000`) |
|
||||
| `soosef status` | Show instance status: identity, keys, chain, fieldkit, config |
|
||||
|
||||
### `soosef serve` options
|
||||
|
||||
| Option | Default | Description |
|
||||
|---|---|---|
|
||||
| `--host` | `127.0.0.1` | Bind address |
|
||||
| `--port` | `5000` | Bind port |
|
||||
| `--no-https` | off | Disable HTTPS (use HTTP) |
|
||||
| `--debug` | off | Use Flask dev server instead of Waitress |
|
||||
| `--workers` | `4` | Number of Waitress/Gunicorn worker threads |
|
||||
|
||||
### Steganography commands (`soosef stego`)
|
||||
|
||||
```bash
|
||||
soosef stego encode -i cover.png -m "secret message" -o output.png
|
||||
soosef stego decode -i output.png
|
||||
```
|
||||
|
||||
### Attestation commands (`soosef attest`)
|
||||
|
||||
```bash
|
||||
soosef attest sign -i photo.jpg # Sign a file
|
||||
soosef attest verify -i photo.jpg # Verify attestation
|
||||
soosef attest batch ./photos/ --caption "Field report"
|
||||
```
|
||||
|
||||
### Fieldkit commands (`soosef fieldkit`)
|
||||
|
||||
```bash
|
||||
soosef fieldkit status # Show fieldkit state
|
||||
soosef fieldkit checkin # Reset dead man's switch timer
|
||||
soosef fieldkit check-deadman # Check if deadman timer has expired
|
||||
soosef fieldkit purge --confirm # Activate killswitch (destroys all data)
|
||||
soosef fieldkit geofence set --lat 48.8566 --lon 2.3522 --radius 1000
|
||||
soosef fieldkit geofence check --lat 48.8600 --lon 2.3500
|
||||
soosef fieldkit geofence clear
|
||||
soosef fieldkit usb snapshot # Snapshot current USB devices as whitelist
|
||||
soosef fieldkit usb check # Check for unauthorized USB devices
|
||||
```
|
||||
|
||||
### Key management commands (`soosef keys`)
|
||||
|
||||
```bash
|
||||
soosef keys show # Display current key info
|
||||
soosef keys export -o backup.enc # Export encrypted key bundle
|
||||
soosef keys import -b backup.enc # Import key bundle
|
||||
soosef keys rotate-identity # Generate new Ed25519 identity
|
||||
soosef keys rotate-channel # Generate new channel key
|
||||
```
|
||||
|
||||
### Chain commands (`soosef chain`)
|
||||
|
||||
```bash
|
||||
soosef chain status # Show chain head, length, integrity
|
||||
soosef chain verify # Verify entire chain integrity
|
||||
soosef chain show INDEX # Show a specific chain record
|
||||
soosef chain log --count 20 # Show recent chain entries
|
||||
soosef chain backfill # Backfill existing attestations into chain
|
||||
soosef chain export --start 0 --end 100 -o chain.cbor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Web UI
|
||||
|
||||
Start with `soosef serve`. The web UI provides authenticated access to all features
|
||||
through Flask blueprints.
|
||||
|
||||
### Routes
|
||||
|
||||
| Blueprint | Routes | Description |
|
||||
|---|---|---|
|
||||
| stego | `/encode`, `/decode`, `/generate` | Steganography operations |
|
||||
| attest | `/attest`, `/verify` | Attestation signing and verification |
|
||||
| fieldkit | `/fieldkit/*` | Killswitch, dead man's switch, status dashboard |
|
||||
| keys | `/keys/*` | Key management, rotation, export/import |
|
||||
| admin | `/admin/*` | User management (multi-user auth via SQLite) |
|
||||
| health | `/health` | Capability reporting endpoint (see API section) |
|
||||
|
||||
<!-- TODO: screenshots -->
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
SooSeF loads configuration from `~/.soosef/config.json`. All fields have sensible defaults.
|
||||
`soosef init` writes the default config file.
|
||||
|
||||
### Config fields
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `host` | string | `127.0.0.1` | Web UI bind address |
|
||||
| `port` | int | `5000` | Web UI bind port |
|
||||
| `https_enabled` | bool | `true` | Enable HTTPS with self-signed cert |
|
||||
| `auth_enabled` | bool | `true` | Require login for web UI |
|
||||
| `max_upload_mb` | int | `50` | Maximum upload size in MB |
|
||||
| `session_timeout_minutes` | int | `15` | Session expiry |
|
||||
| `login_lockout_attempts` | int | `5` | Failed logins before lockout |
|
||||
| `login_lockout_minutes` | int | `15` | Lockout duration |
|
||||
| `default_embed_mode` | string | `auto` | Stegasoo encoding mode |
|
||||
| `killswitch_enabled` | bool | `false` | Enable killswitch functionality |
|
||||
| `deadman_enabled` | bool | `false` | Enable dead man's switch |
|
||||
| `deadman_interval_hours` | int | `24` | Check-in interval |
|
||||
| `deadman_grace_hours` | int | `2` | Grace period after missed check-in |
|
||||
| `deadman_warning_webhook` | string | `""` | URL to POST warning before auto-purge |
|
||||
| `usb_monitoring_enabled` | bool | `false` | Enable USB device whitelist enforcement |
|
||||
| `tamper_monitoring_enabled` | bool | `false` | Enable file integrity monitoring |
|
||||
| `chain_enabled` | bool | `true` | Enable attestation hash chain |
|
||||
| `chain_auto_wrap` | bool | `true` | Auto-wrap attestations in chain records |
|
||||
| `backup_reminder_days` | int | `7` | Days before backup reminder |
|
||||
| `gpio_killswitch_pin` | int | `17` | Raspberry Pi GPIO pin for hardware killswitch |
|
||||
| `gpio_killswitch_hold_seconds` | float | `5.0` | Hold duration to trigger hardware killswitch |
|
||||
|
||||
### Environment variables
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `SOOSEF_DATA_DIR` | Override the data directory (default: `~/.soosef`) |
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Source layout
|
||||
|
||||
```
|
||||
src/soosef/
|
||||
__init__.py Package init, __version__
|
||||
cli.py Click CLI (entry point: soosef)
|
||||
paths.py All path constants (single source of truth)
|
||||
config.py Unified config loader (dataclass + JSON)
|
||||
exceptions.py SoosefError base exception
|
||||
stegasoo/ Steganography engine (subpackage)
|
||||
verisoo/ Attestation engine (subpackage)
|
||||
keystore/
|
||||
manager.py Key material management (channel + identity)
|
||||
models.py KeyBundle, IdentityBundle dataclasses
|
||||
export.py Encrypted key bundle export/import
|
||||
fieldkit/
|
||||
killswitch.py Emergency data destruction
|
||||
deadman.py Dead man's switch
|
||||
tamper.py File integrity monitoring
|
||||
usb_monitor.py USB device whitelist (Linux/pyudev)
|
||||
geofence.py GPS boundary enforcement
|
||||
|
||||
frontends/web/
|
||||
app.py Flask app factory (create_app())
|
||||
auth.py SQLite3 multi-user auth
|
||||
temp_storage.py File-based temp storage with expiry
|
||||
subprocess_stego.py Crash-safe subprocess isolation
|
||||
ssl_utils.py Self-signed HTTPS cert generation
|
||||
blueprints/
|
||||
stego.py /encode, /decode, /generate
|
||||
attest.py /attest, /verify
|
||||
fieldkit.py /fieldkit/*
|
||||
keys.py /keys/*
|
||||
admin.py /admin/*
|
||||
```
|
||||
|
||||
### Data directory (`~/.soosef/`)
|
||||
|
||||
```
|
||||
~/.soosef/
|
||||
config.json Unified configuration
|
||||
audit.jsonl Append-only audit trail
|
||||
identity/ Ed25519 keypair (private.pem, public.pem, identity.meta.json)
|
||||
stegasoo/ Channel key (channel.key)
|
||||
attestations/ Verisoo attestation store (log.bin, index/, peers.json)
|
||||
chain/ Hash chain (chain.bin, state.cbor)
|
||||
auth/ Web UI auth database (soosef.db)
|
||||
certs/ Self-signed TLS certificates
|
||||
fieldkit/ Fieldkit state (deadman.json, tamper/, usb/, geofence.json)
|
||||
temp/ Ephemeral file storage
|
||||
instance/ Flask instance (sessions, secret key)
|
||||
```
|
||||
|
||||
Sensitive directories (`identity/`, `auth/`, `certs/`, and the root) are created with
|
||||
`0700` permissions.
|
||||
|
||||
---
|
||||
|
||||
## Security Model
|
||||
|
||||
**Two key domains, never merged.** Stegasoo uses AES-256-GCM with keys derived via
|
||||
Argon2id from user-supplied factors. Verisoo uses Ed25519 for signing. These serve
|
||||
different security purposes and are kept strictly separate.
|
||||
|
||||
**Killswitch priority.** The killswitch destroys all data under `~/.soosef/`, including
|
||||
the audit log. This is intentional -- in a field compromise scenario, data destruction
|
||||
takes precedence over audit trail preservation.
|
||||
|
||||
**Offline-first.** All static assets are vendored (no CDN calls). Pip wheels can be
|
||||
bundled for fully airgapped installation. No network access is required for any core
|
||||
functionality.
|
||||
|
||||
**Web UI hardening:**
|
||||
- CSRF protection via Flask-WTF
|
||||
- Session timeout (default: 15 minutes)
|
||||
- Login rate limiting with lockout (5 attempts, 15-minute lockout)
|
||||
- HTTPS by default with auto-generated self-signed certificates
|
||||
- EXIF stripping on steganographic encode to prevent metadata leakage
|
||||
|
||||
**Subprocess isolation.** Steganographic operations run in a subprocess boundary
|
||||
(`subprocess_stego.py`) to contain crashes and prevent memory corruption from affecting
|
||||
the main web server process.
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
### `/health` endpoint
|
||||
|
||||
The web UI exposes a `/health` endpoint that reports installed capabilities:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"version": "0.2.0",
|
||||
"capabilities": ["stego-lsb", "stego-dct", "attest", "fieldkit", "chain"]
|
||||
}
|
||||
```
|
||||
|
||||
Useful for monitoring and for clients to discover which extras are installed.
|
||||
|
||||
### FastAPI (optional)
|
||||
|
||||
Install the `api` extra for a standalone FastAPI REST interface:
|
||||
|
||||
```bash
|
||||
pip install "soosef[api]"
|
||||
```
|
||||
|
||||
This provides `soosef.api` with a FastAPI application served by uvicorn, suitable for
|
||||
programmatic integration.
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
git clone https://github.com/alee/soosef.git
|
||||
cd soosef
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
### Commands
|
||||
|
||||
```bash
|
||||
pytest # Run tests with coverage
|
||||
black src/ tests/ frontends/ # Format (100-char line length)
|
||||
ruff check src/ tests/ frontends/ --fix # Lint
|
||||
mypy src/ # Type check
|
||||
```
|
||||
|
||||
### Code style
|
||||
|
||||
- Black with 100-character line length
|
||||
- Ruff with E, F, I, N, W, UP rule sets
|
||||
- mypy strict mode with missing imports ignored
|
||||
- Imperative commit messages (e.g., "Add killswitch purge confirmation")
|
||||
|
||||
### Python support
|
||||
|
||||
Python 3.11, 3.12, 3.13, and 3.14.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT License. See [LICENSE](LICENSE) for details.
|
||||
|
||||
638
docs/deployment.md
Normal file
638
docs/deployment.md
Normal file
@ -0,0 +1,638 @@
|
||||
# SooSeF Deployment Guide
|
||||
|
||||
Deploying SooSeF on a Raspberry Pi for airgapped LAN use.
|
||||
|
||||
This guide is for field deployers: IT staff at NGOs, technically competent journalists,
|
||||
and anyone setting up a shared SooSeF instance on a local network with no internet access.
|
||||
|
||||
---
|
||||
|
||||
## 1. Hardware Requirements
|
||||
|
||||
**Minimum:**
|
||||
|
||||
- Raspberry Pi 4 Model B, 2 GB RAM (4 GB recommended)
|
||||
- 32 GB microSD card (Class 10 / A2 recommended)
|
||||
- USB-C power supply (5V 3A, official RPi PSU recommended)
|
||||
- Ethernet cable or pre-configured Wi-Fi for LAN
|
||||
|
||||
**Optional:**
|
||||
|
||||
- USB GPS module (e.g., VK-162) for geofencing
|
||||
- Momentary push button + 10k pull-down resistor on GPIO pin 17 for hardware killswitch
|
||||
- USB drive for airgap package transfer and key backups
|
||||
- Case with passive cooling (no fan noise in sensitive environments)
|
||||
|
||||
If you plan to use the hardware killswitch button, wire it between GPIO 17 and 3.3V with
|
||||
a 10k pull-down to GND. The default requires a 5-second hold to trigger (configurable via
|
||||
`gpio_killswitch_hold_seconds` in config).
|
||||
|
||||
---
|
||||
|
||||
## 2. OS Setup
|
||||
|
||||
Install **Raspberry Pi OS Lite (64-bit, Bookworm or later)**. The desktop environment is
|
||||
unnecessary and wastes resources.
|
||||
|
||||
After first boot:
|
||||
|
||||
```bash
|
||||
# Set hostname
|
||||
sudo hostnamectl set-hostname soosef-node
|
||||
|
||||
# Create a dedicated service user
|
||||
sudo useradd -m -s /bin/bash soosef
|
||||
sudo passwd soosef
|
||||
|
||||
# Enable SSH (if not already)
|
||||
sudo systemctl enable --now ssh
|
||||
|
||||
# Update system packages (do this before going airgapped)
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
```
|
||||
|
||||
Set a strong password. If possible, use SSH key authentication and disable password login
|
||||
in `/etc/ssh/sshd_config` (`PasswordAuthentication no`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Security Hardening
|
||||
|
||||
### 3.1 Disable or encrypt swap
|
||||
|
||||
Python does not zero memory when objects are garbage-collected. Cryptographic keys,
|
||||
passwords, and plaintext can persist in swap long after the process exits. On an SD card,
|
||||
this data may survive even after the swap file is deleted (wear leveling).
|
||||
|
||||
**Option A: Disable swap entirely (recommended if you have 4 GB+ RAM)**
|
||||
|
||||
```bash
|
||||
sudo dphys-swapfile swapoff
|
||||
sudo systemctl disable dphys-swapfile
|
||||
sudo rm /var/swap
|
||||
```
|
||||
|
||||
**Option B: Encrypted swap (if you need swap on 2 GB models)**
|
||||
|
||||
```bash
|
||||
sudo dphys-swapfile swapoff
|
||||
sudo systemctl disable dphys-swapfile
|
||||
|
||||
# Use dm-crypt with a random key (regenerated each boot)
|
||||
echo "swap /dev/mmcblk0p3 /dev/urandom swap,cipher=aes-xts-plain64,size=256" | sudo tee -a /etc/crypttab
|
||||
echo "/dev/mapper/swap none swap sw 0 0" | sudo tee -a /etc/fstab
|
||||
```
|
||||
|
||||
Adjust the device path to match your partition layout.
|
||||
|
||||
### 3.2 Disable core dumps
|
||||
|
||||
A core dump from the SooSeF process would contain key material in plaintext.
|
||||
|
||||
```bash
|
||||
echo "* hard core 0" | sudo tee -a /etc/security/limits.conf
|
||||
echo "kernel.core_pattern=/dev/null" | sudo tee -a /etc/sysctl.d/99-soosef.conf
|
||||
sudo sysctl -p /etc/sysctl.d/99-soosef.conf
|
||||
```
|
||||
|
||||
### 3.3 Firewall
|
||||
|
||||
```bash
|
||||
sudo apt install -y ufw
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
sudo ufw allow ssh
|
||||
sudo ufw allow 5000/tcp # SooSeF web UI
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
If running fully airgapped, also deny outgoing:
|
||||
|
||||
```bash
|
||||
sudo ufw default deny outgoing
|
||||
```
|
||||
|
||||
### 3.4 Disable unnecessary services
|
||||
|
||||
```bash
|
||||
sudo systemctl disable bluetooth
|
||||
sudo systemctl disable avahi-daemon
|
||||
sudo systemctl disable triggerhappy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Installation
|
||||
|
||||
### 4.1 System dependencies
|
||||
|
||||
```bash
|
||||
sudo apt install -y \
|
||||
python3 python3-pip python3-venv python3-dev \
|
||||
libjpeg-dev libjpeg62-turbo-dev zlib1g-dev \
|
||||
libffi-dev libssl-dev \
|
||||
shred coreutils
|
||||
```
|
||||
|
||||
`libjpeg-dev` is required for Pillow and jpeglib (DCT steganography). `libffi-dev` is
|
||||
required for argon2-cffi.
|
||||
|
||||
### 4.2 Create virtual environment
|
||||
|
||||
```bash
|
||||
sudo -u soosef -i # Switch to the soosef user
|
||||
|
||||
python3 -m venv ~/soosef-env
|
||||
source ~/soosef-env/bin/activate
|
||||
pip install --upgrade pip wheel
|
||||
```
|
||||
|
||||
### 4.3 Install SooSeF
|
||||
|
||||
**If the Pi has internet access (pre-deployment):**
|
||||
|
||||
```bash
|
||||
pip install "soosef[web,cli,fieldkit]"
|
||||
```
|
||||
|
||||
For hardware killswitch support via GPIO:
|
||||
|
||||
```bash
|
||||
pip install "soosef[rpi]"
|
||||
```
|
||||
|
||||
The `rpi` extra includes `web`, `cli`, `fieldkit`, and `gpiozero`.
|
||||
|
||||
**For airgapped install (no internet on the Pi):**
|
||||
|
||||
On an internet-connected machine with the same architecture (aarch64 for RPi 4):
|
||||
|
||||
```bash
|
||||
mkdir soosef-wheels
|
||||
pip download "soosef[rpi]" -d soosef-wheels/
|
||||
```
|
||||
|
||||
Copy the `soosef-wheels/` directory to a USB drive, then on the Pi:
|
||||
|
||||
```bash
|
||||
pip install --no-index --find-links /media/usb/soosef-wheels/ "soosef[rpi]"
|
||||
```
|
||||
|
||||
### 4.4 Verify installation
|
||||
|
||||
```bash
|
||||
soosef --version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Initial Setup
|
||||
|
||||
### 5.1 Initialize SooSeF
|
||||
|
||||
```bash
|
||||
soosef init
|
||||
```
|
||||
|
||||
This creates the `~/.soosef/` directory structure:
|
||||
|
||||
```
|
||||
~/.soosef/
|
||||
config.json Unified configuration
|
||||
identity/ Ed25519 signing keypair (verisoo)
|
||||
private.pem
|
||||
public.pem
|
||||
identity.meta.json
|
||||
stegasoo/ Stegasoo state
|
||||
channel.key AES-256-GCM channel key
|
||||
attestations/ Verisoo attestation log and index
|
||||
chain/ Hash chain data
|
||||
auth/ Web UI user database (SQLite)
|
||||
certs/ Self-signed TLS certificates
|
||||
fieldkit/ Killswitch, deadman, tamper, USB, geofence state
|
||||
temp/ Ephemeral upload/processing files
|
||||
instance/ Flask session data
|
||||
audit.jsonl Append-only audit trail
|
||||
```
|
||||
|
||||
The `identity/` and `auth/` directories are created with mode 0700.
|
||||
|
||||
`soosef init` generates:
|
||||
|
||||
- An Ed25519 identity keypair (for signing attestations)
|
||||
- A channel key (for steganographic encoding)
|
||||
- A default `config.json`
|
||||
|
||||
### 5.2 First user setup
|
||||
|
||||
Start the server and create the first admin user through the web UI:
|
||||
|
||||
```bash
|
||||
soosef serve --host 0.0.0.0 --no-https
|
||||
```
|
||||
|
||||
Navigate to `http://<pi-ip>:5000` from a device on the same LAN. The web UI will prompt
|
||||
you to create the first user account.
|
||||
|
||||
After creating the admin account, stop the server (Ctrl+C) and restart with HTTPS
|
||||
(see Section 6).
|
||||
|
||||
---
|
||||
|
||||
## 6. Running
|
||||
|
||||
### 6.1 Basic usage
|
||||
|
||||
```bash
|
||||
# LAN-only, no HTTPS (acceptable if the network is physically isolated)
|
||||
soosef serve --host 0.0.0.0 --no-https
|
||||
|
||||
# With self-signed HTTPS (recommended)
|
||||
soosef serve --host 0.0.0.0
|
||||
|
||||
# Custom port
|
||||
soosef serve --host 0.0.0.0 --port 8443
|
||||
```
|
||||
|
||||
On first HTTPS start, SooSeF auto-generates a self-signed certificate at
|
||||
`~/.soosef/certs/cert.pem`. Browsers will show a certificate warning -- this is expected
|
||||
for self-signed certs. Instruct users to accept the warning or distribute the cert file
|
||||
to client devices.
|
||||
|
||||
SooSeF uses Waitress (pure Python, no C dependencies) as its production server with 4
|
||||
worker threads by default. Adjust with `--workers`.
|
||||
|
||||
### 6.2 systemd service
|
||||
|
||||
Create `/etc/systemd/system/soosef.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=SooSeF Security Fieldkit
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=soosef
|
||||
Group=soosef
|
||||
WorkingDirectory=/home/soosef
|
||||
Environment="PATH=/home/soosef/soosef-env/bin:/usr/bin"
|
||||
ExecStart=/home/soosef/soosef-env/bin/soosef serve --host 0.0.0.0 --workers 4
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# Hardening
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=read-only
|
||||
ReadWritePaths=/home/soosef/.soosef
|
||||
PrivateTmp=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Enable and start:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now soosef
|
||||
sudo journalctl -u soosef -f # Watch logs
|
||||
```
|
||||
|
||||
Add `--no-https` to `ExecStart` if running on a physically isolated LAN where TLS is
|
||||
unnecessary.
|
||||
|
||||
---
|
||||
|
||||
## 7. Configuration
|
||||
|
||||
Configuration lives at `~/.soosef/config.json`. Edit it directly or use the web admin
|
||||
panel. All fields have sensible defaults -- you only need to set what you want to change.
|
||||
|
||||
| Field | Default | Description |
|
||||
|---|---|---|
|
||||
| `host` | `127.0.0.1` | Bind address. Set to `0.0.0.0` for LAN access. |
|
||||
| `port` | `5000` | TCP port for the web UI. |
|
||||
| `https_enabled` | `true` | Enable self-signed HTTPS. |
|
||||
| `auth_enabled` | `true` | Require login. Do not disable this. |
|
||||
| `max_upload_mb` | `50` | Maximum file upload size in MB. |
|
||||
| `session_timeout_minutes` | `15` | Idle session expiry. Lower is safer. |
|
||||
| `login_lockout_attempts` | `5` | Failed logins before lockout. |
|
||||
| `login_lockout_minutes` | `15` | Lockout duration. |
|
||||
| `killswitch_enabled` | `false` | Enable software killswitch. |
|
||||
| `deadman_enabled` | `false` | Enable dead man's switch. |
|
||||
| `deadman_interval_hours` | `24` | Hours between required check-ins. |
|
||||
| `deadman_grace_hours` | `2` | Grace period after missed check-in before purge. |
|
||||
| `deadman_warning_webhook` | `""` | URL to POST a JSON warning when check-in is overdue. Must be a public URL (SSRF protection blocks private IPs). |
|
||||
| `usb_monitoring_enabled` | `false` | Monitor for unauthorized USB devices. |
|
||||
| `tamper_monitoring_enabled` | `false` | File integrity monitoring. |
|
||||
| `chain_enabled` | `true` | Wrap attestations in a hash chain. |
|
||||
| `chain_auto_wrap` | `true` | Automatically chain verisoo attestations. |
|
||||
| `backup_reminder_days` | `7` | Warn if no backup in this many days. |
|
||||
| `gpio_killswitch_pin` | `17` | GPIO pin for hardware killswitch button. |
|
||||
| `gpio_killswitch_hold_seconds` | `5.0` | Required hold time to trigger hardware killswitch. |
|
||||
|
||||
Example minimal config for a field deployment:
|
||||
|
||||
```json
|
||||
{
|
||||
"host": "0.0.0.0",
|
||||
"port": 5000,
|
||||
"https_enabled": true,
|
||||
"session_timeout_minutes": 10,
|
||||
"deadman_enabled": true,
|
||||
"deadman_interval_hours": 12,
|
||||
"deadman_grace_hours": 1,
|
||||
"killswitch_enabled": true,
|
||||
"backup_reminder_days": 3
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Fieldkit Setup
|
||||
|
||||
### 8.1 Dead man's switch
|
||||
|
||||
The dead man's switch requires periodic check-ins. If you miss a check-in, SooSeF sends
|
||||
a warning during the grace period. If the grace period expires without a check-in, the
|
||||
killswitch fires automatically and destroys all key material and data.
|
||||
|
||||
Arm it:
|
||||
|
||||
```bash
|
||||
soosef fieldkit deadman arm --interval 12 --grace 1
|
||||
```
|
||||
|
||||
This requires a check-in every 12 hours, with a 1-hour grace period.
|
||||
|
||||
Check in:
|
||||
|
||||
```bash
|
||||
soosef fieldkit checkin
|
||||
```
|
||||
|
||||
You can also check in through the web UI at `/fieldkit`.
|
||||
|
||||
Check status:
|
||||
|
||||
```bash
|
||||
soosef status
|
||||
```
|
||||
|
||||
The dead man's switch enforcement loop runs as a background thread inside `soosef serve`,
|
||||
checking every 60 seconds. It will send a webhook warning (if configured) during the grace
|
||||
period, then execute a full purge if the grace period expires.
|
||||
|
||||
Disarm:
|
||||
|
||||
```bash
|
||||
soosef fieldkit deadman disarm
|
||||
```
|
||||
|
||||
### 8.2 Geofence
|
||||
|
||||
If you have a USB GPS module, you can set a geographic boundary. SooSeF will trigger the
|
||||
killswitch if the device moves outside the fence.
|
||||
|
||||
```bash
|
||||
soosef fieldkit geofence set --lat 50.4501 --lon 30.5234 --radius 5000
|
||||
```
|
||||
|
||||
Coordinates are in decimal degrees, radius in meters.
|
||||
|
||||
### 8.3 USB whitelist
|
||||
|
||||
Record currently connected USB devices as the trusted baseline:
|
||||
|
||||
```bash
|
||||
soosef fieldkit usb learn
|
||||
```
|
||||
|
||||
When monitoring is enabled, SooSeF will alert (or trigger killswitch, depending on config)
|
||||
if an unknown USB device is connected.
|
||||
|
||||
### 8.4 Tamper baseline
|
||||
|
||||
Record file integrity baselines for critical files:
|
||||
|
||||
```bash
|
||||
soosef fieldkit tamper baseline
|
||||
```
|
||||
|
||||
SooSeF monitors for unexpected changes to tracked files when tamper monitoring is enabled.
|
||||
|
||||
---
|
||||
|
||||
## 9. Key Management
|
||||
|
||||
SooSeF manages two separate key domains:
|
||||
|
||||
- **Ed25519 identity key** (`~/.soosef/identity/`) -- used for signing attestations.
|
||||
This is your provenance identity.
|
||||
- **AES-256-GCM channel key** (`~/.soosef/stegasoo/channel.key`) -- used for
|
||||
steganographic encoding/decoding. Shared with anyone who needs to read your
|
||||
stego messages.
|
||||
|
||||
These are separate security concerns and are never merged.
|
||||
|
||||
### 9.1 Backup
|
||||
|
||||
Back up keys regularly. SooSeF warns if no backup has been taken within the
|
||||
`backup_reminder_days` window (default: 7 days).
|
||||
|
||||
```bash
|
||||
soosef keys backup --output /media/usb/soosef-backup.enc
|
||||
```
|
||||
|
||||
This creates an encrypted bundle. You will be prompted for a passphrase. Store the USB
|
||||
drive physically separate from the Pi.
|
||||
|
||||
### 9.2 Restore
|
||||
|
||||
```bash
|
||||
soosef keys restore --input /media/usb/soosef-backup.enc
|
||||
```
|
||||
|
||||
### 9.3 Key rotation
|
||||
|
||||
Generate a new channel key (the old one is overwritten):
|
||||
|
||||
```bash
|
||||
soosef init --no-identity
|
||||
```
|
||||
|
||||
Generate a new identity (the old one is overwritten -- all previous attestations will
|
||||
reference the old fingerprint):
|
||||
|
||||
```bash
|
||||
soosef init --no-channel
|
||||
```
|
||||
|
||||
After rotating keys, take a fresh backup immediately.
|
||||
|
||||
### 9.4 Trusting collaborator keys
|
||||
|
||||
Import a collaborator's public key so you can verify their attestations:
|
||||
|
||||
```bash
|
||||
soosef keys trust --import /media/usb/collaborator-pubkey.pem
|
||||
```
|
||||
|
||||
Verify the fingerprint out-of-band (in person, over a secure channel) before trusting.
|
||||
|
||||
---
|
||||
|
||||
## 10. Operational Security Notes
|
||||
|
||||
SooSeF is a tool, not a shield. Understand what it cannot do.
|
||||
|
||||
### What SooSeF does not protect against
|
||||
|
||||
- **Physical coercion.** If someone forces you to unlock the device or reveal passwords,
|
||||
no software can help. The killswitch is for situations where you can act before
|
||||
interception, not during.
|
||||
- **Social engineering.** SooSeF cannot prevent users from being tricked into revealing
|
||||
credentials or disabling security features.
|
||||
- **Leaving the browser open.** The session timeout helps, but if someone walks up to an
|
||||
unlocked browser session, they have access. Train users to close the browser or lock the
|
||||
screen.
|
||||
- **Compromised client devices.** SooSeF secures the server. If a user's laptop has
|
||||
malware, their browser session is compromised regardless of what the server does.
|
||||
|
||||
### Shred limitations on flash storage
|
||||
|
||||
The killswitch uses `shred` on Linux (3-pass overwrite + zero). On spinning disks, this
|
||||
is effective. On SD cards and SSDs, **it is not reliable** because:
|
||||
|
||||
- Flash translation layers remap physical blocks. Overwritten data may persist on
|
||||
remapped blocks.
|
||||
- Wear leveling distributes writes across the flash, meaning the original block may be
|
||||
preserved.
|
||||
|
||||
SooSeF's defense against this is **cryptographic erasure**: destroy the keys first, then
|
||||
the data. Even if fragments of encrypted data survive on flash, they are useless without
|
||||
the keys. The killswitch destroys keys before anything else, and keys are small enough to
|
||||
fit in a single flash block.
|
||||
|
||||
This is why full-disk encryption matters -- see below.
|
||||
|
||||
### Full-disk encryption (LUKS)
|
||||
|
||||
For serious deployments, encrypt the entire SD card (or at least the data partition) with
|
||||
LUKS. This way, even if the SD card is physically seized:
|
||||
|
||||
- All data at rest is encrypted
|
||||
- Shred limitations are irrelevant because the underlying storage is encrypted
|
||||
- Power-off = data inaccessible (assuming the LUKS passphrase is strong)
|
||||
|
||||
Setting up LUKS on Raspberry Pi OS is beyond the scope of this guide, but the short
|
||||
version is: create an encrypted partition, mount it at `/home/soosef/.soosef`, and
|
||||
configure auto-unlock via a keyfile on a separate USB (remove the USB after boot in
|
||||
hostile environments).
|
||||
|
||||
### Memory considerations
|
||||
|
||||
Python does not securely zero memory. Key material, passwords, and plaintext may persist
|
||||
in process memory and swap. The mitigations in Section 3 (disable swap, disable core
|
||||
dumps) reduce the window, but a memory dump of the running process would expose secrets.
|
||||
This is a fundamental limitation of Python-based security tools.
|
||||
|
||||
---
|
||||
|
||||
## 11. Troubleshooting
|
||||
|
||||
### Health check
|
||||
|
||||
SooSeF exposes a `/health` endpoint on the web UI. Hit it from the LAN to verify the
|
||||
server is running:
|
||||
|
||||
```bash
|
||||
curl -k https://<pi-ip>:5000/health
|
||||
```
|
||||
|
||||
The `-k` flag skips certificate verification for self-signed certs.
|
||||
|
||||
### System status
|
||||
|
||||
```bash
|
||||
soosef status
|
||||
```
|
||||
|
||||
This checks identity key, channel key, trusted keys, dead man's switch state, geofence,
|
||||
chain status, and backup status.
|
||||
|
||||
### Common issues
|
||||
|
||||
**scipy fails to build on Raspberry Pi**
|
||||
|
||||
scipy requires Fortran and BLAS libraries. On Raspberry Pi OS:
|
||||
|
||||
```bash
|
||||
sudo apt install -y gfortran libopenblas-dev
|
||||
```
|
||||
|
||||
If the build still fails (common on low-memory Pis), increase swap temporarily during
|
||||
install, then disable it again:
|
||||
|
||||
```bash
|
||||
sudo dphys-swapfile swapon
|
||||
pip install scipy
|
||||
sudo dphys-swapfile swapoff
|
||||
```
|
||||
|
||||
Or use pre-built wheels:
|
||||
|
||||
```bash
|
||||
pip install --prefer-binary scipy
|
||||
```
|
||||
|
||||
**Argon2 OOM on low-memory Pi (2 GB)**
|
||||
|
||||
Argon2 password hashing is memory-intensive by design. If the server crashes during login
|
||||
on a 2 GB Pi with other services running, either:
|
||||
|
||||
- Free memory by disabling unnecessary services
|
||||
- Reduce Argon2 memory cost (not recommended -- weakens password hashing)
|
||||
|
||||
The default Argon2 parameters use ~64 MB per hash operation. With 2 GB total RAM and a
|
||||
running server, this is tight but workable if nothing else is competing for memory.
|
||||
|
||||
**Web UI unreachable from LAN**
|
||||
|
||||
1. Check that `host` is set to `0.0.0.0` in config, not `127.0.0.1`
|
||||
2. Check firewall: `sudo ufw status` -- port 5000 must be allowed
|
||||
3. Check the service is running: `sudo systemctl status soosef`
|
||||
4. Check the Pi's IP: `ip addr show`
|
||||
|
||||
**Certificate warnings in browser**
|
||||
|
||||
Expected with self-signed certificates. Users must click through the warning. To avoid
|
||||
this, distribute `~/.soosef/certs/cert.pem` to client devices and install it as a
|
||||
trusted certificate.
|
||||
|
||||
**Dead man's switch fires unexpectedly**
|
||||
|
||||
The switch checks every 60 seconds. If the Pi loses power or the service crashes and
|
||||
does not restart within `interval_hours + grace_hours`, the switch will fire on the next
|
||||
start. Make sure the systemd service is set to `Restart=on-failure` and the Pi has
|
||||
reliable power.
|
||||
|
||||
If you need to perform maintenance, disarm the switch first:
|
||||
|
||||
```bash
|
||||
soosef fieldkit deadman disarm
|
||||
```
|
||||
|
||||
Re-arm when maintenance is complete.
|
||||
|
||||
**Permission errors on ~/.soosef/**
|
||||
|
||||
The `identity/`, `auth/`, and `certs/` directories are mode 0700. If running under a
|
||||
different user than the one who ran `soosef init`, you will get permission denied errors.
|
||||
Always run SooSeF as the same user.
|
||||
|
||||
```bash
|
||||
ls -la ~/.soosef/
|
||||
```
|
||||
Loading…
Reference in New Issue
Block a user