Consolidate stegasoo and verisoo into soosef monorepo

Merge stegasoo (v4.3.0, steganography) and verisoo (v0.1.0, attestation)
as subpackages under soosef.stegasoo and soosef.verisoo. This eliminates
cross-repo coordination and enables atomic changes across the full stack.

- Copy stegasoo (34 modules) and verisoo (15 modules) into src/soosef/
- Convert all verisoo absolute imports to relative imports
- Rewire ~50 import sites across soosef code (cli, web, keystore, tests)
- Replace stegasoo/verisoo pip deps with inlined code + pip extras
  (stego-dct, stego-audio, attest, web, api, cli, fieldkit, all, dev)
- Add _availability.py for runtime feature detection
- Add unified FastAPI mount point at soosef.api
- Copy and adapt tests from both repos (155 pass, 1 skip)
- Drop standalone CLI/web frontends; keep FastAPI as optional modules
- Both source repos tagged pre-monorepo-consolidation on GitHub

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee
2026-04-01 19:06:14 -04:00
parent c8dc9be011
commit e3bc1cce1f
91 changed files with 30573 additions and 62 deletions

View File

@@ -123,8 +123,8 @@ def create_app(config: SoosefConfig | None = None) -> Flask:
# Stegasoo capabilities
try:
from stegasoo import HAS_AUDIO_SUPPORT, get_channel_status, has_dct_support
from stegasoo.constants import (
from soosef.stegasoo import HAS_AUDIO_SUPPORT, get_channel_status, has_dct_support
from soosef.stegasoo.constants import (
DEFAULT_PASSPHRASE_WORDS,
MAX_FILE_PAYLOAD_SIZE,
MAX_MESSAGE_CHARS,
@@ -164,7 +164,7 @@ def create_app(config: SoosefConfig | None = None) -> Flask:
# Verisoo availability
try:
import verisoo # noqa: F401
import soosef.verisoo # noqa: F401
has_verisoo = True
except ImportError:
@@ -241,13 +241,13 @@ def _register_stegasoo_routes(app: Flask) -> None:
"""
import temp_storage
from auth import admin_required, login_required
from stegasoo import (
from soosef.stegasoo import (
export_rsa_key_pem,
generate_credentials,
get_channel_status,
load_rsa_key,
)
from stegasoo.constants import (
from soosef.stegasoo.constants import (
DEFAULT_PASSPHRASE_WORDS,
MAX_PIN_LENGTH,
MIN_PASSPHRASE_WORDS,
@@ -255,7 +255,7 @@ def _register_stegasoo_routes(app: Flask) -> None:
TEMP_FILE_EXPIRY,
VALID_RSA_SIZES,
)
from stegasoo.qr_utils import (
from soosef.stegasoo.qr_utils import (
can_fit_in_qr,
generate_qr_code,
)

View File

@@ -273,7 +273,7 @@ def verify_and_reset_admin_password(recovery_key: str, new_password: str) -> tup
Returns:
(success, message) tuple
"""
from stegasoo.recovery import verify_recovery_key
from soosef.stegasoo.recovery import verify_recovery_key
stored_hash = get_recovery_key_hash()
if not stored_hash:

View File

@@ -21,7 +21,7 @@ bp = Blueprint("attest", __name__)
def _get_storage():
"""Get verisoo LocalStorage pointed at soosef's attestation directory."""
from verisoo.storage import LocalStorage
from soosef.verisoo.storage import LocalStorage
from soosef.paths import ATTESTATIONS_DIR
@@ -30,7 +30,7 @@ def _get_storage():
def _get_private_key():
"""Load the Ed25519 private key from soosef identity directory."""
from verisoo.crypto import load_private_key
from soosef.verisoo.crypto import load_private_key
from soosef.paths import IDENTITY_PRIVATE_KEY
@@ -139,7 +139,7 @@ def attest():
auto_exif = request.form.get("auto_exif", "on") == "on"
# Create the attestation
from verisoo.attestation import create_attestation
from soosef.verisoo.attestation import create_attestation
attestation = create_attestation(
image_data=image_data,
@@ -167,7 +167,7 @@ def attest():
# Save our own identity so we can look it up during verification
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from verisoo.models import Identity
from soosef.verisoo.models import Identity
pub_key = private_key.public_key()
pub_bytes = pub_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
@@ -217,7 +217,7 @@ def _verify_image(image_data: bytes) -> dict:
matches — list of match dicts (record, match_type, distances, attestor_name)
record_count — total records searched
"""
from verisoo.hashing import compute_all_distances, hash_image, is_same_image
from soosef.verisoo.hashing import compute_all_distances, hash_image, is_same_image
query_hashes = hash_image(image_data)
storage = _get_storage()

View File

@@ -41,7 +41,7 @@ def register_stego_routes(app, **deps):
temp_storage = deps["temp_storage"]
_has_qrcode_read = deps.get("has_qrcode_read", False)
from stegasoo import (
from soosef.stegasoo import (
HAS_AUDIO_SUPPORT,
CapacityError,
DecryptionError,
@@ -60,13 +60,13 @@ def register_stego_routes(app, **deps):
validate_rsa_key,
validate_security_factors,
)
from stegasoo.channel import resolve_channel_key
from stegasoo.constants import (
from soosef.stegasoo.channel import resolve_channel_key
from soosef.stegasoo.constants import (
TEMP_FILE_EXPIRY,
THUMBNAIL_QUALITY,
THUMBNAIL_SIZE,
)
from stegasoo.qr_utils import (
from soosef.stegasoo.qr_utils import (
decompress_data,
extract_key_from_qr,
is_compressed,
@@ -686,7 +686,7 @@ def register_stego_routes(app, **deps):
return _error_response(result.error_message)
# Pre-check payload capacity BEFORE encode (fail fast)
from stegasoo.steganography import will_fit_by_mode
from soosef.stegasoo.steganography import will_fit_by_mode
payload_size = (
len(payload.data) if hasattr(payload, "data") else len(payload.encode("utf-8"))
@@ -1613,8 +1613,8 @@ def register_stego_routes(app, **deps):
@app.route("/about")
def about():
from auth import get_current_user
from stegasoo import has_argon2
from stegasoo.channel import get_channel_status
from soosef.stegasoo import has_argon2
from soosef.stegasoo.channel import get_channel_status
channel_status = get_channel_status()
current_user = get_current_user()
@@ -1644,7 +1644,7 @@ def register_stego_routes(app, **deps):
@login_required
def api_tools_capacity():
"""Calculate image capacity for steganography."""
from stegasoo.dct_steganography import estimate_capacity_comparison
from soosef.stegasoo.dct_steganography import estimate_capacity_comparison
carrier = request.files.get("image")
if not carrier:
@@ -1666,7 +1666,7 @@ def register_stego_routes(app, **deps):
"""Strip EXIF/metadata from image."""
import io
from stegasoo.utils import strip_image_metadata
from soosef.stegasoo.utils import strip_image_metadata
image_file = request.files.get("image")
if not image_file:
@@ -1689,7 +1689,7 @@ def register_stego_routes(app, **deps):
@login_required
def api_tools_exif():
"""Read EXIF metadata from image."""
from stegasoo.utils import read_image_exif
from soosef.stegasoo.utils import read_image_exif
image_file = request.files.get("image")
if not image_file:
@@ -1718,7 +1718,7 @@ def register_stego_routes(app, **deps):
@login_required
def api_tools_exif_update():
"""Update EXIF fields in image."""
from stegasoo.utils import write_image_exif
from soosef.stegasoo.utils import write_image_exif
image_file = request.files.get("image")
if not image_file:
@@ -1757,7 +1757,7 @@ def register_stego_routes(app, **deps):
@login_required
def api_tools_exif_clear():
"""Remove all EXIF metadata from image."""
from stegasoo.utils import strip_image_metadata
from soosef.stegasoo.utils import strip_image_metadata
image_file = request.files.get("image")
if not image_file:

View File

@@ -73,7 +73,7 @@ def _get_channel_info(resolved_key):
Returns:
(mode, fingerprint) tuple
"""
from stegasoo import get_channel_status, has_channel_key
from soosef.stegasoo import get_channel_status, has_channel_key
if resolved_key == "":
return "public", None
@@ -94,7 +94,7 @@ def _get_channel_info(resolved_key):
def encode_operation(params: dict) -> dict:
"""Handle encode operation."""
logger.debug("encode_operation: mode=%s", params.get("embed_mode", "lsb"))
from stegasoo import FilePayload, encode
from soosef.stegasoo import FilePayload, encode
# Decode base64 inputs
carrier_data = base64.b64decode(params["carrier_b64"])
@@ -173,7 +173,7 @@ def _write_decode_progress(progress_file: str | None, percent: int, phase: str)
def decode_operation(params: dict) -> dict:
"""Handle decode operation."""
logger.debug("decode_operation: mode=%s", params.get("embed_mode", "auto"))
from stegasoo import decode
from soosef.stegasoo import decode
progress_file = params.get("progress_file")
@@ -227,7 +227,7 @@ def decode_operation(params: dict) -> dict:
def compare_operation(params: dict) -> dict:
"""Handle compare_modes operation."""
from stegasoo import compare_modes
from soosef.stegasoo import compare_modes
carrier_data = base64.b64decode(params["carrier_b64"])
result = compare_modes(carrier_data)
@@ -240,7 +240,7 @@ def compare_operation(params: dict) -> dict:
def capacity_check_operation(params: dict) -> dict:
"""Handle will_fit_by_mode operation."""
from stegasoo import will_fit_by_mode
from soosef.stegasoo import will_fit_by_mode
carrier_data = base64.b64decode(params["carrier_b64"])
@@ -259,7 +259,7 @@ def capacity_check_operation(params: dict) -> dict:
def encode_audio_operation(params: dict) -> dict:
"""Handle audio encode operation (v4.3.0)."""
logger.debug("encode_audio_operation: mode=%s", params.get("embed_mode", "audio_lsb"))
from stegasoo import FilePayload, encode_audio
from soosef.stegasoo import FilePayload, encode_audio
carrier_data = base64.b64decode(params["carrier_b64"])
reference_data = base64.b64decode(params["reference_b64"])
@@ -324,7 +324,7 @@ def encode_audio_operation(params: dict) -> dict:
def decode_audio_operation(params: dict) -> dict:
"""Handle audio decode operation (v4.3.0)."""
logger.debug("decode_audio_operation: mode=%s", params.get("embed_mode", "audio_auto"))
from stegasoo import decode_audio
from soosef.stegasoo import decode_audio
progress_file = params.get("progress_file")
_write_decode_progress(progress_file, 5, "reading")
@@ -370,9 +370,9 @@ def decode_audio_operation(params: dict) -> dict:
def audio_info_operation(params: dict) -> dict:
"""Handle audio info operation (v4.3.0)."""
from stegasoo import get_audio_info
from stegasoo.audio_steganography import calculate_audio_lsb_capacity
from stegasoo.spread_steganography import calculate_audio_spread_capacity
from soosef.stegasoo import get_audio_info
from soosef.stegasoo.audio_steganography import calculate_audio_lsb_capacity
from soosef.stegasoo.spread_steganography import calculate_audio_spread_capacity
audio_data = base64.b64decode(params["audio_b64"])
@@ -397,7 +397,7 @@ def audio_info_operation(params: dict) -> dict:
def channel_status_operation(params: dict) -> dict:
"""Handle channel status check (v4.0.0)."""
from stegasoo import get_channel_status
from soosef.stegasoo import get_channel_status
status = get_channel_status()
reveal = params.get("reveal", False)