Menu ▾ ▴

Architecture

RedoSan

Architecture

This document describes the internal architecture of RedoSan Authenticity, covering the dual-interface design, the CLI's polyfill layer, the data pipeline, MPA navigation, and how browser and Node.js environments share code.


High-Level Design

┌─────────────────────────────────────────────────────────────────────┐
│                        User Interfaces                             │
│  ┌──────────────┐  ┌────────────────┐  ┌────────────────────────┐  │
│  │ CLI (Node.js) │  │ Simplified     │  │ Professional Mode      │  │
│  │ Commander.js  │  │ Mode (Browser) │  │ (Browser SPA + MPA)   │  │
│  │ 14 commands   │  │ 10-step wizard │  │ 23 standalone pages   │  │
│  └──────┬───────┘  └───────┬────────┘  └───────┬───────────────┘  │
└─────────┼──────────────────┼──────────────────┼──────────────────┘
          │                  │                  │
┌─────────▼──────────────────▼──────────────────▼──────────────────┐
│                      Shared Algorithm Layer                       │
│  ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐  │
│  │ Watermark│ │ Audio WM │ │ Document│ │ Fingerpr│ │ Forensic│  │
│  │ Core (9) │ │ (8 algo) │ │ WM (5)  │ │ (21 alg)│ │ Analyzer│  │
│  └──────────┘ └──────────┘ └─────────┘ └─────────┘ └─────────┘  │
│  ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐  │
│  │ Pixel    │ │ C2PA     │ │ Metadata│ │ Timestmp│ │ DID     │  │
│  │ Inject   │ │ Sign/Read│ │ EXIF    │ │ OTS     │ │ Identity│  │
│  │ (23 alg) │ │          │ │         │ │         │ │         │  │
│  └──────────┘ └──────────┘ └─────────┘ └─────────┘ └─────────┘  │
│  ┌──────────┐ ┌──────────┐ ┌─────────┐                           │
│  │Certificat│ │ Converter│ │ ID Forge│                           │
│  │ PDF/DOCX │ │FFmpeg.wasm│ │ ID Gen  │                           │
│  └──────────┘ └──────────┘ └─────────┘                           │
│  ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌───────────┐             │
│  │Face Bio  │ │ Iris Bio │ │Voice Bio│ │ Removal   │             │
│  │WebAuthn  │ │ Quality  │ │VAD/ECAPA│ │ Tools     │             │
│  └──────────┘ └──────────┘ └─────────┘ └───────────┘             │
└──────────────────────────────────────────────────────────────────┘
          │
┌─────────▼────────────────────────────────────────────────────────┐
│                Polyfill Layer (CLI only)                         │
│  crypto.subtle │ document.createElement('canvas') │              │
│  ImageData     │ globalThis.window │ Buffer I/O                  │
└──────────────────────────────────────────────────────────────────┘

The Polyfill Architecture (CLI)

The CLI runs browser-original JavaScript files using vm.runInContext(). This is necessary because the browser code uses top-level function and var declarations that are module-scoped in Node.js — require() would fail.

The polyfills are defined in cli/utils.js and injected into the V8 context before each module is loaded:

Polyfills Provided

Browser API Node.js Implementation
crypto.subtle.digest() crypto.createHash() for SHA family; custom implementations for WHIRLPOOL, etc.
crypto.subtle.importKey() No-op stub (not used in CLI context)
crypto.subtle.deriveBits() crypto.pbkdf2Sync() with 100,000 iterations
document.createElement('canvas') new canvas.Canvas() from the canvas npm package
HTMLCanvasElement.getContext('2d') canvas.CanvasRenderingContext2D
CanvasRenderingContext2D.getImageData() Returns { data: Buffer, width, height }
CanvasRenderingContext2D.putImageData() Writes pixel data back to canvas
globalThis.ImageData Constructor that accepts (data, width, height)
globalThis.window Empty object (for window.location checks that always pass in CLI)
globalThis.atob / globalThis.btoa Standard Node.js Buffer encoding
globalThis.crypto.getRandomValues() crypto.randomFillSync()
globalThis.TextEncoder / TextDecoder Standard Node.js implementation

Why vm.runInContext() Instead of require()?

The browser JavaScript files are written with browser conventions:

// Browser file structure (top-level declarations)
function embedWatermark(ctx, message, password) { ... }
function extractWatermark(ctx, password) { ... }

In Node.js, require() wraps the module in a function scope, so these top-level declarations would be private. vm.runInContext() executes the code in the global scope of a new V8 context, making all declarations available to subsequent modules.

Module Loading Order

cli/utils.js ──→ Polyfills ──→ Shared V8 Context
                ↓
     ┌─────────────────────┐
     │ Browser JS File 1   │ ← vm.runInContext(src, context)
     │                     │
     │ var fingerprint;     │
     │ function pHash() {} │
     │ ...                  │
     └─────────────────────┘
                ↓
     ┌─────────────────────┐
     │ Browser JS File 2   │ ← can call fingerprint, pHash, etc.
     │                     │
     │ ...                  │
     └─────────────────────┘

Because the CLI loads browser files in a shared context, all functions and variables from earlier files are available to later files, exactly as they would be in the browser.


Data Pipeline (Simplified Mode)

The simplified mode orchestrates a 10-step pipeline. Each step produces data that is consumed by subsequent steps:

Step 1: Upload
  Output: File object, ArrayBuffer, Object URL
  Stored: window._simpleFile, window._simpleArrayBuffer,
          window._simpleObjectUrl

Step 2: AI Question
  Output: Question string, Answer string
  Stored: window._simpleAIQuestion, window._simpleAIAnswer

Step 3: User Info
  Output: { name, phone, email, website, social, music }
  Stored: window._simpleUserInfo

Step 4: Fingerprint
  Input: ArrayBuffer → hashing.js
  Output: { md5, sha1, sha256, ..., phash, ahash, dhask, whash }
  Stored: window._simpleFingerprint
  Visual: Progress bar, results table

Step 5: Timestamp
  Input: ArrayBuffer → timestamp.js
  Output: OTS file (Uint8Array), timestamp hash
  Stored: window._simpleOtsData, window._simpleOtsHash
  Visual: Progress bar "Creating timestamp..."

Step 6: Watermark
  Input: canvas, message (includes timestamp hash), password
  Algorithm: watermark_core.js (auto-selected)
  Output: watermarked canvas/blob
  Stored: window._simpleWmBlobUrl
  Visual: Progress bar "Embedding watermark..."

Step 7: Pixel Injection
  Input: watermarked canvas, OTS data, password
  Algorithm: pixel_injection.js (enhanced_lsb)
  Output: pixel-injected canvas/blob
  Stored: window._simplePiBlobUrl
  Visual: Progress bar "Injecting pixel data..."

Step 8: C2PA Signing (LAST pixel operation)
  Input: pixel-injected blob, user info, social links
  Process: c2pa.js → adds C2PA manifest to JPEG APP11 or PNG c2pa chunk
  Output: C2PA-signed blob
  Stored: window._c2paSignedUrl
  Visual: Progress bar "Signing with C2PA..."

Step 9: Digital Passport
  Input: All stored data, final signed blob
  Output: PDF certificate with QR code
  Visual: Progress bar "Generating certificate..."

Step 10: Done
  Input: final signed blob, all stored data
  Output: Download button, Digital Passport PDF
  Visual: Lightbox preview, clear button

Critical constraint: C2PA signing must be the last pixel operation because canvas's toBlob() and toDataURL() strip C2PA chunks from the image data. Any pixel-level operation after C2PA signing would lose the Content Credentials.


State Management

The browser uses a global state object pattern (properties on window) rather than a framework like React or Vue:

Property Type Purpose
window._simpleFile File Uploaded file reference
window._simpleArrayBuffer ArrayBuffer Raw file data for hashing
window._simpleObjectUrl string Object URL for image preview
window._simpleAIQuestion string AI question text
window._simpleAIAnswer string AI answer text
window._simpleUserInfo object { name, phone, email, website, social, music }
window._simpleFingerprint object All hash results
window._simpleOtsData Uint8Array OTS file bytes
window._simpleOtsHash string Timestamp hash hex
window._simpleWmBlobUrl string Watermarked image URL
window._simplePiBlobUrl string Pixel-injected image URL
window._c2paSignedUrl string Final C2PA-signed image URL
window._wmLastBlobUrl string Watermark blob URL tracker (for cleanup)

Each professional mode tool maintains its own isolated state (e.g., window._wmAlgorithm, window._piPassword).

State is cleared by clearSimpleData() which nullifies all properties, revokes Object URLs, and calls initSimplified() to reset the UI.


Navigation System

SPA Mode (index.html)

The browser uses the History API for SPA routing with hash-based navigation:

history.pushState(
  { modeOverlay: 'simplified', modeSet: true, page: 'simple-page' },
  '',
  '#/simple-page'
)

The popstate event listener restores UI state:

History State Effect
{ page: 'home' } Show landing page
{ page: 'watermark' } Show watermark tool
{ page: 'fingerprint' } Show fingerprint tool
{ page: 'about' } Show about page
... 23+ page IDs total

SEO is handled via PAGE_TITLES and PAGE_DESCS maps in navigation.js. On every showPage() call, document.title and the <meta name="description"> tag are updated.

MPA Mode (Standalone Pages)

Each tool has its own standalone page at Style/pages/{name}/index.html. These pages share the same <head>, sidebar, footer, modals, and scripts as index.html, but contain only the single page section for their tool.

The MPA router (mpa-router.js) enables seamless navigation:

  1. Interception: Links to other tool pages (relative URLs) are intercepted
  2. AJAX Fetch: The target page HTML is fetched via fetch()
  3. Content Swap: Only the content inside <div id="app"> is swapped
  4. State Push: history.pushState() updates the URL
  5. popstate: Back/forward restores cached pages from sessionStorage
  6. Audio Persistence: The music player continues playing across page navigations

Detection: Pages set data-standalone="page-name" on <html>; navigation.js checks this to determine mode.


CLI Architecture

The CLI uses Commander.js v14 for command parsing with 14 subcommands:

cli/index.js
├── program.version() / .description()
├── program.command('fingerprint')
│   ├── .argument('<file>')
│   ├── .option('-a, --algo <type>')
│   ├── .option('-j, --json')
│   └── .option('-o, --output <file>')
├── program.command('watermark')
│   ├── .command('embed')
│   └── .command('extract')
├── program.command('metadata')
│   └── ...
├── program.command('audio-watermark')
│   ├── .command('embed')
│   └── .command('extract')
├── program.command('pixel-injection')
│   ├── .command('embed')
│   └── .command('extract')
├── program.command('timestamp')
│   ├── create/verify
├── program.command('c2pa')
│   ├── sign/read/verify
├── program.command('forensic')
├── program.command('did')
│   ├── generate/sign
├── program.command('certificate')
├── program.command('document-watermark')
│   ├── embed/extract
├── program.command('converter')
├── program.command('upgrade')
└── program.command('tools')

Two helpers live outside Commander: cli/menu.js (interactive numbered menu that shells out to index.js) and cli/lib/id_forge.js (standalone ID generator: node cli/lib/id_forge.js <type> [count|file]).

Each command handler:

  1. Validates the input file through the 6-layer validation pipeline
  2. Loads the required browser JS modules via vm.runInContext()
  3. Calls the relevant function with CLI-provided parameters
  4. Formats and outputs results (text or JSON)

The CLI shares a single --allow-dangerous flag at the top level that bypasses validation for all commands.


Internationalization Architecture

The i18n system in Style/i18n.js supports 8 languages:

i18n.js
├── let currentLang = 'en'
├── const translations = { ar: {...}, de: {...}, en: {...}, es: {...}, 
│                          fr: {...}, ja: {...}, ko: {...}, zh: {...} }
├── function __(key, fallback)
│   └── Returns translation or fallback
├── function setLanguage(lang)
│   ├── Updates currentLang
│   ├── Sets dir="rtl" / dir="ltr" on <html>
│   ├── Updates html lang attribute
│   └── Re-translates all [data-i18n] elements
├── function initI18n()
│   └── Detects browser language, loads translations
└── function sanitizeHtml(text)
    ├── Tag whitelist: h2, h3, p, ul, li, a, br, strong, em, b, i, code, pre, blockquote, ol, span, div
    ├── Strips event handlers (onclick=, onerror=, etc.)
    ├── Strips javascript: URLs from href/src
    └── Returns safe HTML string

The sanitizeHtml() function is applied to 5 known-safe i18n keys that contain HTML: page.about, page.privacy, page.contact, page.social, and shared.drop_file.

Translation data is loaded from Style/lang/i18n-data-{lang}.js files, aggregated by i18n-data.js.


Security Architecture Overview

Security is implemented at multiple layers:

Layer Mechanism Scope
Service Worker Extension blocklist (60+), JS/CSS/YML/HTML/JSON/CDN whitelists, URL encoding detection, logo hotlink protection Browser
Domain Self-Check IIFE regex check on window.location All browser JS files
File Validation 6-layer pipeline (extension, magic bytes, content scan, document threats, structure, pooled buffer) CLI + Browser
XSS Prevention escHtml() for text, sanitizeHtml() for HTML content, tag whitelist Browser
Prototype Pollution Filtering in getAdvancedOptions(), case-insensitive key blocking Pixel Injection
Bot Detection checkAutomation(), showBotOverlay() for headless browsers Browser
VPN Detection detectWebRTCIPs(), startAsyncVPNDetection() Browser
Biometric Privacy Face/voice/iris templates stored encrypted on-device (WebAuthn PRF vault for face); never uploaded Biometrics

See the [Security] page for detailed documentation.


File Structure Relationships

Browser JS (Style/) ←── Shared by SPA + MPA pages
    │
    ├── Algorithm modules (Watermark/, Pixel_Injection/, etc.)
    │   └── Shared between Browser UI + CLI (via vm polyfills)
    │
    ├── Biometrics (Face_Biometric/, Iris_Biometric/, Voice_Biometric/)
    │   └── On-device engines (browser-only, WASM/ONNX models from CDN)
    │
    ├── Removal_Tools/ — metadata/watermark/fingerprint stripping
    │
    ├── CLI (cli/)
    │   ├── index.js — Commander.js entry (14 commands)
    │   ├── menu.js — interactive menu wrapper
    │   ├── utils.js — Polyfills + file I/O
    │   ├── lib/id_forge.js — standalone ID generator
    │   └── commands/ — 12 command handlers
    │
    └── Service Worker (sw.js)
        └── Security enforcement for all pages

The simplified.js file was split into modular files:

  • simplified.js — Bootstrap and step orchestration
  • simplified_countries.js — Country phone code data
  • simplified_helpers.js — Step helper functions
  • simplified_renderers.js — Step renderers

The certificate.js file was split into modular files:

  • certificate.js — Main entry
  • certificate_pdf.js, certificate_docx.js, certificate_epub.js — Format generators
  • certificate_ots.js — OTS integration
  • certificate_utils.js — Shared utilities

The Pixel Injection module grew to 6 files:

  • pixel_injection.js — Main class
  • watermark_core_advanced.js — Core algorithms
  • watermark_core_algorithms.js — Algorithm-specific implementations
  • watermark_core_transforms.js — DCT/DWT/DFT transforms
  • watermark_advanced_ui.js — Advanced UI with robustness testing
  • advanced_watermarking.js — Alternative class

Related

Wiki: API Reference
Wiki: FAQ
Wiki: Face Biometric
Wiki: Home
Wiki: Installation
Wiki: Iris Biometric
Wiki: Security
Wiki: Usage Guide
Wiki: Voice Biometric
Wiki: _Sidebar