{"id":49844751,"url":"https://github.com/flyingsurveyor/qrfs","last_synced_at":"2026-05-14T09:07:21.662Z","repository":{"id":352845793,"uuid":"1216829934","full_name":"flyingsurveyor/qrfs","owner":"flyingsurveyor","description":"QR FileSystem: a physical, offline, encrypted data transport and storage system based on QR","archived":false,"fork":false,"pushed_at":"2026-05-08T22:28:01.000Z","size":304,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-08T23:35:31.500Z","etag":null,"topics":["air-gapped","archival","encryption","file","flask","optical","python","qrcode","raspberry-pi","termux"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flyingsurveyor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-21T09:19:01.000Z","updated_at":"2026-05-08T22:01:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/flyingsurveyor/qrfs","commit_stats":null,"previous_names":["flyingsurveyor/qrfs"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/flyingsurveyor/qrfs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingsurveyor%2Fqrfs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingsurveyor%2Fqrfs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingsurveyor%2Fqrfs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingsurveyor%2Fqrfs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flyingsurveyor","download_url":"https://codeload.github.com/flyingsurveyor/qrfs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingsurveyor%2Fqrfs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33017743,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["air-gapped","archival","encryption","file","flask","optical","python","qrcode","raspberry-pi","termux"],"created_at":"2026-05-14T09:07:20.452Z","updated_at":"2026-05-14T09:07:21.649Z","avatar_url":"https://github.com/flyingsurveyor.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# QRFS – QR Filesystem\n\n[![CI](https://github.com/flyingsurveyor/qrfs/actions/workflows/ci.yml/badge.svg)](https://github.com/flyingsurveyor/qrfs/actions/workflows/ci.yml)\n\nQRFS is an experimental system to encode encrypted data into printable QR code pages.\n\nIt is NOT a traditional filesystem.\n\nIt is a:\n\u003e **physical, offline, encrypted data transport and storage system**\n\n---\n\n## 📐 Specification\n\nQRFS is independently re-implementable. The on-wire format (`QFSP v1`, `QFSC v6`, `QRC3`) is\nfully documented in [`docs/SPEC-1.0.md`](docs/SPEC-1.0.md) — an RFC-style specification that\nany competent implementer can use to build a conforming QRFS encoder or decoder **without reading\na single line of Python code**. The Python package in this repository is the reference\nimplementation. Conformance test vectors are in `tests/vectors/`.\n\n---\n\n## 🧠 What QRFS Is\n\nQRFS allows you to:\n\n- take any file\n- encrypt it securely\n- split it into chunks\n- encode it into QR codes\n- print or display them\n- reconstruct the file later from scans or photos\n\nIt works offline, including local encode/decode and the browser-based live scanner shipped in `qrfs/static/vendor/`.\n\n---\n\n## 🚀 Core Features\n\n- Password-based encryption (Argon2 + AEAD)\n- Public key encryption (X25519 / SealedBox)\n- Digital signatures (Ed25519)\n- Chunking system\n- FEC (XOR and Reed-Solomon, with explicit parity QR)\n- Multi-page PDF generation\n- Scan \u0026 reconstruct from images\n\n---\n\n## ⚖️ What QRFS Is NOT\n\n- Not a replacement for cloud storage\n- Not efficient for large data\n- Not a high-speed transfer system\n\n---\n\n## 🔥 Real Use Cases\n\n### 1. Air-gapped data transfer\nMove data between isolated systems without USB or network.\n\n### 2. Field data exchange\nExchange data without connectivity using printed pages or phone images.\n\n### 3. Physical encrypted archive\nStore data in printed form, readable without digital infrastructure.\n\n---\n\n## 🧊 Long-term Archival / Time Capsule\n\nQRFS can be used for **long-term data preservation**.\n\nConcept:\n\n- Store data on physical media (paper, metal, glass)\n- Include:\n  - human-readable explanation\n  - decoding instructions\n  - format specification\n- Encode actual data using QRFS\n\nThis creates a **self-describing archive**.\n\nEven if all software is lost, the data can be reconstructed.\n\n---\n\n## 🧠 Key Insight\n\nQRFS separates:\n\n- **data transport (physical)**\n- **data security (cryptography)**\n\n---\n\n## 📦 Working with Multiple Files\n\nQRFS operates on a single input file.\n\nFor multiple files or folders:\n\n👉 Create a ZIP archive first, then encode it.\n\nZIP may optionally be password-protected as an additional layer.\n\n---\n\n## 🧩 FEC: XOR vs Reed-Solomon\n\nQRFS can optionally add **extra parity QR codes** to improve recovery when some QR codes are missing or unreadable.\n\n### XOR FEC\n\n- adds **1 parity QR** for each group of `N` data QR\n- can recover **at most 1 missing data chunk per group**\n- simple, predictable, and easy to reason about\n\nExample: with group size `5`, QRFS emits `5 data + 1 parity`.\nIf exactly one of those 5 data QR is missing, QRFS can reconstruct it.\nIf two data QR are missing from the same group, XOR is not enough.\n\n### Reed-Solomon FEC\n\n- adds `P` parity QR for each group of `N` data QR\n- can recover up to `P` **known erasures per group**\n- more flexible than XOR, but also denser and more demanding\n\nExample: with group size `5` and parity `2`, QRFS emits `5 data + 2 parity`.\nThat group can survive up to 2 missing chunks in total inside the group.\n\n### Important practical notes\n\n- FEC helps with **missing or unreadable chunks**. It does **not** replace the QR code's own ECC level.\n- Parity QR carry a small amount of extra metadata (chunk lengths), so they can be **slightly larger** than plain data QR.\n- Dense presets plus FEC should always be tested on your **real printer / camera / scanner** path before relying on them.\n- The internal **Testbench** page is useful for validating chunk loss scenarios before publishing or field use.\n\n---\n\n## ⚠️ Limitations\n\n- Low data density compared to digital storage\n- Requires reconstruction process\n- Depends on image quality when scanning\n- Physical media can degrade\n\n---\n\n## 🔐 Security Model\n\nSecurity relies on:\n\n- strong password (with Argon2)\n- or public/private key cryptography\n- authenticated encryption\n\n---\n\n## 🛠 Installation\n\nQRFS binds to `127.0.0.1` (loopback only) by default, so a fresh\n`python qrfs.py` is **not reachable from the network** unless you opt in.\n\n- On the same device: `http://127.0.0.1:5000`\n- From another device on the same LAN: `python qrfs.py --lan` → `http://\u003cdevice-ip\u003e:5000`\n\nRun `python qrfs.py --debug` only if you explicitly want Flask debug mode.\nThe default non-debug path uses Waitress when installed.\n\n### Security defaults\n\n**Loopback-only by default.**\nA fresh `python qrfs.py` with no arguments binds to `127.0.0.1:5000` and is\nreachable only from the same device.  Use `--lan` (or `QRFS_LAN=1`) to expose\nQRFS on the local network.  Use `--host \u003caddr\u003e` for full control.\n\n**Optional self-signed HTTPS.**\nAdd `--https` to run the server over TLS.  On first run QRFS auto-generates an\nEd25519 self-signed certificate under `data/tls/` (key stored with mode\n`0o600`) and prints its SHA-256 fingerprint at startup.  Subsequent runs reuse\nthe same certificate.  Supply `--cert \u003cpath\u003e --key \u003cpath\u003e` to use your own\ncertificate instead.\n\n\u003e **Note:** Self-signed TLS does not protect against active MITM unless you\n\u003e verify and pin the certificate fingerprint out-of-band on each remote device.\n\n**KDF rate limiting.**\nPassword-based decode attempts (Argon2id) are rate-limited to **5 per IP per\n60 seconds**.  The 6th attempt within the window returns HTTP 429 with a\n`Retry-After` header.\n\n### Raspberry Pi / Debian / Ubuntu\n\n#### 1. Install system packages\n\n```bash\nsudo apt update\nsudo apt install -y \\\n  git \\\n  python3 \\\n  python3-pip \\\n  python3-venv \\\n  poppler-utils \\\n  libzbar0\n```\n\nIf `pip install -r requirements.txt` needs to compile native packages, install these optional build dependencies too:\n\n```bash\nsudo apt install -y \\\n  build-essential \\\n  python3-dev \\\n  pkg-config \\\n  libjpeg-dev \\\n  zlib1g-dev \\\n  libpng-dev \\\n  libffi-dev \\\n  libssl-dev \\\n  cargo\n```\n\n#### 2. Clone the repository\n\n```bash\ngit clone https://github.com/flyingsurveyor/qrfs.git\ncd qrfs\n```\n\n#### 3. Create a virtual environment and install Python dependencies\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\npython -m pip install --upgrade pip\npython -m pip install -r requirements.txt\n```\n\n#### 4. Start QRFS\n\n```bash\npython qrfs.py\n```\n\n### Termux\n\n#### 1. Install system packages\n\n```bash\npkg update\npkg upgrade -y\npkg install -y \\\n  git \\\n  python \\\n  zbar \\\n  poppler \\\n  libjpeg-turbo \\\n  libpng\n```\n\nIf `pip install -r requirements.txt` needs to compile native packages, install these optional build dependencies too:\n\n```bash\npkg install -y \\\n  clang \\\n  make \\\n  pkg-config \\\n  ndk-sysroot \\\n  rust\n```\n\n#### 2. Clone the repository\n\n```bash\ngit clone https://github.com/flyingsurveyor/qrfs.git\ncd qrfs\n```\n\n#### 3. Install Python dependencies\n\n```bash\npython -m pip install --upgrade pip\npython -m pip install -r requirements.txt\n```\n\n#### 4. Start QRFS\n\n```bash\npython qrfs.py\n```\n\n### Quick dependency check\n\n```bash\nwhich pdftoppm\npython -c \"from pyzbar.pyzbar import decode; print('OK')\"\n```\n\nIf `pdftoppm` is found and the Python command prints `OK`, the main decoding dependencies are in place.\n\n---\n\n## 🌍 Future Directions\n\nQRFS is still experimental, but its direction is becoming clearer.\n\nThe goal is not to turn it into a generic storage system or a novelty QR project.\n\nThe real direction is to make QRFS more reliable, more self-describing, and more useful in degraded, offline, hostile, or infrastructure-poor environments.\n\nPossible future directions include:\n\n- **Better scanning UX**  \n  Faster and more reliable recovery from photos and scans, with clearer feedback about missing, duplicated, or damaged chunks.\n\n- **Improved FEC strategies**  \n  Smarter redundancy profiles, better real-world recovery behavior, and stronger resilience to partial page loss or poor image quality.\n\n- **Standardization of the QRFS format**  \n  A documented, versioned, implementation-independent format that can be decoded and reconstructed without relying on a single codebase.\n\n- **Physical medium optimization**  \n  Better support for paper, low-quality printers, difficult lighting, and more durable media such as metal, engraving, or other long-life physical substrates.\n\n- **Time capsule / archival edition**  \n  A more conservative and self-describing archival mode designed for long-term preservation, with human-readable recovery guidance and format documentation.\n\n- **Paranoid Mode for politically harsh environments**  \n  A minimal-disclosure mode that reduces metadata leakage, avoids unnecessary identifiers, and makes physical transport safer in hostile conditions.\n\n- **Transport to and from Reticulum networks**  \n  Using QRFS as a physical bridge for disconnected or delayed networks: exporting payloads from Reticulum, carrying them physically, and reinjecting them later.\n\n- **Paper computing / executable capsules**  \n  Exploring whether small scripts, bootstrap tools, configurations, and operational payloads can travel physically on paper as signed, inspectable, self-describing QRFS bundles.\n\n- **Field-ready operational profiles**  \n  Clear presets such as archive, rugged field, balanced, or dense mode, so QRFS can be tuned for real-world use instead of only lab conditions.\n\nIn the long term, QRFS may evolve from a simple encrypted QR transport tool into something broader:\n\n\u003e **a physical carrier for data, instructions, and minimal capabilities across disconnected worlds**\n\n---\n\n## 🧭 Philosophy\n\nQRFS is not about replacing modern systems.\n\nIt is about:\n\n\u003e **having an alternative when modern systems are unavailable**\n\n---\n\n## 🛠 Development\n\nTo set up a development environment:\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -e .[dev]\n```\n\nRun the test suite:\n\n```bash\npytest\n```\n\nRun the linter:\n\n```bash\nruff check .\n```\n\nCI runs the same checks (`pytest`, `ruff check .`, and `bandit -r qrfs/core`) on every push to `main` and on every pull request, across Python 3.11, 3.12, and 3.13.\n\nThe on-wire format is pinned by reference vectors under `tests/vectors/` — see `docs/FORMAT.md` §12.\n\n---\n\n## 📜 License\n\nQRFS is released under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eMade with ❤️ for freedom\u003c/b\u003e\u003cbr\u003e\u003cbr\u003e\n  \u003ca href=\"https://github.com/flyingsurveyor\"\u003eFlyingSurveyor\u003c/a\u003e · Italy\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflyingsurveyor%2Fqrfs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflyingsurveyor%2Fqrfs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflyingsurveyor%2Fqrfs/lists"}