Commit Graph

5 Commits

Author SHA1 Message Date
Aaron D. Lee
490f9d4a1d Rebrand SooSeF to FieldWitness
Complete project rebrand for better positioning in the press freedom
and digital security space. FieldWitness communicates both field
deployment and evidence testimony — appropriate for the target audience
of journalists, NGOs, and human rights organizations.

Rename mapping:
- soosef → fieldwitness (package, CLI, all imports)
- soosef.stegasoo → fieldwitness.stego
- soosef.verisoo → fieldwitness.attest
- ~/.soosef/ → ~/.fwmetadata/ (innocuous data dir name)
- SOOSEF_DATA_DIR → FIELDWITNESS_DATA_DIR
- SoosefConfig → FieldWitnessConfig
- SoosefError → FieldWitnessError

Also includes:
- License switch from MIT to GPL-3.0
- C2PA bridge module (Phase 0-2 MVP): cert.py, export.py, vendor_assertions.py
- README repositioned to lead with provenance/federation, stego backgrounded
- Threat model skeleton at docs/security/threat-model.md
- Planning docs: docs/planning/c2pa-integration.md, docs/planning/gtm-feasibility.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:05:13 -04:00
Aaron D. Lee
2629aabcc5 Fix 12 security findings from adversarial audit
Some checks failed
CI / typecheck (push) Waiting to run
CI / lint (push) Has been cancelled
CRITICAL:
- #1+#2: Consistency proof verification no longer a stub — implements
  actual hash chain reconstruction from proof hashes, rejects proofs
  that don't reconstruct to the expected root. GossipNode._verify_consistency
  now calls verify_consistency_proof() instead of just checking sizes.
- #3: Remove passphrase.lower() from KDF — was silently discarding
  case entropy from mixed-case passphrases. Passphrases are now
  case-sensitive as users would expect.
- #4: Federation gossip now applies record_filter (trust store check)
  on every received record before appending to the log. Untrusted
  attestor fingerprints are rejected with a warning.
- #5: Killswitch disables all logging BEFORE activation to prevent
  audit log from recording killswitch activity that could survive an
  interrupted purge. Audit log destruction moved to position 4 (right
  after keys + flask secret, before other data).

HIGH:
- #6: CSRF exemption narrowed from entire dropbox blueprint to only
  the upload view function. Admin routes retain CSRF protection.
- #7: /health endpoint returns only {"status":"ok"} to anonymous
  callers. Full operational report requires authentication.
- #8: Metadata stripping now reconstructs image from pixel data only
  (Image.new + putdata), stripping XMP, IPTC, and ICC profiles — not
  just EXIF.
- #9: Same as #6 (CSRF scope fix).

MEDIUM:
- #11: Receipt HMAC key changed from public upload token to server-side
  secret key, making valid receipts unforgeable by the source or anyone
  who captured the upload URL.
- #12: Docker CMD no longer defaults to --no-https. HTTPS with
  self-signed cert is the default; --no-https requires explicit opt-in.
- #14: shred return code now checked — non-zero exit falls through to
  the zero-overwrite fallback instead of silently succeeding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:31:03 -04:00
Aaron D. Lee
f557cac45a Implement 6 evidence lifecycle features
Some checks failed
CI / lint (push) Failing after 56s
CI / typecheck (push) Failing after 29s
1. Client-side SHA-256 in drop box: browser computes and displays
   file fingerprints via SubtleCrypto before upload. Receipt codes
   are HMAC-derived from file hash so source can verify
   correspondence. Source sees hash before submitting.

2. Drop box token persistence: replaced in-memory dict with SQLite
   (dropbox.db). Tokens and receipts survive server restarts.
   Receipt verification now returns filename, SHA-256, and timestamp.

3. RFC 3161 trusted timestamps + manual anchors: new
   federation/anchors.py with get_chain_head_anchor(),
   submit_rfc3161(), save_anchor(), and manual export format.
   CLI: `soosef chain anchor [--tsa URL]`. A single anchor
   implicitly timestamps every preceding chain record.

4. Derived work lineage: attestation metadata supports
   derived_from (parent record ID) and derivation_type
   (crop, redact, brightness, etc.) for tracking edits
   through the chain of custody.

5. Self-contained evidence package: new soosef.evidence module
   with export_evidence_package() producing a ZIP with images,
   attestation records, chain data, public key, standalone
   verify.py script, and README.

6. Cold archive export: new soosef.archive module with
   export_cold_archive() bundling chain.bin, verisoo log,
   LMDB index, keys, anchors, trusted keys, ALGORITHMS.txt
   documenting all crypto, and verification instructions.
   Designed for OAIS (ISO 14721) alignment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 21:04:20 -04:00
Aaron D. Lee
171e51643c Add extract-then-strip EXIF pipeline for attestation intake
Some checks failed
CI / lint (push) Failing after 53s
CI / typecheck (push) Failing after 30s
Resolves the tension between steganography (strip everything to
protect sources) and attestation (preserve evidence of provenance):

- New soosef.metadata module with extract_and_classify() and
  extract_strip_pipeline() — classifies EXIF fields as evidentiary
  (GPS, timestamp — valuable for proving provenance) vs dangerous
  (device serial, firmware — could identify the source)
- Drop box now uses extract-then-strip: attests ORIGINAL bytes (hash
  matches what source submitted), extracts evidentiary EXIF into
  attestation metadata, strips dangerous fields, stores clean copy
- Attest route gains strip_device option: when enabled, includes
  GPS/timestamp in attestation but excludes device serial/firmware
- Stego encode unchanged: still strips all metadata from carriers
  (correct for steganography threat model)

The key insight: for stego, the carrier is a vessel (strip everything).
For attestation, EXIF is the evidence (extract, classify, preserve
selectively). Both hashes (original + stripped) are recorded so the
relationship between raw submission and stored copy is provable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:57:36 -04:00
Aaron D. Lee
9431033c72 Implement 7 real-world scenario features (Round 4)
Some checks failed
CI / lint (push) Failing after 52s
CI / typecheck (push) Failing after 30s
1. Source drop box: token-gated anonymous upload with auto-attestation,
   EXIF stripping, receipt codes, and self-destructing URLs. New
   /dropbox blueprint with admin panel for token management. CSRF
   exempted for source-facing upload routes.

2. Investigation namespaces: attestation records tagged with
   investigation label via metadata. Log view filters by investigation
   with dropdown. Supports long-running multi-story workflows.

3. Scale fixes: replaced O(n) full-scan perceptual hash search with
   LMDB find_similar_images() index lookup. Added incremental chain
   verification (verify_incremental) with last_verified_index
   checkpoint in ChainState.

4. Deep forensic purge: killswitch now scrubs __pycache__, pip
   dist-info, pip cache, and shell history entries containing 'soosef'.
   Runs before package uninstall for maximum trace removal.

5. Cross-org federation: new federation/exchange.py with
   export_attestation_bundle() and import_attestation_bundle().
   Bundles are self-authenticating JSON with investigation filter.
   Import validates against trust store fingerprints.

6. Wrong-key diagnostics: enhanced decrypt error messages include
   current channel key fingerprint hint. New carrier_tracker.py
   tracks carrier SHA-256 hashes and warns on reuse (statistical
   analysis risk).

7. Selective disclosure: ChainStore.selective_disclosure() produces
   proof bundles with full selected records + hash-only redacted
   records + complete hash chain for linkage verification. New
   `soosef chain disclose -i 0,5,10 -o proof.json` CLI command
   for court-ordered evidence production.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:41:41 -04:00