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>
This commit is contained in:
Aaron D. Lee
2026-04-02 15:05:13 -04:00
parent 6325e86873
commit 490f9d4a1d
188 changed files with 4588 additions and 2017 deletions

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Account - Stegasoo{% endblock %}
{% block title %}Account - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">
@@ -269,16 +269,16 @@
{% block scripts %}
<script src="{{ url_for('static', filename='js/auth.js') }}"></script>
<script src="{{ url_for('static', filename='js/soosef.js') }}"></script>
<script src="{{ url_for('static', filename='js/fieldwitness.js') }}"></script>
{% if is_admin %}
<script src="{{ url_for('static', filename='js/qrcode.min.js') }}"></script>
{% endif %}
<script>
StegasooAuth.initPasswordConfirmation('accountForm', 'newPasswordInput', 'newPasswordConfirmInput');
StegoAuth.initPasswordConfirmation('accountForm', 'newPasswordInput', 'newPasswordConfirmInput');
// Webcam QR scanning for channel key input (v4.1.5)
document.getElementById('scanChannelKeyBtn')?.addEventListener('click', function() {
Stegasoo.showQrScanner((text) => {
Stego.showQrScanner((text) => {
const input = document.getElementById('channelKeyInput');
if (input) {
// Clean and format the key
@@ -294,7 +294,7 @@ document.getElementById('scanChannelKeyBtn')?.addEventListener('click', function
// Format channel key input as user types
document.getElementById('channelKeyInput')?.addEventListener('input', function() {
Stegasoo.formatChannelKeyInput(this);
Stego.formatChannelKeyInput(this);
});
function renameKey(keyId, currentName) {
@@ -336,7 +336,7 @@ document.getElementById('qrDownload')?.addEventListener('click', function() {
const keyName = document.getElementById('qrKeyName').textContent;
if (canvas) {
const link = document.createElement('a');
link.download = 'stegasoo-channel-key-' + keyName.toLowerCase().replace(/\s+/g, '-') + '.png';
link.download = 'stego-channel-key-' + keyName.toLowerCase().replace(/\s+/g, '-') + '.png';
link.href = canvas.toDataURL('image/png');
link.click();
}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Password Reset - Stegasoo{% endblock %}
{% block title %}Password Reset - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -1,9 +1,9 @@
{% extends "base.html" %}
{% block title %}Settings — SooSeF Admin{% endblock %}
{% block title %}Settings — FieldWitness Admin{% endblock %}
{% block content %}
<h2><i class="bi bi-sliders me-2"></i>System Settings</h2>
<div class="alert alert-info">
<i class="bi bi-info-circle me-2"></i>
System settings will be migrated from stegasoo's admin panel.
System settings will be migrated from fieldwitness.stego's admin panel.
</div>
{% endblock %}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}User Created - Stegasoo{% endblock %}
{% block title %}User Created - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Add User - Stegasoo{% endblock %}
{% block title %}Add User - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Manage Users - Stegasoo{% endblock %}
{% block title %}Manage Users - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Attest Image — SooSeF{% endblock %}
{% block title %}Attest Image — FieldWitness{% endblock %}
{% block content %}
<div class="row justify-content-center">
@@ -18,7 +18,7 @@
<div class="alert alert-warning">
<i class="bi bi-exclamation-triangle me-2"></i>
<strong>No identity configured.</strong> Generate one from the
<a href="/keys" class="alert-link">Keys page</a> or run <code>soosef init</code>.
<a href="/keys" class="alert-link">Keys page</a> or run <code>fieldwitness init</code>.
</div>
{% endif %}

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Attestation Log — SooSeF{% endblock %}
{% block title %}Attestation Log — FieldWitness{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Attestation Record — SooSeF{% endblock %}
{% block title %}Attestation Record — FieldWitness{% endblock %}
{% block content %}
<h2><i class="bi bi-file-earmark-check me-2"></i>Attestation Record</h2>
<p class="text-muted">Record ID: <code>{{ record_id }}</code></p>

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Attestation Created — SooSeF{% endblock %}
{% block title %}Attestation Created — FieldWitness{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Verify Image — SooSeF{% endblock %}
{% block title %}Verify Image — FieldWitness{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Verification Result — SooSeF{% endblock %}
{% block title %}Verification Result — FieldWitness{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}SooSeF{% endblock %}</title>
<title>{% block title %}FieldWitness{% endblock %}</title>
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}">
<link href="{{ url_for('static', filename='vendor/css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='vendor/css/bootstrap-icons.min.css') }}" rel="stylesheet">
@@ -13,7 +13,7 @@
<nav class="navbar navbar-expand-lg navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/" style="padding-left: 6px; margin-right: 8px;">
<strong>SooSeF</strong>
<strong>FieldWitness</strong>
</a>
{# Channel + Identity indicators #}
@@ -40,7 +40,7 @@
</li>
{% if not auth_enabled or is_authenticated %}
{# ── Stegasoo ── #}
{# ── Stego ── #}
<li class="nav-item">
<a class="nav-link nav-expand" href="/encode"><i class="bi bi-lock"></i><span>Encode</span></a>
</li>
@@ -51,8 +51,8 @@
<a class="nav-link nav-expand" href="/generate"><i class="bi bi-key"></i><span>Generate</span></a>
</li>
{# ── Verisoo ── #}
{% if has_verisoo %}
{# ── Attest ── #}
{% if has_attest %}
<li class="nav-item">
<a class="nav-link nav-expand" href="/attest"><i class="bi bi-patch-check"></i><span>Attest</span></a>
</li>
@@ -140,9 +140,9 @@
<footer class="py-4 mt-5">
<div class="container text-center text-muted">
<small>
SooSeF v{{ version }} — Soo Security Fieldkit
FieldWitness v{{ version }} — FieldWitness
<span class="mx-2">|</span>
<span class="text-muted">Stegasoo + Verisoo</span>
<span class="text-muted">Stego + Attest</span>
</small>
</div>
</footer>

View File

@@ -1,8 +1,8 @@
{% extends "base.html" %}
{% block title %}Source Drop Box — SooSeF{% endblock %}
{% block title %}Source Drop Box — FieldWitness{% endblock %}
{% block content %}
<h2><i class="bi bi-inbox me-2"></i>Source Drop Box</h2>
<p class="text-muted">Create time-limited upload links for sources who cannot install SooSeF.</p>
<p class="text-muted">Create time-limited upload links for sources who cannot install FieldWitness.</p>
<div class="card bg-dark mb-4">
<div class="card-body">

View File

@@ -1,8 +1,8 @@
{% extends "base.html" %}
{% block title %}Federation — SooSeF{% endblock %}
{% block title %}Federation — FieldWitness{% endblock %}
{% block content %}
<h2><i class="bi bi-diagram-3 me-2"></i>Federation</h2>
<p class="text-muted">Gossip-based attestation sync between SooSeF instances.</p>
<p class="text-muted">Gossip-based attestation sync between FieldWitness instances.</p>
<div class="row mb-4">
<div class="col-md-4">

View File

@@ -1,8 +1,8 @@
{% extends "base.html" %}
{% block title %}Keys — SooSeF{% endblock %}
{% block title %}Keys — FieldWitness{% endblock %}
{% block content %}
<h2><i class="bi bi-key me-2"></i>Key Management</h2>
<p class="text-muted">Manage Stegasoo channel keys and Verisoo Ed25519 identity.</p>
<p class="text-muted">Manage Stego channel keys and Attest Ed25519 identity.</p>
<div class="row g-4">
{# Channel Key #}
@@ -13,7 +13,7 @@
{% if keystore.has_channel_key %}
<p class="text-muted small">
Fingerprint: <code>{{ keystore.channel_fingerprint }}</code><br>
Used for Stegasoo deployment isolation.
Used for Stego deployment isolation.
</p>
{% else %}
<p class="text-muted small">No channel key configured.</p>
@@ -36,7 +36,7 @@
{% if keystore.has_identity %}
<p class="text-muted small">
Fingerprint: <code>{{ keystore.identity_fingerprint }}</code><br>
Used for Verisoo attestation signing.
Used for Attest attestation signing.
</p>
{% else %}
<p class="text-muted small">No identity configured.</p>

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Killswitch — SooSeF{% endblock %}
{% block title %}Killswitch — FieldWitness{% endblock %}
{% block content %}
<h2 class="text-danger"><i class="bi bi-exclamation-octagon me-2"></i>Emergency Killswitch</h2>
<p class="text-muted">Destroy all key material and sensitive data. This action is irreversible.</p>
@@ -9,7 +9,7 @@
<h5 class="card-title text-danger">Destruction Order</h5>
<ol class="text-muted small">
<li>Ed25519 identity keys (signing identity)</li>
<li>Stegasoo channel key (deployment binding)</li>
<li>Stego channel key (deployment binding)</li>
<li>Flask session secret (invalidates all sessions)</li>
<li>Auth database (user accounts)</li>
<li>Attestation log + index (provenance records)</li>

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Fieldkit Status — SooSeF{% endblock %}
{% block title %}Fieldkit Status — FieldWitness{% endblock %}
{% block content %}
<h2><i class="bi bi-speedometer2 me-2"></i>Fieldkit Status</h2>
<p class="text-muted">Security monitors and system health.</p>

View File

@@ -1,19 +1,19 @@
{% extends "base.html" %}
{% block title %}SooSeF — Soo Security Fieldkit{% endblock %}
{% block title %}FieldWitness — FieldWitness{% endblock %}
{% block content %}
<div class="text-center mb-5">
<h1 class="display-5 fw-bold">Soo Security Fieldkit</h1>
<h1 class="display-5 fw-bold">FieldWitness</h1>
<p class="lead text-muted">Offline-first security toolkit for field operations</p>
</div>
<div class="row g-4">
{# ── Stegasoo Card ── #}
{# ── Stego Card ── #}
<div class="col-md-6 col-lg-4">
<div class="card h-100 bg-dark border-secondary">
<div class="card-body">
<h5 class="card-title"><i class="bi bi-lock me-2 text-primary"></i>Encode</h5>
<p class="card-text text-muted">Hide encrypted messages in images or audio using Stegasoo's hybrid authentication.</p>
<p class="card-text text-muted">Hide encrypted messages in images or audio using Stego's hybrid authentication.</p>
<a href="/encode" class="btn btn-outline-primary btn-sm">Encode Message</a>
</div>
</div>
@@ -37,8 +37,8 @@
</div>
</div>
{# ── Verisoo Cards ── #}
{% if has_verisoo %}
{# ── Attest Cards ── #}
{% if has_attest %}
<div class="col-md-6 col-lg-4">
<div class="card h-100 bg-dark border-secondary">
<div class="card-body">
@@ -102,10 +102,10 @@
<i class="bi bi-image me-1"></i>DCT: {{ 'Available' if has_dct else 'Unavailable' }}
</span>
</div>
{% if has_verisoo %}
{% if has_attest %}
<div class="col-auto">
<span class="badge bg-success">
<i class="bi bi-patch-check me-1"></i>Verisoo: Active
<i class="bi bi-patch-check me-1"></i>Attest: Active
</span>
</div>
{% endif %}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Login - Stegasoo{% endblock %}
{% block title %}Login - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Password Recovery - Stegasoo{% endblock %}
{% block title %}Password Recovery - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">
@@ -116,7 +116,7 @@
<div class="alert alert-warning mt-4 small">
<i class="bi bi-exclamation-triangle me-2"></i>
<strong>Note:</strong> This will reset the admin password. If you don't have a valid recovery key,
you'll need to delete the database and reconfigure Stegasoo.
you'll need to delete the database and reconfigure Stego.
</div>
</div>
</div>
@@ -125,6 +125,6 @@
{% block scripts %}
<script src="{{ url_for('static', filename='js/auth.js') }}"></script>
<script>
StegasooAuth.initPasswordConfirmation('recoverForm', 'passwordInput', 'passwordConfirmInput');
StegoAuth.initPasswordConfirmation('recoverForm', 'passwordInput', 'passwordConfirmInput');
</script>
{% endblock %}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Regenerate Recovery Key - Stegasoo{% endblock %}
{% block title %}Regenerate Recovery Key - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">
@@ -142,7 +142,7 @@ function copyToClipboard() {
// Download as text file
function downloadTextFile() {
const key = document.getElementById('recoveryKey').value;
const content = `Stegasoo Recovery Key
const content = `Stego Recovery Key
=====================
${key}
@@ -158,7 +158,7 @@ Generated: ${new Date().toISOString()}
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'stegasoo-recovery-key.txt';
a.download = 'stego-recovery-key.txt';
a.click();
URL.revokeObjectURL(url);
}
@@ -170,7 +170,7 @@ function downloadQRImage() {
const a = document.createElement('a');
a.href = img.src;
a.download = 'stegasoo-recovery-qr.png';
a.download = 'stego-recovery-qr.png';
a.click();
}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Setup - Stegasoo{% endblock %}
{% block title %}Setup - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">
@@ -12,7 +12,7 @@
</div>
<div class="card-body">
<p class="text-muted text-center mb-4">
Welcome to Stegasoo! Create your admin account to get started.
Welcome to Stego! Create your admin account to get started.
</p>
<form method="POST" action="{{ url_for('setup') }}" id="setupForm">
@@ -72,6 +72,6 @@
{% block scripts %}
<script src="{{ url_for('static', filename='js/auth.js') }}"></script>
<script>
StegasooAuth.initPasswordConfirmation('setupForm', 'passwordInput', 'passwordConfirmInput');
StegoAuth.initPasswordConfirmation('setupForm', 'passwordInput', 'passwordConfirmInput');
</script>
{% endblock %}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Recovery Key Setup - Stegasoo{% endblock %}
{% block title %}Recovery Key Setup - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">
@@ -135,7 +135,7 @@ function copyToClipboard() {
// Download as text file
function downloadTextFile() {
const key = document.getElementById('recoveryKey').value;
const content = `Stegasoo Recovery Key
const content = `Stego Recovery Key
=====================
${key}
@@ -151,7 +151,7 @@ Generated: ${new Date().toISOString()}
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'stegasoo-recovery-key.txt';
a.download = 'stego-recovery-key.txt';
a.click();
URL.revokeObjectURL(url);
}
@@ -163,7 +163,7 @@ function downloadQRImage() {
const a = document.createElement('a');
a.href = img.src;
a.download = 'stegasoo-recovery-qr.png';
a.download = 'stego-recovery-qr.png';
a.click();
}

View File

@@ -1,17 +1,17 @@
{% extends "base.html" %}
{% block title %}About - Stegasoo{% endblock %}
{% block title %}About - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-lg-10">
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0"><i class="bi bi-info-circle me-2"></i>About Stegasoo</h5>
<h5 class="mb-0"><i class="bi bi-info-circle me-2"></i>About Stego</h5>
</div>
<div class="card-body">
<p class="lead">
Stegasoo hides encrypted messages and files inside images using multi-factor authentication.
Stego hides encrypted messages and files inside images using multi-factor authentication.
</p>
<h6 class="text-primary mt-4 mb-3">Features</h6>

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Decode Message - Stegasoo{% endblock %}
{% block title %}Decode Message - Stego{% endblock %}
{% block content %}
<style>
@@ -487,7 +487,7 @@
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='js/soosef.js') }}"></script>
<script src="{{ url_for('static', filename='js/fieldwitness.js') }}"></script>
<script>
// ============================================================================
// MODE HINT - Dynamic text based on selected extraction mode
@@ -677,6 +677,6 @@ if (document.getElementById('modeDct')?.disabled) {
// LOADING STATE
// ============================================================================
Stegasoo.initFormLoading('decodeForm', 'decodeBtn', 'Decoding...');
Stego.initFormLoading('decodeForm', 'decodeBtn', 'Decoding...');
</script>
{% endblock %}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Encode Message - Stegasoo{% endblock %}
{% block title %}Encode Message - Stego{% endblock %}
{% block content %}
<style>
@@ -507,7 +507,7 @@
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='js/soosef.js') }}"></script>
<script src="{{ url_for('static', filename='js/fieldwitness.js') }}"></script>
<script>
// ============================================================================
// MODE HINT - Dynamic text based on selected embedding mode

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Encode Success - Stegasoo{% endblock %}
{% block title %}Encode Success - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">
@@ -218,7 +218,7 @@ if (navigator.share && navigator.canShare) {
try {
await navigator.share({
files: [file],
title: 'Stegasoo Image',
title: 'Stego Image',
});
} catch (err) {
if (err.name !== 'AbortError') {

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Generate Credentials - Stegasoo{% endblock %}
{% block title %}Generate Credentials - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center" data-page="generate">
@@ -500,7 +500,7 @@
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='js/soosef.js') }}"></script>
<script src="{{ url_for('static', filename='js/fieldwitness.js') }}"></script>
<script src="{{ url_for('static', filename='js/generate.js') }}"></script>
{% if generated %}
<script>
@@ -508,7 +508,7 @@
const passphraseWords = '{{ passphrase|default("", true) }}'.split(' ').filter(w => w.length > 0);
function copyPin() {
Stegasoo.copyToClipboard(
Stego.copyToClipboard(
'{{ pin|default("", true) }}',
document.getElementById('pinCopyIcon'),
document.getElementById('pinCopyText')
@@ -516,7 +516,7 @@ function copyPin() {
}
function copyPassphrase() {
Stegasoo.copyToClipboard(
Stego.copyToClipboard(
'{{ passphrase|default("", true) }}',
document.getElementById('passphraseCopyIcon'),
document.getElementById('passphraseCopyText')
@@ -524,11 +524,11 @@ function copyPassphrase() {
}
function toggleMemoryAid() {
StegasooGenerate.toggleMemoryAid(passphraseWords);
StegoGenerate.toggleMemoryAid(passphraseWords);
}
function regenerateStory() {
StegasooGenerate.regenerateStory(passphraseWords);
StegoGenerate.regenerateStory(passphraseWords);
}
</script>
{% endif %}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Tools - Stegasoo{% endblock %}
{% block title %}Tools - Stego{% endblock %}
{% block content %}
<div class="row justify-content-center">