fieldwitness/frontends/web/blueprints/federation.py
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

79 lines
2.2 KiB
Python

"""
Federation blueprint — peer status dashboard and management.
"""
from auth import admin_required, login_required
from flask import Blueprint, flash, redirect, render_template, request, url_for
bp = Blueprint("federation", __name__, url_prefix="/federation")
@bp.route("/")
@login_required
def status():
"""Federation status dashboard."""
from fieldwitness.attest.peer_store import PeerStore
store = PeerStore()
peers = store.list_peers()
history = store.get_sync_history(limit=20)
# Get local node info
node_info = {"root": None, "size": 0}
try:
from fieldwitness.attest.storage import LocalStorage
import fieldwitness.paths as _paths
storage = LocalStorage(_paths.ATTESTATIONS_DIR)
stats = storage.get_stats()
merkle_log = storage.load_merkle_log()
node_info = {
"root": merkle_log.root_hash[:16] + "..." if merkle_log.root_hash else "empty",
"size": merkle_log.size,
"record_count": stats.record_count,
}
except Exception:
pass
return render_template(
"federation/status.html",
peers=peers,
history=history,
node_info=node_info,
)
@bp.route("/peer/add", methods=["POST"])
@admin_required
def peer_add():
"""Add a federation peer."""
from fieldwitness.attest.peer_store import PeerStore
url = request.form.get("url", "").strip()
fingerprint = request.form.get("fingerprint", "").strip()
if not url or not fingerprint:
flash("URL and fingerprint are required.", "error")
return redirect(url_for("federation.status"))
store = PeerStore()
store.add_peer(url, fingerprint)
flash(f"Peer added: {url}", "success")
return redirect(url_for("federation.status"))
@bp.route("/peer/remove", methods=["POST"])
@admin_required
def peer_remove():
"""Remove a federation peer."""
from fieldwitness.attest.peer_store import PeerStore
url = request.form.get("url", "").strip()
store = PeerStore()
if store.remove_peer(url):
flash(f"Peer removed: {url}", "success")
else:
flash(f"Peer not found: {url}", "error")
return redirect(url_for("federation.status"))