Repository navigation
v0.55.0
filex v0.55.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.55.0
docker pull ghcr.io/brf-tech/filex:full-v0.55.0What changed
Added
- Storage plugins from an app store (#215). A store link (or the
store screen's new Storage plugins tab, through a request and its
approval) installs a storage plugin the store lists: the review reads the
release's ownfilex-storage.jsonthe store reviewed, holds this server's
build to the store's pin and says - in the reader's language, from the
server - that the plugin is a program running with filex's rights outside
any sandbox, what the store's plugin validator measured and on which
platform, and whether the build's signature satisfies
FILEX_PLUGIN_TRUSTED_KEYS(refused when it must and cannot); Install
downloads the build, refuses other bytes before anything runs and installs
it as a binary plugin, which filex starts and probes as any other, keeping
its repository as its source. A paid storage plugin's license is the
store's, kept under its own row and checked daily; while it does not hold
the plugin is held (new state: nothing runs, its storages do not open,
nothing is removed), with License… on its row. The plugin list says
which store a plugin came from (from_store,license). The store screen's
row states are the server's answer (state), and every refusal of a
storage link is the server's sentence (detail.kind: "storage"). The
Storage plugins tab has the store screen's own audience; a store lists only
self-contained builds (linux/amd64andlinux/arm64required,windows/*
anddarwin/*optional and signed when present). Newfilex plugin-validator
command: the network-less conformance runner a store uses
(PLUGINS.md → Installing from a store,
CLI.md). - A frame of its own package and
blob:reads for an app's interface
(#189). Two narrow exceptions to an interface's sandbox, for an editor
that runs in the browser.ui.frame_package(permission
ui:frame-package) lets the interface open pages of its own package in
frames of its own: this version's pages only -frame-srcandchild-src
name the package's path, neverdata:,blob:, another app, a page of
filex or the network - each served under the same policy, as an opaque
origin of its own, with the script that removes WebRTC; filex's bridge
still answers only the frame filex drew. Every interface page now carries
noframe-ancestors(it was*, which does not match the opaque origin
of an interface framing its own page - Chromium refused it), and filex's
security-headers middleware adds none to them.ui.connect_blob(permission
ui:connect-blob) putsblob:inconnect-src, so the interface reads a
blob:address it made withfetchorXMLHttpRequest; nothing else
opens. Both are off unless the manifest asks, derived like the interface's
other permissions and part of the module's described interface, shown in
the install review in the administrator's language, and an update that
adds one stops at the review. An app that asks needs filex 0.55
("filex": ">=0.55.0"): an older filex refuses the field. The office
editor app needs both - ONLYOFFICE's editor opens its page in a frame and
loads the document from ablob:address
(APP-PLUGINS.md → What the review shows,
APP-PLUGINS-API.md → An app's own interface). - Printing for an app's interface:
ui.print(#189). A sandboxed
frame may not open the browser's print dialog, so an interface with the new
ui.print(permissionui:print, the same kind asui:download- the
print dialog can save the PDF) hands filex a PDF and filex prints it from a
page of its own,GET /_print/: its policy frames only theblob:PDF it
makes from the bytes posted to it, and filex's pages frame it by path
beside/_appui/and/z/(theirs still frame noblob:). filex asks
every time, and the print dialog opens on the person's click on the
question's Allow, a button of the print page itself; at most 64 MiB
(LIMITS.maxPrintBytes),%PDF-bytes only;fx.print(name, pdf)in
@brftech/filex-app-ui. Where the web component runs in another site, that
site needs to be inFILEX_FRAME_ANCESTORSfor its apps to print
(CONFIGURATION.md → Security headers and framing).
An app that asks needs filex 0.55
(APP-PLUGINS-API.md → Printing a PDF). - An app's interface is told when a file is end-to-end encrypted
(#189). Every file row the server answers with says it - the folder
listing, the explorer's search and/api/files/search, Recent, Starred, a
tag view, Shared with me, a file's own/api/files/statand the id-based
listing:encrypted: "folder"inside an encrypted folder,"vault"inside
a vault,"file"for a single encrypted file (.fxe), by one server rule -
and an app's interface reads it asFileInfo.encrypted, whichever of those
views it was opened from; a plain file and a folder row carry no such field.
The server says it, no client guesses it. It is information: filex 0.55
decrypts nothing for an app. Shared with me rows also saye2e_rootnow, as
the other views' rows do, and an encrypted file in any of those views is
offered no app ("Open with", an app's action) and no ONLYOFFICE, as in its
folder
(APP-PLUGINS-API.md → session.get). - Editing together in the app SDK, defined (#189). The interface
bridge knowscoedit.join,coedit.subscribe,coedit.append,
coedit.lease,coedit.cursor,coedit.blob.put/coedit.blob.getand
coedit.leave, their events (coedit.entry,coedit.cursor,
coedit.dropped) andfile.save'sthrough, so the office editor app can
be written against them (fx.coeditin@brftech/filex-app-ui); filex
0.55 offers no relay yet and answers eachunavailable
(APP-PLUGINS-API.md → Editing together). - The test chain can move what else its host runs out of the way (#194).
CHAIN_PAUSE_CMDruns oncescripts/chain/run.shholds the build lock,
before the run measures the memory it may take, and when it succeeded
CHAIN_RESUME_CMDruns once when the run ends - green, red or stopped by a
signal - for a hand run, a CI run and the nightly run alike. A pause that
fails is logged and the run goes on;result.jsonhost.pauseand the
morning report say what it did
(CONTRIBUTING.md → The whole chain on one Linux host).
Changed
- The snap is built on core24 (#68). The Snap Store package
filex-app
moves from thecore20base tocore24(Ubuntu 24.04) with Snapcraft's
GNOME extension, on x64 and arm64: the first install also brings the GNOME
46 runtime, the graphics libraries and the GTK themes as shared content
snaps. It stays strictly confined, asks for the same interfaces (no
allow-sandbox) and still opens through X11 (XWayland on a Wayland
desktop). The desktop packages are built with electron-builder 26 (from
24), on Node 22; the installers, their names and the update feeds are
unchanged (DESKTOP.md → The snap and the sandbox).
The.deband the.rpmkeep electron-builder 24's install script: the
sandbox helper stays setuid, as every version since 0.50 opened with
(electron-builder 26's would have swapped it for an AppArmor profile).
The AppImage keeps electron-builder 24's entry point: 26's adds
--no-sandboxby itself where it cannot create a user namespace, so on
Ubuntu 23.10 and later without the AppArmor profile the image would have
opened with Chromium's sandbox off instead of saying what to do
(DESKTOP.md → AppImage on recent Ubuntu). - Every release now updates the previous one before it ships (#68). On
real Windows (x64 and arm64) and Ubuntu (x64 and arm64) machines, the
previous release's installer,.deb, AppImage and snap are installed and
opened, and the new release is installed over them the way the app updates
itself; it must leave one copy, of the new version, in the same place, with
the app's data folder the old copy wrote (DESKTOP.md → Updates). - The screenshots show 0.55's new screens (#215, #189). The store scene
takes the store screen's Storage plugins tab and a storage plugin's store
review (the review only from a store served over https, as the build
host's test chain serves it); a new scene takes the question filex asks
before an app's PDF is printed. Each in English and
Turkish, light and dark, at 1280 and 390 px, measured for fit. A page can
name a picture before it is published (<!-- shot: <name> | <alt> -->):
publishing it turns the line into the picture
(e2e/shots/README.md). - The office editor's page says what the app does on a phone and how it
prints (#189): ONLYOFFICE's open-source phone apps only read, so a phone
opens the document to read and Edit opens the folded desktop editor;
Print goes through filex'sui.print
(E2E-OFFICE.md).
Fixed
- A rename or delete over WebDAV, SFTP, FTPS, NFS, the S3 gateway or the AI
surface no longer loses rows to a storage scan running beside it (#201).
0.54 gave each storage a row gate that the queue and the explorer's rename
and move hold from the first byte to the last row (#192); the protocol
servers, the AI and MCP move and delete, the explorer's delete, saving and
discarding a draft (into the trash, or for good on a storage that keeps
none), a restore made inside the request, a cross-storage
move's source delete and the antivirus quarantine made their two steps
without it. A scan between them could drop a moved row with its shares,
versions and comments, or a trashed row with the trash entry it could be
restored from. Every protocol server now goes through one shared frame
(protocolsyncRelocate,Discard,Purge), and the other surfaces hold
the gate the same way (ARCHITECTURE.md, "The row
gate"). - New document no longer types its suggestion over the name being typed.
The dialog fills the name field with the server's first free
Untitled.<ext>once its dry run answers; on a slow server that answer
could arrive after the first keystrokes and replace them mid-word
(Untitled.txtnutes.txt). A suggestion now only fills a name nobody has
typed. - A file in a vault names its owner, not "System" (#94). Every row inside
a vault is the vault folder's - the server knows no file in it and the index
records no author - and the explorer drew them with no owner, which the
Owner column says as "System", the word for a file nobody put there through
filex. The vault'sstateandcreateanswers now carry the folder's
owner_id,owner_nameandowner_self, and every row in the vault shows
them. - The trash restore and an app on a read-only storage say the server's
sentence (#209). Restoring onto a name that is taken now answers the one
refusal shape (409 name_takenwith its sentence in the reader's language;
code: EXISTS,nameandpathstay), and the admin Trash page shows the
server'smessagefor every refusal instead of a sentence of its own or the
code inerror. The explorer no longer words an app action's refusal
itself: a read-only storage (read_only) and a selection the action does
not apply to (422 not_applicable, whose sentence was English for every
reader and is now the server's) are said in the server's words. - An app's refusals and every app store refusal are said in the server's
sentence (#209). An app's run, screen and save doors answered
permission_denied,encrypted,not_found,handler_off,not_granted
andnot_applicablewith an English sentence of their own for every reader
("insufficient permission: docs/a.txt", "plugins cannot read files in an
encrypted folder"); the codes stay andmessageis now the reason in the
reader's language, and a path outside a folder-limited key is said the same
way on every door. A store link's refusal (an app's or a language pack's,
the trust, the connection, a license key) carried English as well, and the
admin panel threw it away for a copy of its own built from the code; the
server now writes it, withdetail.kindand its English detail in
detail.reason, and the panel prints it
(API-ERRORS.md). A plugin
request's refusal (the store screen's request, the Requests panel) is the
server's sentence as well, and the store screen's own copies of "too many
requests" and "installed already" are gone. - The Apps and Storage plugins lists say an update's state in the server's
sentences (#209). A newer version that needs another filex, what an
approval adds, an update undone, no source to check, an installed app
outside its range and the version kept to go back to were lines the panel
built from the row's fields (deciding there too which one a row got); the
list answers them inupdate_said,compat.messageandprevious.message,
in the reader's language and on their clock, and the panel prints them. A
storage plugin's source that could not be read is said too instead of the
check's English error, and the Apps tab's header (apps on or off, the
processor, signed apps only, a development build, the update check and its
last run) comes from the server asruntime.said. - The install review says an app's filex range in the server's sentence
(#209). A range that leaves this filex out was a sentence the install wizard
built fromcompat.requiresandcompat.filex; the dry run now answers it
incompat.message, in the reader's language, and the wizard prints it. - An app's install, upgrade and update refusals, and the refusals a request
cannot be read with, are said by the server too (#209). The install wizard
and the Apps list built an install refusal's sentence themselves
(fetch_failed,manifest_invalid,permissions_incomplete,
incompatible…); the server now writes it inmessagein the reader's
language, with its English indetail, and says an update check's stored
refusal again for whoever reads the list. The app, store, plugin request,
storage plugin and Default apps doors no longer answer an English phrase or
Go's error text: a body that is not JSON, no file or too many, a storage
that is not there, a full job queue, a chunked save's offset, a server fault
(internal_error), the host's own refusals in an app call (busy, timeout,
out of memory), the session gates, a Default apps rule, a storage plugin's
failed install and the platform operator's gate on every admin door
(supertenant_only) each carry a code and the server's sentence
(API-ERRORS.md). Some codes that were English phrases
are codes now (bad json->bad_json,too many paths->
too_many_paths,paths are required->paths_required,ops queue unavailable->queue_unavailable,bad id->bad_id, a storage
plugin's install error ->install_failedwith the reason indetail). - A store link opened after the session ended comes back to the store page
after the sign-in (#199). The panel went to the sign-in page the moment a
request was refused, while it still believed in the session; the sign-in
page sent that "signed-in" reader on to Home, whose own refusal named Home
as the place to come back to, and the link was lost. A refused request now
asks the server whether the session is over first: if it is, the sign-in
page names the page you were on, with nothing in between; if it is not (a
wrong current password, a one-time code), you stay where you are. - "Delete permanently" in the Trash no longer closes having deleted
nothing (#199). Every listing of the trash cleared the selection, so a
refresh that arrived while the confirmation was open (a live update, the
Refresh button) left it nothing to delete. A reload of the trash on screen
keeps what was selected. - The app SDK no longer promises an app the plaintext of an encrypted
file (#189).FileInfo.encryptedsaid filex decrypts in the browser and
encrypts the save; filex 0.55 does neither for an app. The interface now
getsreadOnly: truefor such a file and itsfile.saveis answered
read_onlyin the frame (@brftech/filex-app-uiprotocol,
APP-PLUGINS-API.md). - A table narrower than its words cuts them cleanly. A column header too
narrow for its name ends in an ellipsis instead of stopping mid-letter
("Store che"), and a sortable header's tooltip names the column ("Sort by
Store checks"). A pill in a cell (a request's "Waiting", "Installed", the
explorer's lock and link badges) keeps its border and dot and shortens its
words inside it, with the whole text on hover, instead of running out
through its edge. The frozen Actions column draws its edge while columns
continue beneath it, so a column cut there reads as one that goes on. One
fix in the shared table, so every table has it.
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