clio/clio-android/description.md
Your Name 56d8fb4d56
Some checks failed
Deploy API / deploy (push) Failing after 1s
adding a bunch of untested files
2026-05-19 20:12:49 -04:00

4.3 KiB

Phone Recorder - Architecture Overview

Purpose

Android app that records audio continuously, encrypts recordings immediately (never stored unencrypted), and syncs them to a server over LAN or internet.

Security Model

Phone (has: server public key)     Server (has: private key)
─────────────────────────────      ────────────────────────
Record audio → temp.ogg
Encrypt with public key →
  recording_*.ogg.enc
        │
        └──── HTTP POST ────────→  Receive encrypted file
                                   Decrypt with private key
                                   Store as .ogg in recordings/
  • Sealed box encryption: X25519 key exchange + XSalsa20-Poly1305
  • Forward secrecy: Each encryption uses ephemeral keys
  • Phone never stores unencrypted: Temp file deleted immediately after encryption
  • If no public key configured: Recordings are deleted (security-first design)

File Format (SREC)

Encrypted files use a chunked format for streaming large files:

[4 bytes: "SREC" magic]
[1 byte: version (1)]
[4 bytes: chunk count, big-endian]
For each chunk (64KB max):
  [4 bytes: encrypted length, big-endian]
  [N bytes: sealed box ciphertext]

Android App Structure

Main Files

File Purpose
MainActivity.kt UI, settings, sync controls
RecordingService.kt Foreground service for recording, encryption on stop
StorageHelper.kt File paths, temp vs recordings directories

Crypto Package (crypto/)

File Purpose
CryptoHelper.kt SREC format encryption using lazysodium
KeyManager.kt Store/retrieve server public key (SharedPreferences)

Sync Package (sync/)

File Purpose
SyncSettings.kt Sync mode enum, server URLs, LAN subnet prefix
NetworkHelper.kt Detect WiFi, LAN (by IP prefix), network availability
SyncTracker.kt Track which files synced successfully (SharedPreferences)
SyncWorker.kt WorkManager background job for uploads
SyncManager.kt Schedule periodic (15min) and immediate syncs

API Package (api/)

File Purpose
RecordingsApi.kt OkHttp client, upload with SHA-256 verification

Sync Modes

Mode Behavior
Never No sync, files stay on phone
LAN Only Sync only when IP matches configured subnet (e.g., 10.0.0.)
WiFi Only Sync on any WiFi network
Any Network Sync on WiFi or mobile data

Server Structure (Python/FastAPI)

File Purpose
main.py FastAPI endpoints
crypto.py PyNaCl decryption, keypair management
config.py Paths, ports

Endpoints

Endpoint Method Description
/health GET Returns {"status": "ok"}
/api/v1/public-key GET Returns Base64 public key
/api/v1/recordings/upload POST Upload encrypted file, returns hash for verification
/api/v1/recordings GET List decrypted recordings

Data Flow

  1. Recording starts: RecordingService writes to temp/recording_TIMESTAMP.ogg
  2. Recording stops:
    • CryptoHelper.encryptFile() reads temp, writes recordings/recording_TIMESTAMP.ogg.enc
    • Temp file deleted
    • SyncManager.scheduleImmediateSync() triggered
  3. Sync runs:
    • SyncWorker checks network conditions match SyncMode
    • Computes SHA-256 of encrypted file
    • Uploads to server
    • Server decrypts, returns hash
    • If hashes match, marks file as synced
  4. Server storage: recordings/YYYY/MM/DD/recording_TIMESTAMP.ogg

Key Dependencies

Android

  • lazysodium-android - libsodium bindings
  • androidx.work - Background job scheduling
  • okhttp3 - HTTP client

Server

  • fastapi + uvicorn - Web framework
  • pynacl - libsodium bindings
  • aiofiles - Async file I/O

Configuration

Android (in-app settings)

  • Sync mode (Never/LAN/WiFi/Any)
  • LAN subnet prefix (default: 10.0.0.)
  • Server URLs (LAN and remote)
  • Server public key (Base64)

Server (config.py or env vars)

  • HOST - Bind address (default: 0.0.0.0)
  • PORT - Listen port (default: 8000)
  • BASE_DIR - Base directory for keys and recordings