Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,19 @@ File (image / audio / video / document / anything)
│
▼
┌─────────────────────────────────────────────┐
│ 🖼️ Images → EXIF, XMP, IPTC (JPEG edit) │
│ 🖼️ Images → EXIF, XMP, IPTC, ICC, RAW │
│ 🎵 Audio → ID3, Vorbis, ASF, APEv2, MP4 │
│ 🎬 Video → MP4/MOV tags, other: read │
│ 🎬 Video → MP4/MOV atoms, MKV/WebM │
│ 📄 PDF → document info + XMP │
│ 📊 Office → OOXML core/app/custom, OLE │
│ 📊 Office → OOXML, OpenDocument, OLE │
│ 📚 E-books → EPUB package metadata │
│ 📁 Any file → size, timestamps, attributes,│
│ xattr; hachoir fallback │
└─────────────────────────────────────────────┘
│
▼
👁️ View · ✏️ Edit · 🗑️ Delete · ⚖️ Diff · 🔑 Hash
👁️ View · ✏️ Edit · 🗑️ Delete · 🛡️ Share safely
⚖️ Diff · 🔑 Hash · 🗂️ Batch
```

---
Expand All @@ -71,20 +73,22 @@ File (image / audio / video / document / anything)
- ✏️ **Typed editing** — read, edit, add and delete individual fields with inputs matching their type (text, numbers, booleans, dates with UTC offset, exact rationals, lists); the sidecar validates every value and decides what is editable
- 🔒 **Verified atomic writes** — changes go to a private copy beside the file, are read back and checked, then replace the original (`ReplaceFileW` on Windows, `os.replace` elsewhere); a failure leaves the file untouched
- ↩️ **Exact Undo** — up to 50 saves per session, restored byte for byte in the usual case (pictures and other binaries included; very large changes fall back to restoring the values); refused if the file changed meanwhile
- 🛡️ **Prepare files for sharing** — the *Share* tab removes location, identity, device, dates, software, thumbnails and edit history in one undoable step; each field shows a privacy badge
- 🗂️ **Batch operations** — on many files: prepare for sharing, shift dates, copy metadata, add a position (fixed or from a GPX track), rename from metadata, export a folder to CSV/JSON
- 🔎 **Files recognized by content** — a file without (or with a wrong) extension is handled as its real format
- 🔑 **File integrity hashes** — on-demand MD5 / SHA-1 / SHA-256 / SHA-512 / BLAKE2b with one-click copy
- 🎨 **Cyber dark theme** — professional dark UI with cyan/blue accents
- 📦 **Compiled binaries** — no Python or Node.js required to run
- 💾 **Offline-first** — zero telemetry; the only network call is the optional update check
- 🚪 **Clean exit** — the *Exit* button stops the background process and everything it started, and releases its memory and port
- 🔔 **Update check** — manual from *About* / *Help*, or opt-in at startup; downloads are SHA-256 verified
- 🆓 **Free & open-source** — MIT license

---

## 🔧 Version

**v0.3.5** (latest stable) — Security and reliability release: every sidecar API call is authenticated with a per-session token, the Electron renderer is sandboxed with a Content Security Policy, PDF/Office edits preserve unrelated content, audio/video edits are atomic, and Undo restores original values. Dependencies updated (Pillow, pypdf, Vite, Electron). No API changes.

**Next: 0.4.0** (in development, not yet released) — update check and repository link in *About*; XMP and IPTC reading and writing for JPEG; typed values (lists, numbers, dates, exact rationals) instead of joined strings; adding fields; exact server-side Undo; uniform API errors; Linux packages built on a RHEL 9 baseline (Ubuntu 22.04+, Debian 12+, Fedora, RHEL 9/10).
The badges at the top of this page always show the latest stable and beta releases.

📖 **See full version history** → [CHANGELOG.md](./CHANGELOG.md)

Expand Down Expand Up @@ -180,14 +184,18 @@ Python Sidecar (FastAPI)
├── /read — full metadata extraction (format + filesystem layer)
├── /write — verified atomic write (and optional deletes) in one save
├── /delete — field removal
├── /sanitize, /sanitize-many — prepare one or many files for sharing
├── /shift-dates, /copy-tags, /geotag, /rename, /export — operations on several files
├── /undo — exact undo of a save by its token
├── /diff — metadata comparison
├── /aliases — common names used by the search box
└── /hash — on-demand file hashing

React Frontend (Vite + TailwindCSS)
├── FolderPanel — folder tree navigation
├── FilePanel — file list with metadata summary
└── DetailPanel — Metadata / Edit / Diff tabs
├── DetailPanel — Metadata / Edit / Share / Diff tabs
└── BatchDialog — operations on several files
```

📖 Full endpoint reference → [API.md](docs/API.md)
Expand Down Expand Up @@ -258,5 +266,5 @@ Distributed with MIT License · [View License](LICENSE)

---

*Last updated: 2026-11-03*
*Last updated: 2026-11-04*
*← [Requirements](docs/REQUIREMENTS.md) | [Docs →](docs/)*
6 changes: 4 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ MetaLens is designed with security-first principles:
- **Atomic, verified writes** — every save (edits and deletions together) is prepared on a copy in a private temporary directory beside the target, read back and checked against the request, and checked for concurrent modification before the copy replaces the original (`ReplaceFileW` on Windows, preserving the security descriptor, alternate data streams and file attributes such as *hidden*; `os.replace` elsewhere). Any failure leaves the original content intact. The replacement is a new file, so hard links to the original are detached. A read-only file is refused (HTTP 403), not modified
- **Path validation** — a dedicated `core.path_security` module normalizes every path (resolves `~`, `..` and symbolic links) and checks that it is an existing, readable regular file or directory before any filesystem access, across all API routes. This is normalization, not a sandbox: an authenticated caller may name any file the user account can access, which is why every request must carry the session token
- **Hardened update check** — requests are made by the Electron main process, never by the renderer (whose CSP still only allows the local sidecar). It queries the GitHub Releases API of `overwrite00/MetaLens` only, and the renderer cannot supply URLs. Release and asset URLs must point to that repository, and the installer is downloaded only when you click *Download & install* (Windows installed builds), checked against its size and the SHA-256 digest published by GitHub, and discarded on any mismatch. Release notes are shown as plain text
- **No internal details in errors** — API error bodies carry fixed, structured messages only; the text of internal exceptions stays in the local log
- **Clean shutdown** — the *Exit* button (and closing the app) stops the sidecar's whole process tree, cancels any update download and releases the port and memory
- **Transparent code** — all handler and analysis logic is open-source and auditable

---
Expand Down Expand Up @@ -39,7 +41,7 @@ MetaLens is designed with security-first principles:
### Metadata Handlers

- Uses established libraries per format: Pillow (image properties), piexif tag tables plus MetaLens's own structure-preserving EXIF/XMP/IPTC codecs and JPEG segment writer (images), mutagen (audio/MP4), pypdf (PDF), Python's `zipfile`/`xml.etree` (Office Open XML packages), olefile (legacy Office), hachoir (read-only fallback for other formats). XMP packets (JPEG, PDF) containing DOCTYPE or entity declarations are refused
- Field capabilities are enforced by the API; client-provided editability flags cannot override them. Writable: JPEG EXIF/XMP/IPTC, audio tags (except AAC), MP4/MOV atoms, PDF document info, Office core properties, `fs:mtime` and Linux `user.` extended attributes. Read-only: other image formats and RAW, AAC, MKV/AVI and other non-MP4 video, encrypted or digitally signed PDFs, digitally signed Office packages (so a signature is never silently invalidated), Office `app.xml`/`custom.xml`, legacy Office, everything read through hachoir
- Field capabilities are enforced by the API; client-provided editability flags cannot override them. Writable: EXIF/XMP/IPTC of JPEG, PNG, WebP, TIFF, TIFF-based RAW and HEIC/AVIF (what a format cannot hold is refused), audio tags (except AAC), MP4/MOV and MKV/WebM metadata, PDF document info and XMP, Office and OpenDocument/EPUB properties, `fs:mtime` and Linux `user.` extended attributes; legacy Office (DOC/XLS/PPT) allows removing properties only. Read-only: GIF/BMP, Canon CR3 and Fujifilm RAF, AAC, AVI and other video read through hachoir, encrypted or digitally signed PDFs, digitally signed Office packages (so a signature is never silently invalidated), everything read through hachoir. Every write is checked so that the picture, audio or video data comes out identical
- Every value is validated before the file is touched; library errors caused by a value are reported as validation errors (HTTP 422), never as crashes
- Filesystem access always goes through `validate_file_path`/`validate_directory_path` before touching disk

Expand Down Expand Up @@ -108,5 +110,5 @@ We appreciate responsible disclosure and will credit you in the security advisor

---

*Last updated: 2026-11-02*
*Last updated: 2026-11-04*
*← [Contributing](./CONTRIBUTING.md) | [Back to README →](./README.md)*
4 changes: 2 additions & 2 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The **detail panel** (`DetailPanel`) opens on the **Metadata** tab by default, s
- Multi-valued fields (artists, keywords, …) are shown as lists, never joined into one string.
- A line above the table tells what sharing the file would reveal (location, identity, device, dates...), and each sensitive field carries a badge with its category.
- Binary values (cover art, pictures, MakerNote, thumbnails) are shown as size, MIME type and SHA-256, not as their bytes.
- Notices above the table explain why the format metadata is read-only (e.g. signed PDF, AAC, legacy Office), report read errors and show warnings (e.g. an EXIF MakerNote that is moved on rewrite, duplicated metadata segments).
- Notices above the table explain why the format metadata is read-only (e.g. signed PDF, AAC, CR3/RAF), report read errors and show warnings (e.g. an EXIF MakerNote that is moved on rewrite, duplicated metadata segments).

---

Expand All @@ -62,7 +62,7 @@ Switch to the **Edit** tab to open `MetadataEditor`:
- Editable fields show an input matching their type: text, multi-line text, number, checkbox (booleans), dropdown (enumerated values), exact `n/d` rationals, a list editor for multi-valued fields, fixed-size inputs for pairs such as track `[number, total]`, and date-time with a separate UTC offset (EXIF dates are local times without offset)
- **Add field** offers the fields the format can store but the file does not have yet (e.g. an ID3 title on an untagged WAV, an XMP keyword list on a JPEG)
- **Save** sends all edits, additions and deletions as **one** save. The sidecar validates every value first (invalid values are reported next to their field and nothing is written), applies the changes to a private copy next to the file, reads the copy back to check that exactly the requested changes were stored, and only then replaces the original (`ReplaceFileW` on Windows, keeping the security descriptor, alternate data streams and attributes such as *hidden*; `os.replace` elsewhere). A failure at any step leaves the original untouched. The file is replaced by a new one, so hard links to it are detached
- When the format metadata is read-only (e.g. RAW, TIFF/PNG/WebP/GIF, AAC, MKV/AVI, legacy `.doc`/`.xls`/`.ppt`, encrypted or digitally signed PDFs, signed Office packages), the Edit tab shows a **read-only** notice with the reason; filesystem fields such as the modification time (`fs:mtime`) stay editable
- When the format metadata is read-only (e.g. GIF/BMP, Canon CR3 and Fujifilm RAF raw files, AAC, AVI and other video read through the fallback, encrypted or digitally signed PDFs, signed Office packages; legacy `.doc`/`.xls`/`.ppt` allow removing properties but not editing them), the Edit tab shows a **read-only** notice with the reason; filesystem fields such as the modification time (`fs:mtime`) stay editable

---

Expand Down
Loading