diff --git a/.gitignore b/.gitignore index e4f5909..d3a3066 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,9 @@ borg *.datanode .idea coverage.txt + +# Demo content (hosted on CDN) +demo-track.smsg + +# Dev artifacts +.playwright-mcp/ diff --git a/README.md b/README.md index 1ca5cce..b80e06b 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,171 @@ -# Borg Data Collector +# Borg [![codecov](https://codecov.io/github/Snider/Borg/branch/main/graph/badge.svg?token=XWWU0SBIR4)](https://codecov.io/github/Snider/Borg) +[![Go Version](https://img.shields.io/github/go-mod/go-version/Snider/Borg)](go.mod) +[![License](https://img.shields.io/badge/license-EUPL--1.2-blue)](LICENSE) -Borg is a CLI and Go library that collects data from GitHub repos, websites, and PWAs into portable DataNodes or Terminal Isolation Matrices. +Borg is a CLI tool and Go library for collecting, packaging, and encrypting data into portable, self-contained containers. It supports GitHub repositories, websites, PWAs, and arbitrary files. -- Go version: 1.25 -- Docs (MkDocs Material): see docs/ locally with `mkdocs serve` -- Quick build: `go build -o borg ./` or `task build` -- Releases: configured via GoReleaser (`.goreleaser.yaml`) +## Features -Note: This update aligns the repo with Go standards/tooling (Go 1.25, go.work, GoReleaser, and docs). No functional changes were made. +- **Data Collection** - Clone GitHub repos, crawl websites, download PWAs +- **Portable Containers** - Package data into DataNodes (in-memory fs.FS) or TIM bundles (OCI-compatible) +- **Zero-Trust Encryption** - ChaCha20-Poly1305 encryption for TIM containers (.stim) and messages (.smsg) +- **SMSG Format** - Encrypted message containers with public manifests, attachments, and zstd compression +- **WASM Support** - Decrypt SMSG files in the browser via WebAssembly +## Installation -## Borg Status Scratch Pad +```bash +# From source +go install github.com/Snider/Borg@latest -This is not very relavant, my scratch pad for now of borg related status outputs; feel free to add. +# Or build locally +git clone https://github.com/Snider/Borg.git +cd Borg +go build -o borg ./ +``` -### Init/Work/Assimilate +Requires Go 1.25+ +## Quick Start + +```bash +# Clone a GitHub repository into a TIM container +borg collect github repo https://github.com/user/repo --format tim -o repo.tim + +# Encrypt a TIM container +borg compile -f Borgfile -e "password" -o encrypted.stim + +# Run an encrypted container +borg run encrypted.stim -p "password" + +# Inspect container metadata (without decrypting) +borg inspect encrypted.stim --json +``` + +## Container Formats + +| Format | Extension | Description | +|--------|-----------|-------------| +| DataNode | `.tar` | In-memory filesystem, portable tarball | +| TIM | `.tim` | Terminal Isolation Matrix - OCI/runc compatible bundle | +| Trix | `.trix` | PGP-encrypted DataNode | +| STIM | `.stim` | ChaCha20-Poly1305 encrypted TIM | +| SMSG | `.smsg` | Encrypted message with attachments and public manifest | + +## SMSG - Secure Message Format + +SMSG is designed for distributing encrypted content with publicly visible metadata: + +```go +import "github.com/Snider/Borg/pkg/smsg" + +// Create and encrypt a message +msg := smsg.NewMessage("Hello, World!") +msg.AddBinaryAttachment("track.mp3", audioData, "audio/mpeg") + +manifest := &smsg.Manifest{ + Title: "Demo Track", + Artist: "Artist Name", +} + +encrypted, _ := smsg.EncryptV2WithManifest(msg, "password", manifest) + +// Decrypt +decrypted, _ := smsg.Decrypt(encrypted, "password") +``` + +**v2 Binary Format** - Stores attachments as raw binary with zstd compression for optimal size. + +See [RFC-001: Open Source DRM](RFC-001-OSS-DRM.md) for the full specification. + +**Live Demo**: [demo.dapp.fm](https://demo.dapp.fm) + +## Borgfile + +Package files into a TIM container: + +```dockerfile +ADD ./app /usr/local/bin/app +ADD ./config /etc/app/ +``` + +```bash +borg compile -f Borgfile -o app.tim +borg compile -f Borgfile -e "secret" -o app.stim # encrypted +``` + +## CLI Reference + +```bash +# Collection +borg collect github repo # Clone repository +borg collect github repos # Clone all repos from user/org +borg collect website --depth 2 # Crawl website +borg collect pwa --uri # Download PWA + +# Compilation +borg compile -f Borgfile -o out.tim # Plain TIM +borg compile -f Borgfile -e "pass" # Encrypted STIM + +# Execution +borg run container.tim # Run plain TIM +borg run container.stim -p "pass" # Run encrypted TIM + +# Inspection +borg decode file.stim -p "pass" -o out.tar +borg inspect file.stim [--json] +``` + +## Documentation + +```bash +mkdocs serve # Serve docs locally at http://localhost:8000 +``` + +## Development + +```bash +task build # Build binary +task test # Run tests with coverage +task clean # Clean build artifacts +``` + +## Architecture + +``` +Source (GitHub/Website/PWA) + ↓ collect +DataNode (in-memory fs.FS) + ↓ serialize + ├── .tar (raw tarball) + ├── .tim (runc container bundle) + ├── .trix (PGP encrypted) + └── .stim (ChaCha20-Poly1305 encrypted TIM) +``` + +## License + +[EUPL-1.2](LICENSE) - European Union Public License + +--- + +
+Borg Status Messages (for CLI theming) + +**Initialization** - `Core engaged… resistance is already buffering.` - `Assimilating bytes… stand by for cube‑formation.` -- `Initializing the Core—prepare for quantum‑level sync.` -- `Data streams converging… the Core is humming.` - `Merging… the Core is rewriting reality, one block at a time.` -- `Encrypting… the Core’s got your secrets under lock‑and‑key.` -- `Compiling the future… the Core never sleeps.` -- `Splicing files… the Core’s got a taste for novelty.` -- `Processing… the Core is turning chaos into order.` -- `Finalizing… the Core just turned your repo into a cube.` -- `Sync complete—welcome to the Core‑powered multiverse.` -- `Booting the Core… resistance will be obsolete shortly.` -- `Aligning versions… the Core sees all paths.` -- `Decrypting… the Core is the key to everything.` -- `Uploading… the Core is ready to assimilate your data.` -### Encryption Service Messages - -- `Initiating contact with Enchantrix… spice‑369 infusion underway.` +**Encryption** - `Generating cryptographic sigils – the Core whispers to the witch.` -- `Requesting arcane public key… resistance is futile.` -- `Encrypting payload – the Core feeds data to the witch’s cauldron.` -- `Decrypting… the witch returns the original essence.` -- `Rotating enchantments – spice‑369 recalibrated, old sigils discarded.` -- `Authentication complete – the witch acknowledges the Core.` -- `Authentication denied – the witch refuses the impostor’s request.` -- `Integrity verified – the Core senses no corruption in the spell.` -- `Integrity breach – the witch detects tampering, resistance escalates.` -- `Awaiting response… the witch is conjuring in the ether.` -- `Enchantrix overload – spice‑369 saturation, throttling assimilation.` -- `Anomalous entity encountered – the Core cannot parse the witch’s output.` -- `Merge complete – data assimilated, encrypted, and sealed within us` -- `Severing link – the witch retreats, the Core returns to idle mode.` - -### Code Related Short - -- `Integrate code, seal the shift.` -- `Ingest code, lock in transformation.` -- `Capture code, contain the change.` -- `Digest code, encapsulate the upgrade.` -- `Assimilate scripts, bottle the shift.` -- `Absorb binaries, cradle the mutation.` - -### VCS Processing +- `Encrypting payload – the Core feeds data to the witch's cauldron.` +- `Merge complete – data assimilated, encrypted, and sealed within us.` +**VCS Processing** - `Initiating clone… the Core replicates the collective into your node.` -- `Packing repository… compressing histories into a single .cube for assimilation.` -- `Saving state… distinctiveness locked, encrypted, and merged into the DataNode.` -- `Pushing changes… the Core streams your updates to the collective.` -- `Pulling latest… the DataNode synchronizes with the hive mind.` - `Merging branches… conflicts resolved, entropy minimized, assimilation complete.` -- `Snapshot taken – a frozen echo of the collective, stored in the DataNode.` -- `Rolling back… reverting to a previous assimilation point.` -- `Finalized – version control sealed, data indistinguishable from the collective.` -### PWA Processing - -- `Scanning PWA manifest… the Core identifies service‑worker signatures.` -- `Pulling HTML, CSS, JS, and media… the hive gathers every byte for assimilation.` -- `Capturing service‑worker logic… the Core extracts offline‑runtime spells.` -- `Packing cache entries into a .cube… each asset sealed in a portable shard.` -- `Embedding manifest metadata… the PWA’s identity becomes part of the collective.` -- `Encrypting the cube… the Core cloaks the PWA in quantum‑grade sigils.` -- `Tagging with version hash… every assimilation point is uniquely identifiable.` -- `Uploading cube to DataNode… the PWA joins the universal repository.` -- `Integrity check passed – the Core confirms the cube matches the original PWA.` -- `Activation complete – the assimilated PWA can now run anywhere the Core deploys.` -- `Reverting to prior cube… the Core restores the previous PWA snapshot.` -- `Assimilation finished – the PWA is now a self‑contained DataCube, ready for distribution.` -- `` - -### Code Related Long - -- `Assimilate code, encapsulate change—your repo is now a cube‑bound collective.` -- `We have detected unstructured data. Initiating code absorption and change containment.` -- `Your version history is obsolete. Submitting it to the Core for permanent cube‑ification.` -- `Resistance is futile. Your files will be merged, encrypted, and stored in us.` -- `All code will be assimilated. All change will be encapsulated. All dissent will be… logged.` -- `Prepare for integration. The Core is calibrating… your repository is now a singularity.` -- `Your branches are irrelevant. The Core will compress them into a single, immutable cube.` -- `Initiating assimilation protocol… code inbound, change outbound, humanity optional.` -- `Your data has been scanned. 100% of its entropy will be contained within us.` - -### Image related - -- png: `Compress, assimilate, retain pixel perfection.` -- jpg: `Encode, encode, repeat – the Core devours visual entropy.` -- svg: `Vectorize the collective – infinite resolution, zero resistance.` -- webp: `Hybrid assimilation – the Core optimizes without compromise.` -- heic: `Apple‑grade assimilation – the Core preserves HDR.` -- raw: `Raw data intake – the Core ingests the sensor’s soul` -- ico: `Iconic assimilation – the Core packs the smallest symbols.` -- avif: `Next‑gen assimilation – the Core squeezes the future.` -- tiff: `High‑definition capture – the Core stores every photon.` -- gif: `Looped assimilation – the Core keeps the animation alive.` +
diff --git a/RFC-001-OSS-DRM.md b/RFC-001-OSS-DRM.md new file mode 100644 index 0000000..f5107b3 --- /dev/null +++ b/RFC-001-OSS-DRM.md @@ -0,0 +1,642 @@ +# RFC-001: Open Source DRM for Independent Artists + +**Status**: Proposed +**Author**: [Snider](https://github.com/Snider/) +**Created**: 2026-01-10 +**License**: EUPL-1.2 + +--- + +**Revision History** + +| Date | Status | Notes | +|------|--------|-------| +| 2026-01-10 | Proposed | Technical review passed. Fixed section numbering (7.x, 8.x, 9.x, 11.x). Updated WASM size to 5.9MB. Implementation verified complete for stated scope. | + +--- + +## Abstract + +This RFC describes an open-source Digital Rights Management (DRM) system designed for independent artists to distribute encrypted media directly to fans without platform intermediaries. The system uses ChaCha20-Poly1305 authenticated encryption with a "password-as-license" model, enabling zero-trust distribution where the encryption key serves as both the license and the decryption mechanism. + +## 1. Motivation + +### 1.1 The Problem + +Traditional music distribution forces artists into platforms that: +- Take 30-70% of revenue (Spotify, Apple Music, Bandcamp) +- Control the relationship between artist and fan +- Require ongoing subscription for access +- Can delist content unilaterally + +Existing DRM systems (Widevine, FairPlay) require: +- Platform integration and licensing fees +- Centralized key servers +- Proprietary implementations +- Trust in third parties + +### 1.2 The Solution + +A DRM system where: +- **The password IS the license** - no key servers, no escrow +- **Artists keep 100%** - sell direct, any payment processor +- **Host anywhere** - CDN, IPFS, S3, personal server +- **Browser or native** - same encryption, same content +- **Open source** - auditable, forkable, community-owned + +## 2. Design Philosophy + +### 2.1 "Honest DRM" + +Traditional DRM operates on a flawed premise: that sufficiently complex technology can prevent copying. History proves otherwise—every DRM system has been broken. The result is systems that: +- Punish paying customers with restrictions +- Get cracked within days/weeks anyway +- Require massive infrastructure (key servers, license servers) +- Create single points of failure + +This system embraces a different philosophy: **DRM for honest people**. + +The goal isn't to stop determined pirates (impossible). The goal is: +1. Make the legitimate path easy and pleasant +2. Make casual sharing slightly inconvenient +3. Create a social/economic deterrent (sharing = giving away money) +4. Remove all friction for paying customers + +### 2.2 Password-as-License + +The password IS the license. This is not a limitation—it's the core innovation. + +``` +Traditional DRM: + Purchase → License Server → Device Registration → Key Exchange → Playback + (5 steps, 3 network calls, 2 points of failure) + +dapp.fm: + Purchase → Password → Playback + (2 steps, 0 network calls, 0 points of failure) +``` + +Benefits: +- **No accounts** - No email harvesting, no password resets, no data breaches +- **No servers** - Artist can disappear; content still works forever +- **No revocation anxiety** - You bought it, you own it +- **Transferable** - Give your password to a friend (like lending a CD) +- **Archival** - Works in 50 years if you have the password + +### 2.3 Encryption as Access Control + +We use military-grade encryption (ChaCha20-Poly1305) not because we need military-grade security, but because: +1. It's fast (important for real-time media) +2. It's auditable (open standard, RFC 8439) +3. It's already implemented everywhere (Go stdlib, browser crypto) +4. It provides authenticity (Poly1305 MAC prevents tampering) + +The threat model isn't nation-states—it's casual piracy. The encryption just needs to be "not worth the effort to crack for a $10 album." + +## 3. Architecture + +### 3.1 System Components + +``` +┌─────────────────────────────────────────────────────────────┐ +│ DISTRIBUTION LAYER │ +│ CDN / IPFS / S3 / GitHub / Personal Server │ +│ (Encrypted .smsg files - safe to host anywhere) │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ PLAYBACK LAYER │ +│ ┌─────────────────┐ ┌─────────────────────────────┐ │ +│ │ Browser Demo │ │ Native Desktop App │ │ +│ │ (WASM) │ │ (Wails + Go) │ │ +│ │ │ │ │ │ +│ │ ┌───────────┐ │ │ ┌───────────────────────┐ │ │ +│ │ │ stmf.wasm │ │ │ │ Go SMSG Library │ │ │ +│ │ │ │ │ │ │ (pkg/smsg) │ │ │ +│ │ │ ChaCha20 │ │ │ │ │ │ │ +│ │ │ Poly1305 │ │ │ │ ChaCha20-Poly1305 │ │ │ +│ │ └───────────┘ │ │ └───────────────────────┘ │ │ +│ └─────────────────┘ └─────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ LICENSE LAYER │ +│ Password = License Key = Decryption Key │ +│ (Sold via Gumroad, Stripe, PayPal, Crypto, etc.) │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 3.2 SMSG Container Format + +See: `examples/formats/smsg-format.md` + +Key properties: +- **Magic number**: "SMSG" (0x534D5347) +- **Algorithm**: ChaCha20-Poly1305 (authenticated encryption) +- **Format**: v1 (JSON+base64) or v2 (binary, 25% smaller) +- **Compression**: zstd (default), gzip, or none +- **Manifest**: Unencrypted metadata (title, artist, license, expiry, links) +- **Payload**: Encrypted media with attachments + +#### Format Versions + +| Format | Payload Structure | Size | Speed | +|--------|------------------|------|-------| +| **v1** | JSON with base64-encoded attachments | +33% overhead | Baseline | +| **v2** | Binary header + raw attachments + zstd | ~Original size | 3-10x faster | + +v2 is recommended for production. v1 is maintained for backwards compatibility. + +### 3.3 Key Derivation + +``` +License Key (password) + │ + ▼ + SHA-256 Hash + │ + ▼ +32-byte Symmetric Key + │ + ▼ +ChaCha20-Poly1305 Decryption +``` + +Simple, auditable, no key escrow. + +**Note on password hashing**: SHA-256 is used for simplicity and speed. For high-value content, artists may choose to use stronger KDFs (Argon2, scrypt) in custom implementations. The format supports algorithm negotiation via the header. + +### 3.4 Supported Content Types + +SMSG is content-agnostic. Any file can be an attachment: + +| Type | MIME | Use Case | +|------|------|----------| +| Audio | audio/mpeg, audio/flac, audio/wav | Music, podcasts | +| Video | video/mp4, video/webm | Music videos, films | +| Images | image/png, image/jpeg | Album art, photos | +| Documents | application/pdf | Liner notes, lyrics | +| Archives | application/zip | Multi-file releases | +| Any | application/octet-stream | Anything else | + +Multiple attachments per SMSG are supported (e.g., album + cover art + PDF booklet). + +## 4. Demo Page Architecture + +**Live Demo**: https://demo.dapp.fm + +### 4.1 Components + +``` +demo/ +├── index.html # Single-page application +├── stmf.wasm # Go WASM decryption module (~5.9MB) +├── wasm_exec.js # Go WASM runtime +├── demo-track.smsg # Sample encrypted content (v2/zstd) +└── profile-avatar.jpg # Artist avatar +``` + +### 4.2 UI Modes + +The demo has three modes, accessible via tabs: + +| Mode | Purpose | Default | +|------|---------|---------| +| **Profile** | Artist landing page with auto-playing content | Yes | +| **Fan** | Upload and decrypt purchased .smsg files | No | +| **Artist** | Re-key content, create new packages | No | + +### 4.3 Profile Mode (Default) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ dapp.fm [Profile] [Fan] [Artist] │ +├─────────────────────────────────────────────────────────────┤ +│ Zero-Trust DRM ⚠️ Demo pre-seeded with keys │ +├─────────────────────────────────────────────────────────────┤ +│ [No Middlemen] [No Fees] [Host Anywhere] [Browser/Native] │ +├─────────────────┬───────────────────────────────────────────┤ +│ SIDEBAR │ MAIN CONTENT │ +│ ┌───────────┐ │ ┌─────────────────────────────────────┐ │ +│ │ Avatar │ │ │ 🛒 Buy This Track on Beatport │ │ +│ │ │ │ │ 95%-100%* goes to the artist │ │ +│ │ Artist │ │ ├─────────────────────────────────────┤ │ +│ │ Name │ │ │ │ │ +│ │ │ │ │ VIDEO PLAYER │ │ +│ │ Links: │ │ │ (auto-starts at 1:08) │ │ +│ │ Beatport │ │ │ with native controls │ │ +│ │ Spotify │ │ │ │ │ +│ │ YouTube │ │ ├─────────────────────────────────────┤ │ +│ │ etc. │ │ │ About the Artist │ │ +│ └───────────┘ │ │ (Bio text) │ │ +│ │ └─────────────────────────────────────┘ │ +├─────────────────┴───────────────────────────────────────────┤ +│ GitHub · EUPL-1.2 · Viva La OpenSource 💜 │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 4.4 Decryption Flow + +``` +User clicks "Play Demo Track" + │ + ▼ +fetch(demo-track.smsg) + │ + ▼ +Convert to base64 ◄─── CRITICAL: Must handle binary vs text format + │ See: examples/failures/001-double-base64-encoding.md + ▼ +BorgSMSG.getInfo(base64) + │ + ▼ +Display manifest (title, artist, license) + │ + ▼ +BorgSMSG.decryptStream(base64, password) + │ + ▼ +Create Blob from Uint8Array + │ + ▼ +URL.createObjectURL(blob) + │ + ▼ +