Repository navigation
v0.54.0
filex v0.54.0
Self-hosted file manager - Go single binary + multi-framework frontend.
Download a binary below, or pull a Docker image:
docker pull ghcr.io/brf-tech/filex:slim-v0.54.0
docker pull ghcr.io/brf-tech/filex:full-v0.54.0What changed
⚠ Upgrading to 0.54:
- Embedders: update the server with the packages.
@brftech/filex,
@brftech/filex-coreand@brftech/filex-react0.54 need a filex 0.54
server: which files open for editing, the input limits and the version
line come from its capabilities, with no list to fall back on
(API.md).- API clients: the refusals that put an English sentence in
errorput
a code there now, and every refusal carries the server's sentence in
message- show that (API-ERRORS.md). The presigned
S3 multipart upload (POST /api/files/upload/init,/finalize,/abort)
is gone; the staged upload works on every driver
(UPLOADS.md). The notification lists no longer read
lang=: a row comes in the account's language.- Migrations 00096, 00097, 00098 and 00105 run at the first start (the
vault's lock, Web Push devices, a symlink's reason, a webhook's language);
nothing to do by hand.- The desktop app has no language of its own: an install that had
pinned one hands it to its account once, if the account had none.
Added
- Push notifications while filex is closed (#191). Push notifications
on this device in user settings → Notifications (a browser tab, the
installed app, and the app on an iPhone's or iPad's Home Screen, iOS 16.4
or later) sends what the person's bell tells them to that phone or browser
with filex closed: the same kinds, the same mutes and the same digest - an
urgent kind at once, a held kind as its digest - in their language, a tap
opening what the bell would. Web Push (RFC 8030, 8291, 8292) with a VAPID
key made at the first start and stored sealed withFILEX_SECRET_KEY(no
key, no push); only the browsers' push services are accepted as endpoints
(FILEX_PUSH_HOSTSadds one), each row is pushed to a device once however
many servers run, devices are listed and removable, a test push is one
click, signing out forgets the browser, and Admin → Notifications → Push
notifications rotates the key
(NOTIFICATIONS.md → Web Push). - The ONLYOFFICE editor speaks the person's language (#214,
GitHub Discussion #93).
It opened in English for everybody; the server now chooses its language and
regional setting (editorConfig.lang,editorConfig.region) for every
surface that opens it: the administrator's fixed language, else the one the
request names, the language on the person's screen (which the viewer sends),
their account's,FILEX_DEFAULT_LOCALE, English - a language pack's
language too, whenever ONLYOFFICE offers it, and the nearest one it offers
for a regional tag (de-AT→de,zh-HK→zh-TW). External services
→ ONLYOFFICE → Editor language sets Automatic (the default) or one of
the editor's 46 languages for everybody, andFILEX_ONLYOFFICE_LANGpins
it likeFILEX_ONLYOFFICE_URL
(ONLYOFFICE.md → The editor's language). - The vault, encryption level 3, in the explorer (#94). Behind the server's
FILEX_E2E_VAULTswitch (off by default,capabilities.e2e_vault), the
encrypted-folder dialog offers level 3 for a new folder, with its cost and
the pack size (4 MiB or 16 MiB). An unlocked vault lists from its encrypted
index in this tab - the server never hears a path below the vault folder -
opens and downloads by byte ranges of its packs, and takes the write lock
at the first change (upload, new folder, rename, move or copy inside the
vault, delete), committing each change as one generation. A strip says who
writes and counts down both clocks: the person's idle time (1 to 10
minutes, a new row in Settings → Preferences), after which the writer goes
back to read-only, and the 15 minutes after which an unused vault drops
its keys and asks for the password again. The same code runs in the web
app, the desktop app and the embeds (packages/core,lib/e2evault/*,
useE2eVault), held byte for byte to the format's test vectors. An upload
whose name is taken asks first, in the explorer's "already there" dialog,
whether it goes up under the free name (a vault keeps no earlier version,
so nothing is replaced). The folder chooser (Move to, Copy to, an app's
chooser) says which folder is a vault, offers only that vault for what is
inside it and no vault for anything else, and nobody sees the vault's
layout on the storage (v/) as folders - the server's listing now marks a
vault folder (e2e_vault) and a listing inside one (e2e_vault_root).
What the Go writer writes the browser reads, and the other way round:
testdata/vault-goandtestdata/vault-web, frozen fixtures each side opens.
The vault's engine is loaded with the first vault opened or made, not
with the explorer, so the main chunk stays within workbox's 2 MiB
precache limit (lib/e2evault,e2eVaultEngine; a test walks the static
import graph). - Narrow a search on the server (#207).
type(file,diror a kind:
image,spreadsheet...),mime,modified_after/modified_before,
min_size/max_size,under/not_under,ownerandhiddenare
parameters of/api/files/search, the explorer's name search,/api/ai/search,
the MCPfile_searchtool andfilex client search(one flag each), applied
to every candidate before the limit counts it; a value the server cannot read
is a400 bad_filter. Search answers carrytotal, and every hit its
scoreandkind(SEARCH.md → Narrowing a search). - A new link's answer carries its download command (#210).
POST /api/files/share,POST /api/ai/shareand the MCPfile_sharetool return
download_command: thecurland PowerShell lines that fetch the link,
written by the server (-Lfor an S3 redirect,?zip=waitfor a folder,
the PIN as?pin=on the creator's own answer). The share dialog shows both
lines and no longer builds a command itself; an agent passes them on
(SHARING.md → Command line). - The vault's server half, behind a switch (#94). With
FILEX_E2E_VAULT=1(off by default, andcapabilities.e2e_vaultsays
which) the server serves/api/files/e2e/vault/*: a new empty vault made in
one request (folder, key file, generation 1's index, undone if a step
fails), its state and a paged listing of packs and index files with the
server's clock, the write lock (one session at a time, a 60-second lease,
each person's idle time of 1 to 10 minutes, a break by the folder's owner or
an administrator), packs stored whole and once, index files committed only
as the next generation through a temporary file renamed into place and
abandoned after 60 seconds, and the lock holder's garbage collection that
never deletes the three newest generations. The lock lives in the database
(vault_locks, migration 00096) with compare-and-set updates, so several
filex processes on one database agree; its token is kept only as its
SHA-256. Inside a vault folder only that API writes: the explorer, the
queue, the agent API and MCP, archives, apps, the document server's save,
WebDAV, S3, SFTP, FTPS and NFS are refused there (403 VAULT_PATH), and
the key file keeps its vault block and its place (409 VAULT_KEYFILE).vault.create,vault.lock,
vault.unlockandvault.lock_breakare audited,vault.generationand
vault.lockare realtime frames, and thefilexvltmagic joins the
content sniff. BACKEND.md,
CONFIGURATION.md. - Vaults from the command line (#94):
filex decryptreads a vault (level
3) from a copy or straight from the server (filex decrypt docs://Kasa, no
lock,--generation Nfor an older state still kept),filex vault mount
serves one from a WebDAV server on 127.0.0.1 that the system mounts (net
use, mount_webdav, gio or davfs2; no FUSE) - the write lock at the first
change, a commit within 5 seconds of the last write, out after 15 idle
minutes - andfilex vault prunecollects and repacks. They work against
a server with the vault API on (FILEX_E2E_VAULT).
CLI.md. - The vault level's format, written down (#94). Level 3 of end-to-end
encryption - built in this release, behindFILEX_E2E_VAULT(above) - has
a normative format and protocol,
E2E-VAULT-FORMAT.md: equal packs (4 MiB, or
16 MiB chosen at creation) filled with random bytes, an encrypted index of
the whole tree padded with Padmé, keys derived from the folder key with
HKDF so that every key encrypts exactly one plaintext, one writer at a time
under a lock the server keeps (idle after 3 minutes by default, at most 10),
garbage collection by the lock holder, and test vectors from an independent
reference implementation (backend/internal/e2edecrypt/testdata/gen_vault_vectors.mjs,
node:crypto) that the browser, the server and the command line are held
to. The roadmap records the
decisions that replaced its open questions. What the first runs of all
three together settled is in it too: the listing'se2e_vault/
e2e_vault_root, an upload whose name is taken asked about first (a vault
replaces nothing),releasewithlocked_idleonly from a session that
still holds the write lock, and a repack branch of the test vectors
(generations 4 to 6) that holds both writers to one repack layout. access.changedon the live socket (#196). When a grant, a role, a
group, a permission rule, the tenant's encryption policy or an encryption
approval changes, the server tells the people it can concern -
{"type":"access.changed"}to a grant's or a request's person, a group's
members,"scope":"all"to every socket of the tenant the change was made
in (never another tenant's), or to every open socket for a change at the
platform level - and their explorers ask the answers their menus depend on
again. The frame names no path, no person and no reason; a burst is one frame
(REALTIME.md → When access changes).- Every listed link says where it stands (#210).
GET /api/sharesand
GET /api/admin/sharesgive each linkstate:active,expired,
exhausted(its download, visit or upload cap is used up) orrevoked. - Recent, Starred, Shared with me and a tag page and sort on the server
(#207):offset,sort,totalandtruncatedon each,opened_at/
starred_aton the rows; the explorer says when a view holds more than it
loaded and loads the rest on request (BACKEND.md). - The server checks an e-mail address and a username while they are typed
(#209).POST /api/auth/account/checkanswers with the save's own rules and
words, in the reader's language; the profile and the "Add user" form ask it
instead of a copy of the rules in the browser, which had already drifted (it
leta,b@xandada.@xthrough). Whether an address is taken is told only
where the save would tell it (BACKEND.md). GET /api/public/strings(#210): the public pages' sentences
(server.public.*) in one language, for the JavaScript share and
file-request pages (BACKEND.md).share_link_max_daysinGET /api/capabilities(#210): the longest
life a new link made by THIS person may get - the install's ceiling or
their permission rules' Maximum share-link lifetime, whichever is
shorter.- Editing encrypted office documents: the design and a protocol
prototype (#189). Nothing offers it yet. The ONLYOFFICE editor would run
in the browser from its own unchanged files, with only its socket.io client
replaced by a bridge that answers it the way a Document Server does; what
the other editors need goes sealed (a session key under the folder key,
AES-256-GCM, each entry bound to its place in the log and chained to the
one before) through a filex relay that orders it without reading it, gives
the right to write changes only to an editor that has every change before
them, and records who joined, who left and what a save holds. Every bridge
runs the Document Server's lock rules on the same sequence, so the first
request for a paragraph or a range wins everywhere. Who saves is the same
answer in every browser: every 10 minutes while changes are unsaved, on
Save, and by the last writer to leave; unsaved work waits 30 days; a vault
edits alone. filex's half of the prototype is the relay
(backend/internal/e2eoffice, in memory, no route) and the keys and the
log reader (packages/core/src/lib/e2eoffice.ts,e2eofficeSave.ts). The
editor's half - the bridge, the socket.io stand-in and the x2t driver - is
AGPL and is not part of filex: it is the start of an app of its own,
filex-office-editor
(AGPL-3.0-or-later, its own repository and versions), that needs no
Document Server; it has no release yet (E2E-OFFICE.md).
This release has more to it than fits on one page. The rest of the
entry - and every earlier release - is in CHANGELOG.md.
Verify: sha256sum -c checksums.txt
- Documentation - https://docs.filex.sh
- Report a bug - https://github.com/BRF-Tech/filex/issues
- Full changelog - https://github.com/BRF-Tech/filex/blob/main/CHANGELOG.md
- Every release - https://github.com/BRF-Tech/filex/releases
Security advisories
- GHSA-5896-rqg6-cqjr - a forged ONLYOFFICE save callback signed with an editor configuration's token was accepted (Critical, 9.6)
- GHSA-25hj-4g7f-8c2c - a non-owner who could write an encrypted folder could delete its key file history (High, 8.1)
- GHSA-w8mc-47jv-jp74 - the share e-mail sent a caller-supplied link under the instance's mail identity (Medium, 4.1)
All three are fixed in 0.54.0; upgrading is recommended.