Mori
A private, offline media and file browser.
- Type
- Desktop app
- Runs on
- macOS · Windows · Linux
- Get it
- Download
- Price
- €0+ Pay what you want
How it’s built
Source available
The source is public to read, but not under an open-source license.
No license has been chosen yet.
- App
- Tauri 2
- Rust
- React
- TypeScript
- Vite
- Isolation
- Sandboxed decoder workers
- macOS system sandbox
- Content-Security-Policy
Architecture
A Tauri 2 desktop app: a React and TypeScript interface running in the system webview, and a Rust backend that owns everything touching the disk. The split is deliberate — the interface is where untrusted names and previews get displayed, so it's also the part given the least power. File bytes only reach it through a custom mori:// protocol.
Threat model
Mori assumes media from an unfamiliar drive may be malformed or deliberately crafted: image and container bugs, decompression bombs, disguised extensions, symlink tricks, filenames that spoof their own extension. It treats decoding itself as the risky step and keeps that work away from the rest of the app.
Isolated decoding
Images are decoded in short-lived worker processes by memory-safe decoders. A worker receives bytes over a pipe, never a path, and returns a freshly encoded image the host validates. On macOS it enters the system sandbox before reading any input; pixel, memory, input-size and time caps apply everywhere, and a crash or hang fails only that one preview.
Security model
Least privilege first. The interface has no filesystem, shell or HTTP access; its Tauri capability allow-lists only Mori's own commands, and it works with opaque file ids rather than paths. File types come from magic bytes, filenames have control and bidi-override characters replaced before display, and every change to your files passes a backend mutation policy.
Filesystem boundaries
Every file access goes through Rust: the id is looked up in the index, .. and absolute components are rejected, the path is canonicalised and checked against the canonical root (which defeats symlink escapes), and the file is opened without following links.
Indexing & browsing
Opening a drive loads its last index snapshot immediately while a background thread rescans it. Each entry carries a pre-folded search key — lower-cased, accents stripped, Unicode normalised — so "cumpleanos" finds "cumpleaños". Gallery, grid and list are one virtualised view, so folders with tens of thousands of files stay smooth.
Builds & verification
macOS v1.0.1
Not signed with an Apple Developer ID or notarized yet, so macOS warns once. On macOS 15 and later, open it from System Settings → Privacy & Security → Open Anyway; on earlier versions, Control-click Mori and choose Open.
sha256:28bd2e3e44335285e4f4569e02de2dedfe988fbed0f7bb8ade6b62bfd207bb4csha256:8ba7c138955e63f4fc55977045406e1abaf008676489c1761168cc3a9c376affWindows v1.0.1
Not signed with a publisher certificate yet. SmartScreen says "Windows protected your PC" the first time — choose More info → Run anyway.
sha256:010e2a6079cb874bebd795adc061bf6870818f90af4fb2b24036575ceab85b30sha256:f757c9e61c72a85f52115994a5569aad4f0d2b69fc6f1521d04cb09f83ea1a97Linux v1.0.1
sha256:5310b961ea2c2e463a9cbe14d5cca5855311bcdf707183fd529c2ba8c6c86b8dsha256:afb78a2b07ca06eaeac74725079405dc3cc7a3ad528a7edcdbf3fd8299d3759b