Compare commits

...

1205 commits

Author SHA1 Message Date
Henrique Dias
833d908884
docs: update post link 2026-07-28 07:53:06 +02:00
Henrique Dias
1cd18d7ead
docs: include issue summary in readme 2026-07-27 22:04:46 +02:00
Henrique Dias
e8a388f840
chore(release): 2.63.23 2026-07-27 21:50:03 +02:00
Henrique Dias
0dfe44649c
docs: cleanup header 2026-07-27 21:49:14 +02:00
Henrique Dias
05ee853eef
docs: clear inconsistencies, point at repo instead of website 2026-07-27 21:47:58 +02:00
Henrique Dias
afeb478ee1
chore(release): 2.63.22 2026-07-27 17:29:26 +02:00
Henrique Dias
df2869993a
chore: remove renovate.json 2026-07-27 17:29:12 +02:00
transifex-integration[bot]
d49ab67904
chore: update translations 2026-07-27 17:24:27 +02:00
superafun
cfff84306a
fix: use absolute URLs for the PWA manifest icon sources (#6032) 2026-07-27 17:23:54 +02:00
Henrique Dias
72faf6dd3c
fix: enforce rules on recursive operations and expired proxy tokens (#6053) 2026-07-27 17:16:58 +02:00
superafun
a789f29cee
fix: make the sidebar scrollable when content overflows (#6031) 2026-07-27 17:10:57 +02:00
Henrique Dias
74b13db3fa
docs: fix date 2026-07-27 17:02:02 +02:00
Henrique Dias
773b30102c
docs: add wind down notice 2026-07-27 16:58:50 +02:00
Henrique Dias
0b925cbca9
fix: unblock stalled and frozen uploads
A TUS PATCH rejected before its body was read left the client still streaming
a chunk. net/http gives up draining an unread request body after 256KiB and
then closes the connection, so the status we replied with was lost and the
browser saw a bare transport error instead. The client could not tell a
conflict from a network fault, retried blindly, and the upload stalled after
the first chunk — while curl, which reads the response as it writes, still
reported the status and appeared to work. Drain what is left of a rejected
chunk so the answer arrives on a connection that stays usable. The explicit
r.Body.Close() had to go with it: it ran before the drain, and the server
closes the request body itself once the handler returns.

Pressing Upload awaited a recursive listing of the whole destination subtree
before a single byte was sent, with no sign that anything was happening. On a
large destination that reads as a dead button, and the walk kept running after
the client gave up, then reported the failed write as a 500. A flat upload can
only collide with a direct child of the destination, so walk recursively only
for folder uploads, stop the walk once the request is done, and show the action
as busy while the destination is checked.

Along the way: a failed upload was credited as fully sent, so the progress bar
reported 100% when nothing had been written; the progress timer was recreated
without clearing the previous one; and the chunk size field threw on a value
with no unit and raced its own debounce on submit, so it appeared to refuse
every change.

Fixes #6006
Refs #5987
2026-07-27 16:28:17 +02:00
renovate[bot]
9dd7c7d099
chore(deps): update dependency postcss to v8.5.18 [security] (#6047) 2026-07-27 07:47:17 +02:00
Henrique Dias
b24e43b06c
chore: fix renovate.json order 2026-07-27 07:42:09 +02:00
renovate[bot]
91e68edb8c
chore(deps): update dependency dompurify to v3.4.12 [security] (#6046) 2026-07-27 07:41:48 +02:00
Henrique Dias
ac11538f08
chore: update renovate.json 2026-07-26 22:41:19 +02:00
Henrique Dias
f6fb8f6bf5
chore(release): 2.63.21 2026-07-26 10:02:11 +02:00
Henrique Dias
e6d70cf24c
fix(http): canonicalize paths before checking access rules (#6045) 2026-07-26 10:00:18 +02:00
Henrique Dias
41e2b1bbba
docs: update CLAUDE.md 2026-07-26 09:58:40 +02:00
Henrique Dias
41b01a7404
chore: update Go deps 2026-07-26 08:01:32 +02:00
Henrique Dias
0dd8905886
Revert "chore(deps): update all non-major dependencies (#5946)"
This reverts commit 032271bafa.
2026-07-26 08:00:07 +02:00
renovate[bot]
032271bafa
chore(deps): update all non-major dependencies (#5946) 2026-07-26 07:58:26 +02:00
Henrique Dias
50125a5d21
chore(release): 2.63.20 2026-07-25 22:16:14 +02:00
Henrique Dias
bc3d75a94a
test(users): cover concurrent provisioning into one scope
Two usernames that normalize to the same home directory must not both be
provisioned when their requests are handled concurrently. Also cover that
an explicit, non-derived scope may still be legitimately shared.

Refs GHSA-j7jh-37pf-mf8h
2026-07-25 22:15:35 +02:00
Henrique Dias
fb6aeba9ea
fix(users): make the provisioned scope check atomic with the save
The check that stops two usernames normalizing to the same home directory
ran as a storage operation separate from the save, so two first-time users
provisioned concurrently could both observe a free scope and both be saved
into it, ending up sharing one home directory.

Move the check into users.Storage.SaveProvisioned, which holds a single
lock across the lookup and the save, and reduce CreateUserHome to deriving
and creating the directory. This covers all three provisioning paths:
signup, proxy auth and hook auth.

Refs GHSA-j7jh-37pf-mf8h
2026-07-25 22:15:27 +02:00
Henrique Dias
67e893eee7
fix: use aria-selected 2026-07-25 22:09:01 +02:00
Henrique Dias
4a4b0f8c84
docs: update CLAUDE instructions 2026-07-25 22:03:33 +02:00
Henrique Dias
660d84661d
docs: update CLAUDE.md 2026-07-25 08:47:34 +02:00
Henrique Dias
392253c563
docs: update SECURITY.md and add CLAUDE.md 2026-07-25 08:42:52 +02:00
Henrique Dias
328f629181
chore(release): 2.63.19 2026-07-25 08:19:11 +02:00
Henrique Dias
4c3cb4bc9b
test(http): cover TUS Upload-Length enforcement
Refs GHSA-ffv3-7h97-993q
2026-07-25 08:16:19 +02:00
Henrique Dias
3213b605be
test(http): cover scope-safe removal on TUS upload eviction
Refs GHSA-m9f5-2232-frp6
2026-07-25 08:16:19 +02:00
Henrique Dias
610e0b09e9
test(http): cover download-permission gate on the checksum branch
Refs GHSA-7whw-q6gh-xr59
2026-07-25 08:16:19 +02:00
Henrique Dias
7453c78c98
test(storage): cover case-insensitive GetByScope matching
Refs GHSA-576v-w77m-gr84
2026-07-25 08:16:18 +02:00
Henrique Dias
cd5749dff8
test(auth): cover per-user scope isolation for proxy and hook provisioning
Unit tests for Settings.CreateUserHome (derives a per-user home, rejects a
colliding scope, preserves an explicit scope) plus proxy and hook regression
tests asserting that with CreateUserDir enabled two provisioned users receive
distinct home directories instead of the server root.

Refs GHSA-j7jh-37pf-mf8h, GHSA-j2fc-28fx-hc8q
2026-07-25 08:16:18 +02:00
Henrique Dias
4daddec6f2
fix(http): enforce declared Upload-Length on TUS uploads
The TUS PATCH handler copied the whole request body to disk and used the
declared Upload-Length only to decide when the upload was complete. A client
could declare a tiny Upload-Length and then stream an arbitrarily large body
in a single PATCH, writing it all to disk, so any user with create permission
could exhaust the filesystem.

Bound each write to the bytes still expected (Upload-Length - Upload-Offset),
reject a PATCH whose offset already exceeds the declared length, and roll back
and reject a body that exceeds it. This complements the existing negative
Upload-Length handling.

Refs GHSA-ffv3-7h97-993q
2026-07-25 08:16:18 +02:00
Henrique Dias
9bd79c3aae
fix(http): delete abandoned TUS uploads through the scoped filesystem
The in-memory upload cache deleted expired incomplete uploads with a raw
os.Remove on the absolute path it had stored, bypassing ScopedFs entirely.
Because the stored path is only lexically cleaned (no symlink evaluation) and
os.Remove resolves symlinked parent directories, a Create-only user could
register an upload and then, within the 3-minute TTL, swap an in-scope
ancestor directory for a symlink so the eviction deleted an arbitrary file
outside their scope.

Carry a removal callback with each cache entry and invoke it on eviction
instead of os.Remove. For TUS uploads the callback deletes via the uploading
user's scoped filesystem, whose Remove is guarded by the same within() check
that CVE-2026-55667 added, so eviction can no longer follow a symlink out of
scope. The redis backend ignores the callback (it never deleted partial files).

Refs GHSA-m9f5-2232-frp6
2026-07-25 08:16:18 +02:00
Henrique Dias
6c69b5cd89
fix(http): enforce download permission on the checksum branch
The ?checksum= branch of the resource GET handler read the whole file to
compute its digest and returned it without checking Perm.Download, unlike the
sibling raw, preview, subtitle and X-Encoding paths. A user provisioned with
Perm.Download=false could therefore obtain md5/sha1/sha256/sha512 digests of
files they are not allowed to download, giving a file-content hash oracle, and
force a full-file read.

Return 202 Accepted before computing the checksum when the user lacks
Perm.Download, matching the other read paths. This completes the fix for
CVE-2026-35606, whose original patch gated only the content-returning paths.

Refs GHSA-7whw-q6gh-xr59
2026-07-25 08:16:18 +02:00
Henrique Dias
4b8a8d72ce
fix(storage): reject case-folded home directory collisions
GetByScope compared scopes with a case-sensitive exact match, so on a
case-insensitive filesystem two accounts whose scopes differ only in case
(e.g. /users/CaseVictim and /users/casevictim) were treated as distinct even
though both resolve to the same physical home directory. The second account
could then read, overwrite and delete the first account's files.

Match the scope case-insensitively so the collision check performed during
signup, proxy and hook provisioning catches these aliases and rejects the
duplicate.

Refs GHSA-576v-w77m-gr84
2026-07-25 08:16:18 +02:00
Henrique Dias
8ddd3d1db9
fix(auth): isolate auto-provisioned proxy and hook users to their own home
Proxy- and hook-authenticated users were auto-provisioned by applying the
default scope (".") and passing it straight to MakeUserDir, which normalizes
"." to "/". With CreateUserDir enabled, every provisioned user therefore
received the server root as its scope instead of a per-user home directory,
letting one user read, overwrite and delete another user's files.

The signup handler already cleared the scope before deriving the home
directory. Centralize that logic into Settings.CreateUserHome (clear the
scope when CreateUserDir is on and no explicit scope was supplied, derive the
home dir, then reject a scope already owned by another user) and use it from
signup, proxy and hook auth so the three provisioning paths cannot diverge.

Refs GHSA-j7jh-37pf-mf8h, GHSA-j2fc-28fx-hc8q
2026-07-25 08:16:15 +02:00
Henrique Dias
9fffee387f
docs: remove go report 2026-07-25 08:00:00 +02:00
Henrique Dias
5a12cad548
docs: update readme 2026-07-25 07:52:21 +02:00
transifex-integration[bot]
6232686e22
chore: update translations 2026-07-25 07:30:18 +02:00
superafun
b21b1245ae
fix: accessibility and security improvements (#6033) 2026-07-25 07:30:02 +02:00
Archit Goyal
7361d91ea2
fix(upload): handle encoded path conflicts safely (#6040) 2026-07-25 07:29:49 +02:00
Henrique Dias
c05c668148
fix: process --FollowExternalSymlinks 2026-07-25 07:25:26 +02:00
Henrique Dias
b7dc392838
docs: fix typo 2026-07-21 19:18:51 +02:00
TowyTowy
ac46cf0671
fix: return error instead of panicking on an unreadable directory during copy (#6020)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 07:21:44 +02:00
transifex-integration[bot]
f0785391bf
chore: update translations (#6019)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-07-18 07:20:43 +02:00
tianrking
9b78324d77
fix(http): run upload hooks for directories (#6034) 2026-07-17 20:14:41 +02:00
Henrique Dias
fe7efb2e6a
chore(release): 2.63.18 2026-07-04 08:25:01 +02:00
transifex-integration[bot]
2651260a1c
chore: update translations 2026-07-04 08:24:37 +02:00
Henrique Dias
4470288ba1
fix: deduplicate PT language 2026-07-04 08:24:17 +02:00
Henrique Dias
58d22578e8
chore: update dependencies 2026-07-04 08:23:16 +02:00
林桉
dfc2e887e1
fix: avoid recursive conflict checks for copy and move (#6009) 2026-07-04 08:13:31 +02:00
Aditya Raj Singh
aac2516637
fix(preview): keep the EPUB table-of-contents button clear of the header (#6010) 2026-07-04 08:09:10 +02:00
Henrique Dias
c05ead7e8e
docs: warning about hook executor 2026-06-27 09:37:29 +02:00
Henrique Dias
d76b7d1610
chore(release): 2.63.17 2026-06-27 09:14:08 +02:00
Henrique Dias
f30fca636c
fix(share): delete exact directory share on trailing-slash delete (GHSA-pp88-jhwj-5qh5)
DeleteWithPathPrefix queried the share index with the raw path, so deleting a
directory through a trailing-slash path (e.g. DELETE /api/resources/a/) only
matched descendants like /a/child and missed the exact /a share, leaving it in
storage. If the same path was later recreated, the stale public share re-exposed
the new content. Normalize the path before the prefix query so the exact share
and its descendants are both removed. Adds a regression test.
2026-06-27 09:08:57 +02:00
Henrique Dias
ec13054671
fix(share): stop exposing password hash and bypass token in share API (GHSA-833g-cqhp-h72j)
The share management endpoints serialized the storage struct directly, returning
the bcrypt password_hash (crackable offline) and the bypass token for every
share an authenticated caller could list, with admins seeing them for all users.
Return a response DTO that exposes only whether a share is password-protected
(hasPassword) and drops both secrets. The storage struct keeps its tags so the
secrets stay persisted and the server-side auth/public flows are unchanged.
Updates the frontend to use hasPassword and adds a regression test.
2026-06-27 09:08:56 +02:00
Henrique Dias
883a36f02f
fix(auth): reject signup when normalized home dir collides (GHSA-7rc3-g7h6-22m7)
cleanUsername is many-to-one, so distinct usernames (e.g. "teamone/x" and
"teamone-x") can normalize to the same home directory. With CreateUserDir
enabled, the second registrant silently reused the first user's directory,
breaking per-user isolation. Add a GetByScope lookup and reject a signup whose
derived scope is already taken. The check is gated on CreateUserDir: when it is
off, signups intentionally share the configured default scope. Adds a regression
test for the colliding-username case.
2026-06-27 09:08:56 +02:00
Henrique Dias
8503ba61ff
fix(raw): neutralize backslashes in archive entry names (GHSA-83xp-526h-j3ww)
The fix for CVE-2026-54093 rewrote backslashes to the path separator "/" in
archive entry names. On POSIX hosts a backslash is a legal filename byte, so
that rewrite manufactured a traversal sequence ("..\..\x" -> "../../x") out
of a single in-scope file, turning a Windows-only zip-slip into a cross-platform
one. Neutralize backslashes to an inert character instead, and reject any entry
whose name is not already a normalized root-relative path. Adds a regression
test that downloads a folder containing a backslash-named file as a zip.
2026-06-27 08:39:14 +02:00
Henrique Dias
1fb05d65de
docs,cmd: warn about broad scope for self-signup users (GHSA-6759-996p-gpj6)
When Signup is enabled with the default scope and createUserDir off, every
self-registered user inherits the served root and can read/modify/delete all
files. Add a startup WARNING for this configuration and document the risk and
the --createUserDir mitigation. No behavior or default change.
2026-06-27 08:18:18 +02:00
Henrique Dias
2472fbcd30
fix: normalize recursive listing paths to forward slashes (#6003) 2026-06-27 08:01:26 +02:00
JinHyuk Sung
43a404ca69
fix: match admin share paths by owner scope (#5992) 2026-06-27 07:43:22 +02:00
Rayan Salhab
d9cf2f0100
fix: preserve SRT subtitle line breaks (#6002) 2026-06-27 07:28:55 +02:00
transifex-integration[bot]
6209f8fddd
chore: update translations (#5990) 2026-06-27 07:19:42 +02:00
Henrique Dias
bd1520fe09
chore(release): 2.63.16 2026-06-23 13:33:10 +02:00
Henrique Dias
8cfa6a175f
chore(docs): update CLI documentation 2026-06-23 13:33:00 +02:00
Henrique Dias
a1063925e1
fix: restore symlink behavior as opt-in followExternalSymlinks 2026-06-23 13:19:51 +02:00
Henrique Dias
64511ce45e
fix: dangling symlink, write, delete scope bugs 2026-06-23 12:35:55 +02:00
Henrique Dias
be23ab3a15
chore(release): 2.63.15 2026-06-13 07:20:45 +02:00
Henrique Dias
ffb486e05f
chore: bump minor Go dependencies 2026-06-13 07:19:01 +02:00
yfzhou
403d2bbd33
fix: restore ScopedFs RealPath (#5986) 2026-06-13 07:17:48 +02:00
Henrique Dias
dfe6e5b333
chore(release): 2.63.14 2026-06-07 18:21:40 +02:00
Henrique Dias
d9816b1531
chore: add symlink tests 2026-06-07 18:21:13 +02:00
Henrique Dias
7c2c0a11b3
refactor: ScopedFs to avoid escaping symlinks 2026-06-07 18:16:46 +02:00
Henrique Dias
3406d3d7f9
fix: recursive check 2026-06-07 17:12:31 +02:00
Henrique Dias
67ed670d92
chore(release): 2.63.13 2026-06-06 08:33:27 +02:00
Henrique Dias
a1a514dcbb
fix: copy/move allow overwrite 2026-06-06 08:28:31 +02:00
Henrique Dias
5f7311d324
refactor: cleanup and simplify upload.ts 2026-06-06 08:15:16 +02:00
Henrique Dias
998bd95bfa
chore(release): 2.63.12 2026-06-04 17:17:38 +02:00
Puneet Dixit
c1abe8f561
fix: await copy move conflict detection (#5978) 2026-06-04 17:16:30 +02:00
Puneet Dixit
0bb2768754
fix: keep mobile file sort controls visible (#5977) 2026-06-04 12:49:30 +02:00
Puneet Dixit
7b7ff8ae8f
fix: skip inaccessible children when listing directories (#5958) 2026-06-04 12:49:07 +02:00
Henrique Dias
1086903c14
chore(release): 2.63.11 2026-06-04 11:03:17 +02:00
Henrique Dias
3471ec2c4b
fix: incomplete fix for symlinked directories let scopes users and public-share recipients read and write files outside of scope 2026-06-04 11:02:18 +02:00
Henrique Dias
69c76d11cc
chore(release): 2.63.10 2026-06-03 15:42:27 +02:00
Henrique Dias
6b04cbf5e9
fix: allow writes when user scope resolves to filesystem root
WithinScope compared targets against root+separator, which produced
"//" when the scope resolved to "/". No path matched, so every write
was rejected with os.ErrPermission (HTTP 403), breaking saves and
uploads for root-scoped installs. Skip the appended separator when root
already ends in one.
2026-06-03 15:40:26 +02:00
Henrique Dias
503fd6b01f
chore(release): 2.63.9 2026-06-03 13:13:03 +02:00
Henrique Dias
35db07d015
fix: set X-Content-Type-Options: nosniff on raw file responses
Prevents browsers from MIME-sniffing uploaded files into a renderable type.
2026-06-03 12:21:23 +02:00
Henrique Dias
19514367ad
fix: use constant-time comparison for share access token
Compare the share token with subtle.ConstantTimeCompare instead of ==.
2026-06-03 12:21:23 +02:00
Henrique Dias
cdd666fc95
fix: prevent symlink scope escape in copy/move/rename
Check WithinScope for src and dst in resourcePatchHandler before
fileutils.Copy/MoveFile, which follow symlinks and bypassed the
stat()/writeFile() guards (GHSA-239w-m3h6-ch8v).
2026-06-03 12:21:23 +02:00
mehmet turac
103acd15fe
fix: force octet-stream for attachment downloads (#5942) 2026-06-03 11:59:17 +02:00
Henrique Dias
f5e0c4e2e1
chore(release): 2.63.8 2026-06-03 11:57:30 +02:00
Henrique Dias
ca019ae7d9
fix: check if share is within scope when creating 2026-06-03 11:57:10 +02:00
Henrique Dias
4488f5b131
chore(release): 2.63.7 2026-06-03 11:44:54 +02:00
Henrique Dias
166583db63
fix: disallow shares for non-existent paths 2026-06-03 11:43:22 +02:00
Henrique Dias
85b7d2762d
chore(release): 2.63.6 2026-06-03 11:31:10 +02:00
Henrique Dias
4edabb9ccc
chore(docs): update CLI documentation 2026-06-03 11:30:59 +02:00
transifex-integration[bot]
103683069e
chore: Updates for project File Browser (#5947) 2026-06-03 11:25:04 +02:00
Ariel Leyva
5328e80d2e
fix: parse csv files with uneven columns in their rows (#5965) 2026-06-03 11:22:05 +02:00
Henrique Dias
847d08bdd1
fix: address three security disclosures (archive traversal, login DoS, symlink escape)
- http/raw.go: strip Windows backslash separators from archive entry names
  on any host. filepath.ToSlash is a no-op for "\" on Linux, so a stored
  backslash filename was emitted verbatim and could escape the extraction
  directory on Windows extractors (zip-slip). (GHSA-gxjx-7m74-hcq8)

- http/auth.go: cap the login and signup request bodies with
  http.MaxBytesReader (1 MiB). The JSON decoder previously read an
  arbitrarily large password into memory before bcrypt truncated it,
  enabling unauthenticated memory-exhaustion DoS. (GHSA-w5fm-68j4-fpc4)

- files/file.go, http/resource.go: add files.WithinScope and refuse to
  follow a symlink whose on-disk target escapes the user's scoped root,
  on both the read path (stat) and the write path (writeFile). Prevents a
  scoped user from reading/overwriting/sharing files outside their scope
  via a pre-existing escaping symlink. (GHSA-239w-m3h6-ch8v)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 11:21:00 +02:00
Henrique Dias
0231b7ebdf
fix: cross-user unauthorized share-link deletion 2026-06-03 10:31:44 +02:00
Henrique Dias
e07c59df0b
fix: incorrect access control in public directory shares via rule path rebasing 2026-06-03 10:24:05 +02:00
Henrique Dias
0d3eb9bea9
docs: clarify hide dotfiles 2026-06-03 10:20:12 +02:00
Henrique Dias
34ae34e764
fix: remove undocumented hook auth with shell replacement 2026-06-03 09:59:36 +02:00
Henrique Dias
ca0108f070
chore: disable automatic major updates 2026-05-21 16:52:04 +02:00
Henrique Dias
a1e442ef9e
chore(release): 2.63.5 2026-05-21 15:42:07 +02:00
Jose Olcese
6ad8160aa3
fix(router): handle undefined catchAll param on root redirect (#5955) 2026-05-21 15:39:45 +02:00
Henrique Dias
22b848f26e
chore(release): 2.63.4 2026-05-17 15:11:55 +02:00
Henrique Dias
a418dd6bb3
chore: revert node dependencies updates 2026-05-17 15:10:16 +02:00
transifex-integration[bot]
d978d1ecca
chore: sync translations (#5945) 2026-05-17 15:05:08 +02:00
mehmet turac
9cc18a81e3
fix: show item shares from all users to admins (#5941) 2026-05-17 15:01:02 +02:00
Henrique Dias
e38c28273a
chore: fix typo 2026-05-17 15:00:44 +02:00
transifex-integration[bot]
da2dff0933
chore: sync translations 2026-05-17 14:59:45 +02:00
renovate[bot]
261bca67bc
chore(deps): update all non-major dependencies (#5929) 2026-05-17 14:59:19 +02:00
Henrique Dias
ca5e249e3c
chore(release): 2.63.3 2026-05-05 14:26:07 +02:00
Anthony Geourjon
f4e148523e
fix: Fix conflict modal and add a resume transfert option (#5884)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2026-05-05 14:24:06 +02:00
renovate[bot]
1f22fe65ec
chore(deps): update all non-major dependencies (#5926)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-05 14:15:22 +02:00
transifex-integration[bot]
e2bdf6f747
chore: update translations
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-05-05 14:15:09 +02:00
renovate[bot]
d236f1c563
chore(deps): update dependency marked to v18 (#5897)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-28 07:18:13 +02:00
hreczkosiej
4edf425a9f
chore(i18n): add a translation for disk usage (#5916) 2026-04-28 07:14:10 +02:00
transifex-integration[bot]
a1a7ac4f04
chore: update translations (#5918)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-04-28 07:11:49 +02:00
renovate[bot]
74917c8037
chore(deps): update all non-major dependencies (#5915)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-28 07:11:23 +02:00
transifex-integration[bot]
7bd27f5e82
chore: sync translations (#5901)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-04-18 07:50:38 +02:00
Nicholas A. Thompson
9f4288b1b4
docs: Update documentation links in Global.vue (#5905) 2026-04-18 07:49:11 +02:00
savef
41b801d30c
fix: correct environment variable in compose.yaml (#5910) 2026-04-18 07:48:43 +02:00
renovate[bot]
da6b7ac26b
chore(deps): update all non-major dependencies (#5912)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-18 07:48:22 +02:00
renovate[bot]
7f8b920aa4
chore(deps): update actions/upload-pages-artifact action to v5 (#5913)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-18 07:48:08 +02:00
Henrique Dias
dd53644acb
chore(release): 2.63.2 2026-04-11 07:58:44 +02:00
renovate[bot]
9b80a9aa6c
chore(deps): update all non-major dependencies (#5870)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-11 07:54:27 +02:00
transifex-integration[bot]
0321415a15
chore: pull translations (#5871)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-04-11 07:51:05 +02:00
Henrique Dias
23e84c9974
docs: update PR template 2026-04-11 07:50:31 +02:00
Brumaire
0fadf28b18
fix(preview): let arrow keys seek video instead of switching files (#5895) 2026-04-11 07:48:27 +02:00
renovate[bot]
871f337892
chore(deps): update pnpm/action-setup action to v6 (#5898)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-11 07:43:08 +02:00
Henrique Dias
29c73eaca6
chore(release): 2.63.1 2026-04-04 22:15:49 +02:00
kodareef5
f13c7c8cff
fix: restrict default permissions for proxy-auth auto-provisioned users (#5890)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2026-04-04 22:02:34 +02:00
kodareef5
1e03feadb5
fix: check download permission in resource handler (#5891) 2026-04-04 21:58:17 +02:00
kodareef5
8adf127c7d
fix: enforce directory boundary in rule path matching (#5889) 2026-04-04 21:57:40 +02:00
kodareef5
7dbf7a3528
fix: check share owner permissions on public share access (#5888) 2026-04-04 21:56:55 +02:00
Henrique Dias
65a837de49
chore(release): 2.63.0 2026-04-04 10:02:07 +02:00
Ariel Leyva
876cdb3426
feat: enable copy operation on drag‑and‑drop with ctrl key (#5882) 2026-04-04 09:54:19 +02:00
Henrique Dias
2f805de527
docs: update docker compose 2026-04-04 09:19:09 +02:00
Ariel Leyva
7a16129bfc
fix(tus): reject negative upload-length to prevent inconsistent cache entry (#5876) 2026-04-04 09:11:50 +02:00
Ariel Leyva
0f39bd055e
fix: check download permission when sharing permission is enabled (#5875) 2026-04-04 09:11:21 +02:00
Henrique Dias
860c19ddf5
chore(release): 2.62.2 2026-03-28 20:02:32 +01:00
Henrique Dias
a8fc1657b7
fix: shares listing 2026-03-28 20:02:12 +01:00
Henrique Dias
c406bda0c7
fix: json escaping 2026-03-28 19:54:21 +01:00
Henrique Dias
d9f9460c1e
fix: use html/template 2026-03-28 19:16:12 +01:00
Henrique Dias
126227bb27
fix: disable scripted content in epub 2026-03-28 19:14:02 +01:00
Henrique Dias
b6a4fb1f27
fix: self-registered users don't get execute perms 2026-03-28 19:08:19 +01:00
renovate[bot]
2368e468b9
chore(deps): update pnpm/action-setup action to v5 (#5869)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-28 19:07:00 +01:00
renovate[bot]
8d8cd26d7f
chore(deps): update all non-major dependencies (#5838)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-28 19:04:25 +01:00
lif
8f81b77cf2
fix: include filename in Content-Disposition header for inline downloads (#5860) 2026-03-28 19:03:07 +01:00
transifex-integration[bot]
0616f6811f
chore: Updates for project File Browser (#5847)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-03-28 18:59:51 +01:00
fabb
432f3e60ff
fix: double slash in TUS upload path when readEntries returns multiple batches (#5848) 2026-03-28 18:59:28 +01:00
renovate[bot]
ae72f93667
chore(deps): update actions/deploy-pages action to v5 (#5866)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-28 18:53:12 +01:00
Arran
4812536555
fix: touch Redis upload cache key on GetLength to prevent TTL expiry (#5850) 2026-03-26 16:27:28 +01:00
renovate[bot]
6d44b3ae1d
chore(deps): update pnpm/action-setup action to v5 (#5857)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-21 07:14:02 +01:00
renovate[bot]
811cf2dfe5
chore(deps): update go-task/setup-task action to v2 (#5856)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-21 07:13:58 +01:00
Henrique Dias
b5f970731b
chore(release): 2.62.1 2026-03-14 09:31:34 +01:00
Henrique Dias
fc80f4f44c
fix: base url/reverse proxy redirect 2026-03-14 09:30:35 +01:00
Henrique Dias
6aea227617
chore(release): 2.62.0 2026-03-14 08:32:56 +01:00
Henrique Dias
09a26166b4
fix: make perm.share depend on share.download 2026-03-14 08:31:55 +01:00
Henrique Dias
a63573b67e
fix: signup handler shouldn't create admins 2026-03-14 08:23:10 +01:00
Henrique Dias
4bd7d69c82
fix: clean path in patch handler 2026-03-14 08:13:51 +01:00
Henrique Dias
c21af0791a
fix: around languages 2026-03-14 08:12:03 +01:00
transifex-integration[bot]
858eb42651
feat: Updates for project File Browser (#5807)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-03-14 07:57:56 +01:00
Henrique Dias
21709428b1
ci: update transifex settings 2026-03-14 07:57:18 +01:00
renovate[bot]
846fb3333a
chore(deps): update dependency vite to v8 (#5831)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-14 07:55:55 +01:00
Henrique Dias
6f772f2b10
ci: update transifex settings 2026-03-14 07:55:25 +01:00
renovate[bot]
3c5d36673f
chore(deps): update all non-major dependencies (#5818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-14 07:53:53 +01:00
renovate[bot]
27afbb8813
chore(deps): update dependency @vitejs/plugin-legacy to v8 (#5830)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-14 07:52:28 +01:00
renovate[bot]
79875bac7f
chore(deps): update marocchino/sticky-pull-request-comment action to v3 (#5833)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-14 07:51:04 +01:00
Henrique Dias
be8ba18937
docs: add notice on proxy 2026-03-12 07:59:20 +01:00
Andrew Katsikas
ef2e9992dc
fix: properly surface config parse errors (#5822) 2026-03-12 07:34:11 +01:00
Sergio
0542fc0ba4
fix(tus): preserve percent-encoded upload paths in Location header (#5817) 2026-03-11 19:37:07 +01:00
Ariel Leyva
f04af0cac6
fix: allow deleting the user's own account (#5820) 2026-03-11 19:36:05 +01:00
Sergio
f5f8b60b33
fix(upload): avoid skipping whole folder upload on conflict modal (#5814) 2026-03-11 19:34:57 +01:00
Sergio
6dcef07f40
fix(upload): don't mark every folder-upload file as conflicting (#5813) 2026-03-11 19:34:49 +01:00
Henrique Dias
6700a981a5
docs: update readme 2026-03-11 19:32:42 +01:00
renovate[bot]
490e5bbf99
chore(deps): update docker/setup-qemu-action action to v4 (#5812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-07 07:40:47 +01:00
renovate[bot]
df63cb595c
chore(deps): update docker/setup-buildx-action action to v4 (#5811)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-07 07:40:39 +01:00
renovate[bot]
3cb21c727d
chore(deps): update docker/login-action action to v4 (#5810)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-07 07:40:31 +01:00
renovate[bot]
c01b6a840c
chore(deps): update dependency eslint to v10.0.3 (#5809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-07 07:40:23 +01:00
Henrique Dias
cbcf708d94
chore(release): 2.61.2 2026-03-06 16:17:33 +01:00
Henrique Dias
4d9e6b8218
fix(frontend): do not delete original assets 2026-03-06 16:07:08 +01:00
Henrique Dias
8ee55761a1
fix(frontend): input password type 2026-03-06 16:06:54 +01:00
Marcel Szalbach
8598db2acc
fix: added dateFormat to getUserDefaults so this is respected in the … (#5804) 2026-03-06 15:32:04 +01:00
transifex-integration[bot]
a7dc7bf88a
chore: update translations (#5796)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-03-06 15:28:29 +01:00
renovate[bot]
9f56826fb2
chore(deps): update all non-major dependencies (#5794)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 15:27:14 +01:00
Ariel Leyva
d7b00ce5f6
fix: avoid sending the same name in the file/folder rename modal (#5806) 2026-03-06 15:26:54 +01:00
Ariel Leyva
177c7cfcce
fix: validate current password with a modal (#5805) 2026-03-06 15:26:41 +01:00
Ariel Leyva
4af3f85e64
fix(csv-viewer): add support for missing text encodings in dropdown list (#5795) 2026-03-06 15:26:13 +01:00
Henrique Dias
c950a57df8
chore(release): 2.61.1 2026-03-04 10:04:51 +01:00
Henrique Dias
7ed1425115
fix: check for correct permission in TUS Delete 2026-03-04 10:04:22 +01:00
Henrique Dias
148b3c5942
chore(release): 2.61.0 2026-02-28 10:54:35 +01:00
renovate[bot]
a40f80672d
chore(deps): update all non-major dependencies (#5791)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-28 10:44:31 +01:00
transifex-integration[bot]
8dc618a24b
chore: update translations (#5790)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-02-28 10:44:24 +01:00
Henrique Dias
31194fb57a
fix: correctly clean path 2026-02-28 10:31:09 +01:00
Ariel Leyva
aa809096eb
feat: improved conflict resolution when uploading/copying/moving files (#5765) 2026-02-27 14:55:49 +01:00
renovate[bot]
e3d00d591b
chore(deps): update goreleaser/goreleaser-action action to v7 (#5782) 2026-02-22 07:12:45 +01:00
Henrique Dias
7b16e2de90
chore(release): 2.60.0 2026-02-21 18:18:55 +01:00
renovate[bot]
2470b9eb69
chore(deps): update all non-major dependencies (#5780)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-21 18:17:51 +01:00
transifex-integration[bot]
9940bdd663
feat: Updates for project File Browser (#5764)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-02-21 18:12:43 +01:00
Ariel Leyva
200d501547
fix: modal lifecycle issues, multiple modals, new directory creation and discard changes behavior (#5773) 2026-02-21 18:12:10 +01:00
Ariel Leyva
3169a14a4d
fix: always show separators and encoding list in the CSV viewer (#5774) 2026-02-21 18:11:50 +01:00
Henrique Dias
7e78ad97ad
chore(release): 2.59.0 2026-02-15 13:54:23 +01:00
NN708
0467326d5c
fix: render equations in markdown preview (#5745) 2026-02-15 13:53:36 +01:00
transifex-integration[bot]
63a76ef18c
feat: Updates for project File Browser (#5760)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-02-15 13:28:37 +01:00
renovate[bot]
3cad9a2b0e
chore(deps): update dependency eslint to v10 (#5748)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-15 13:28:26 +01:00
Marek Baczyński
804b14b698
feat: add 'Open direct' button to images (#5678) 2026-02-15 12:46:39 +01:00
Henrique Dias
95e6ed75a7
chore(release): 2.58.0 2026-02-14 08:42:21 +01:00
Henrique Dias
b09960e538
fix(frontend): pnpm lock 2026-02-14 08:41:51 +01:00
transifex-integration[bot]
5e8f5be245
feat: Updates for project File Browser (#5759)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-02-14 08:27:14 +01:00
Aaron Dill
e5bc0d3cce
fix: wrap response text in Error before reject (#5753) 2026-02-14 07:40:52 +01:00
Ariel Leyva
f67bccf8c5
feat: support for multiple encodings in CSV files (#5756) 2026-02-14 07:37:28 +01:00
Henrique Dias
88b97def9e
feat: nederlands 2026-02-14 07:35:42 +01:00
Henrique Dias
1f7904dad2
fix: ignore version.go 2026-02-14 07:35:34 +01:00
renovate[bot]
5feaf66575
chore(deps): update all non-major dependencies (#5758)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-14 07:31:45 +01:00
transifex-integration[bot]
c94870fcfe
feat: Updates for project File Browser (#5749)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-02-14 07:30:21 +01:00
Nian
6a76dfeba9
fix: respect Accept-Encoding for pre-compressed JS (#5750) 2026-02-14 07:30:10 +01:00
Henrique Dias
e193d43278
chore(release): 2.57.1 2026-02-08 08:02:48 +01:00
Henrique Dias
489af403a1
fix: remove skip clean 2026-02-08 08:02:03 +01:00
Henrique Dias
ff2f00498c
fix: normalize fields capitalization 2026-02-08 07:50:40 +01:00
renovate[bot]
2957b4605b
chore(deps): update all non-major dependencies (#5747)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-08 07:47:22 +01:00
Henrique Dias
099dfb0ae8
docs: update headers 2026-02-04 22:16:25 +01:00
Henrique Dias
a4289011ef
docs: fix headers 2026-02-04 22:15:32 +01:00
Ariel Leyva
942d59848a
chore(doc): add documentation for hook authentication method (#5742) 2026-02-04 22:12:56 +01:00
Henrique Dias
854e5371b6
chore(release): 2.57.0 2026-02-01 17:16:02 +01:00
Henrique Dias
b9df030e6e
chore(docs): update CLI documentation 2026-02-01 17:14:28 +01:00
renovate[bot]
2b82612e3f
chore(deps): update module github.com/redis/go-redis/v9 to v9.17.3 (#5738)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-01 17:10:19 +01:00
Arran
08d7a1504c
feat: Add Redis upload cache for multi-replica deployments (#5724) 2026-02-01 17:08:40 +01:00
renovate[bot]
b8da36e630
chore(deps): update dependency vue-router to v5 (#5733)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-01 17:03:31 +01:00
renovate[bot]
a8fe32f4aa
chore(deps): update module github.com/shirou/gopsutil/v4 to v4.26.1 (#5736) 2026-02-01 11:43:30 +01:00
transifex-integration[bot]
8fee2561af
feat: Updates for project File Browser (#5725) 2026-02-01 11:38:02 +01:00
Ariel Leyva
d441b28f43
fix: avoid 409 conflict when renaming files differing only by case (#5729) 2026-02-01 11:37:07 +01:00
renovate[bot]
87cfead033
chore(deps): update all non-major dependencies (#5734) 2026-02-01 11:31:54 +01:00
renovate[bot]
3a08949c7f
chore(deps): update all non-major dependencies (#5732)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 07:40:11 +01:00
Ariel Leyva
b594d4d4e2
fix: adjust yaml config decodification to yaml.v3 (#5722) 2026-01-31 07:35:47 +01:00
Henrique Dias
1053aace8c
chore(release): 2.56.0 2026-01-24 14:51:03 +01:00
Ariel Leyva
004488c15b
fix: avoid clearing selection when clicking elements outside the empty area (#5715) 2026-01-24 14:42:00 +01:00
Ariel Leyva
3032a1fade
fix: adjust columns of the table from the "users ls" command (#5716) 2026-01-24 14:39:25 +01:00
renovate[bot]
87f1d00fd7
chore(deps): update all non-major dependencies (#5714)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-24 14:38:10 +01:00
transifex-integration[bot]
f0f2f1ff06
feat: Updates for project File Browser (#5698)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-01-24 14:36:45 +01:00
Henrique Dias
08c8ede587
chore(release): 2.55.0 2026-01-18 09:00:36 +01:00
Henrique Dias
1154b49974
chore: add openbsd, remove windows arm (#5695) 2026-01-18 08:59:57 +01:00
Ariel Leyva
785b7abb7b
feat: added cut, copy, paste and show command palette functions in header (#5648) 2026-01-18 08:55:20 +01:00
renovate[bot]
550a73b6ba
chore(deps): update all non-major dependencies (#5679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-18 08:54:42 +01:00
transifex-integration[bot]
e7ea1ad27d
feat: update translations (#5677)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-01-18 08:45:48 +01:00
GUCHI
24781badd4
Merge commit from fork
Added a dummy bcrypt hash to prevent user enumeration timing attacks in JSON authentication.
2026-01-18 08:44:16 +01:00
Ariel Leyva
4094fb359b
fix: retain file selection when closing the editor (#5693) 2026-01-18 08:37:12 +01:00
Ariel Leyva
cfa6c5864e
fix: request current password when deleting users (#5667) 2026-01-18 08:36:25 +01:00
Andy
59ca0c340a
fix: prevent context menu clicks from clearing file selection (#5681) 2026-01-17 22:57:01 +01:00
Henrique Dias
037e29a708
chore(release): 2.54.0 2026-01-10 10:30:26 +01:00
Beckam White
fda8a99292
feat: add "redirect after copy/move" user setting (#5662) 2026-01-10 10:27:54 +01:00
Ariel Leyva
208535a8cc
fix: clear selection by clicking on empty area (#5663) 2026-01-10 10:05:12 +01:00
transifex-integration[bot]
464b581953
feat: update translations (#5659)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-01-10 09:38:48 +01:00
renovate[bot]
20312ff18e
chore(deps): update all non-major dependencies (#5676)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-10 09:37:56 +01:00
Ariel Leyva
219582c0b0
fix: hide "change password form" in noauth setting (#5652) 2026-01-10 09:31:27 +01:00
Jagadam Dinesh Reddy
4fd18a382c
feat: force file sync while uploading file (#5668) 2026-01-10 09:30:08 +01:00
Henrique Dias
94ec786d34
chore(release): 2.53.1 2026-01-03 08:54:16 +01:00
renovate[bot]
25e9b85259
chore(deps): update all non-major dependencies (#5657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-03 08:53:36 +01:00
Jagadam Dinesh Reddy
ffa893e9ac
fix: download path encoding file paths (#5655) 2026-01-03 08:53:21 +01:00
Ariel Leyva
b8151a038a
fix: request a password to change sensitive user data (#5629) 2026-01-03 08:44:03 +01:00
Henrique Dias
943e5340d0
chore(release): 2.53.0 2025-12-29 08:33:04 +01:00
Henrique Dias
88aa56f53b
chore(docs): update CLI documentation 2025-12-29 08:32:46 +01:00
transifex-integration[bot]
a12a612970
feat: update translations
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-29 08:29:25 +01:00
Ariel Leyva
a2d80c62c1
feat: add "disable image resolution calculation" flag (#5638) 2025-12-29 08:25:49 +01:00
renovate[bot]
1faa21844f
chore(deps): update all non-major dependencies (#5639)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-29 08:25:45 +01:00
Brendan Jackman
7a93b2a062
docs: clarify scope of config file and environment variables (#5643) 2025-12-29 08:20:48 +01:00
transifex-integration[bot]
032d6c7520
feat: update translations (#5631)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-28 22:14:08 +01:00
Dominik
9595f3939c
fix: conversion of backslashes in file paths for archive creation (#5637)
Co-authored-by: FadedAtlas <fadedatlas.shield181@slmail.me>
2025-12-28 22:07:00 +01:00
Brendan Jackman
60b1ee8bb9
fix: fix nil deref in config set command (#5641)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-12-28 22:04:59 +01:00
Brendan Jackman
79d1aa9229
fix: Don't crash on invalid config import (#5640) 2025-12-28 22:04:23 +01:00
Ramires Viana
20bfd131c6
feat: support streaming response for search results (#5630)
Co-authored-by: manx98 <1323517022@qq.com>
2025-12-28 21:57:25 +01:00
transifex-integration[bot]
f89975603e
feat: update translations (#5626)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-21 17:41:19 +00:00
renovate[bot]
2d3b64ecf6
chore(deps): update all non-major dependencies (#5628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-21 13:04:25 +00:00
renovate[bot]
579756dbb5
chore(deps): update all non-major dependencies (#5621)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 08:03:59 +01:00
Henrique Dias
c11c986b73
chore(release): 2.52.0 2025-12-13 09:13:37 +01:00
transifex-integration[bot]
3fdca6dfd9
feat: update translations (#5615)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-13 09:09:31 +01:00
Ariel Leyva
cf966578d8
fix: hide the context menu when changing the route (#5613) 2025-12-13 09:09:05 +01:00
Ariel Leyva
6d4c867672
fix: display the directory name in the shared folder view (#5617) 2025-12-13 09:08:44 +01:00
renovate[bot]
169e97e6f9
chore(deps): update all non-major dependencies (#5620)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-13 09:06:33 +01:00
transifex-integration[bot]
7fa3432f25
feat: sync translations with Transifex
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-09 21:45:34 +01:00
renovate[bot]
e9ce7fa5aa
chore(deps): update all non-major dependencies (#5601) 2025-12-09 21:44:27 +01:00
Henrique Dias
849f5ad443
chore(release): 2.51.2 2025-12-07 08:12:35 +01:00
Henrique Dias
c1715992bd
fix(frontend): add missing i18n strings 2025-12-07 07:47:43 +01:00
Henrique Dias
e4f2503298
chore(release): 2.51.1 2025-12-07 07:44:25 +01:00
Ariel Leyva
152f8302f7
fix: prevent the right-click from selecting multiple items when the "single-click" option is active (#5608) 2025-12-07 07:35:47 +01:00
Henrique Dias
4cbb4b73af
fix(frontend): csv viewer i18n strings 2025-12-07 07:24:15 +01:00
Henrique Dias
58cc874828
chore(release): 2.51.0 2025-12-06 11:37:24 +01:00
Henrique Dias
124def5cd7
chore: dependency updates 2025-12-06 11:33:43 +01:00
transifex-integration[bot]
2d88c06761
feat: update translations
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-06 11:23:24 +01:00
Ariel Leyva
204a3f0eea
fix: added column separator select (comma, semicolon and both) in CSV viewer (#5604)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-12-06 11:08:50 +01:00
Henrique Dias
f029c3005e
refactor: cleanup package names (#5605) 2025-12-06 10:52:11 +01:00
Henrique Dias
a6934e40ff
ci: run renovate on weekends 2025-12-05 15:11:22 +01:00
renovate[bot]
98662ac5ec
chore(deps): update all non-major dependencies (#5600)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 08:47:00 +01:00
renovate[bot]
5cf8ce8db5
chore(deps): update dependency vite to v7.2.6 (#5598)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 08:38:14 +01:00
renovate[bot]
062dc414f8
chore(deps): update module github.com/shirou/gopsutil/v4 to v4.25.11 (#5597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 07:37:25 +01:00
Henrique Dias
63582b644c
chore: run linter 2025-11-30 09:17:35 +01:00
Henrique Dias
4302ece49b
chore(release): 2.50.0 2025-11-30 09:08:15 +01:00
Henrique Dias
e1ee14d827
chore(docs): update CLI documentation 2025-11-30 09:07:56 +01:00
Henrique Dias
84ca722261
ci: use docs on GitHub Pages 2025-11-30 08:49:24 +01:00
jake-dog
b9ac45d5da
feat: configurable logout page URL for proxy/hook auth (#3884)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-30 08:44:34 +01:00
Henrique Dias
701522a060
fix: do not close editor if save failed
Closes #5591
2025-11-30 07:58:37 +01:00
transifex-integration[bot]
78e0395960
feat: update translations
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-11-30 07:32:51 +01:00
renovate[bot]
f0680cf0f5
chore(deps): update dependency prettier to v3.7.3 (#5592)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 07:31:40 +01:00
Krishan Bhasin
982405ec94
feat: render CSVs as table (#5569)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-29 10:45:11 +01:00
renovate[bot]
a78aaed214
chore(deps): update dependency prettier to v3.7.2 (#5589)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 10:25:22 +01:00
renovate[bot]
df11a7dd0e
chore(deps): update all non-major dependencies (#5583)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 17:40:31 +01:00
renovate[bot]
79980bcf52
chore(deps): update all non-major dependencies to v14.1.0 (#5582)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-27 09:05:21 +01:00
renovate[bot]
3be134f23d
chore(deps): update all non-major dependencies (#5578)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 13:56:59 +01:00
transifex-integration[bot]
279a5ccd1e
feat: update frontend/src/i18n/hr.json
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-11-26 13:56:45 +01:00
renovate[bot]
87f73ac982
chore(deps): update dependency vue to v3.5.25 (#5577)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-24 09:39:33 +01:00
renovate[bot]
85cde140ba
chore(deps): update dependency vue-tsc to v3.1.5 (#5575)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-23 08:10:22 +01:00
Henrique Dias
119609c834
chore(release): 2.49.0 2025-11-22 17:15:51 +01:00
Kosmos
d48f5665d6
feat: add "copy download link to clipboard" button to Share prompt (#5173)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-22 17:07:10 +01:00
transifex-integration[bot]
54306bdc87
feat: Updates for project File Browser (#5566)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-11-22 16:36:03 +01:00
renovate[bot]
33deedf559
chore(deps): update dependency vue-i18n to v11.2.1 (#5574)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-22 15:06:10 +01:00
renovate[bot]
88d1eecc4e
chore(deps): update dependency eslint-plugin-vue to v10.6.0 (#5573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-22 07:57:55 +01:00
renovate[bot]
43db19f8c8
chore(deps): update all non-major dependencies (#5571)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 18:57:20 +01:00
renovate[bot]
a360f26979
chore(deps): update actions/checkout action to v6 (#5572)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 18:54:40 +01:00
renovate[bot]
ab367a2740
chore(deps): update all non-major dependencies (#5567)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 09:58:37 +01:00
Henrique Dias
5df5508a85 chore: add govet, gocritic and revive 2025-11-20 07:56:56 +01:00
Brian Fromm
6d5aa355e4
fix: display friendly error message for password validation on signup (#5563)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-19 17:42:50 +01:00
renovate[bot]
a3b5584505
chore(deps): update dependency @vitejs/plugin-vue to v6.0.2 (#5564)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-19 08:14:22 +01:00
transifex-integration[bot]
8db2411cd4
feat: add Bulgarian language
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-19 08:14:10 +01:00
Henrique Dias
c284de9d2c
chore(release): 2.48.2 2025-11-18 11:32:24 +01:00
Henrique Dias
984ea7b569
fix: add transitionary support for FB_BASEURL 2025-11-18 11:30:43 +01:00
Henrique Dias
fd7b70cf38
refactor: rename python for clarification 2025-11-18 11:29:28 +01:00
renovate[bot]
13e3b46718
chore(deps): update all non-major dependencies (#5560)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-18 08:05:02 +01:00
Henrique Dias
d759ab0bd8
chore(release): 2.48.1 2025-11-17 10:02:54 +01:00
Henrique Dias
00323a8f37
chore: fix Taskfile commit when change 2025-11-17 10:02:29 +01:00
Henrique Dias
420adea7e6
fix: options should only override if set 2025-11-17 09:58:27 +01:00
Henrique Dias
f576d38a7e
chore(release): 2.48.0 2025-11-17 09:39:04 +01:00
Henrique Dias
9bdc67c207
chore(docs): update CLI documentation 2025-11-17 09:38:45 +01:00
Henrique Dias
f41585f039
fix: use all available flags in quick setup 2025-11-17 09:17:30 +01:00
Henrique Dias
89be0b1873
refactor: reuse logic for config init and set 2025-11-17 09:16:54 +01:00
Brian Fromm
8c5dc7641e
fix: add tokenExpirationTime to config init and troubleshoot docs (#5546)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-17 08:57:02 +01:00
Henrique Dias
0a0cb8046f
feat: consistent flags and environment variables (#5549)
- In the root command, all flags are now correctly available as environmental variables, except for `--config` flag. This was already supposed to be the case, but due to bugs in the implementation it didn't work properly.
- All configuration options (unless I missed something) that are available as flags should now properly update the configuration when using the `config init` and `config set` commands.
- Flag names are now consistently in the lowerCamelCase format. All flags that were in a different format have been updated in a backwards compatible way. For a transitionary period of at least 6 months, both will work:
  - `--dir-mode` --> `--dirMode`
  - `--hide-login-button` --> `--hideLoginButton`
  - `--create-user-dir` --> `--createUserDir`
  - `--minimum-password-length` --> `--minimumPasswordLength`
  - `--socket-perm` --> `--socketPerm`
  - `--disable-thumbnails` --> `--disableThumbnails`
  - `--disable-preview-resize` --> `--disablePreviewResize`
  - `--disable-exec` --> `--disableExec`
  - `--disable-type-detection-by-header` --> `--disableTypeDetectionByHeader`
  - `--img-processors` --> `--imageProcessors`
  - `--cache-dir` --> `--cacheDir`
  - `--token-expiration-time` --> `--tokenExpirationTime`
  - `--baseurl` --> `--baseURL`
2025-11-17 08:45:43 +01:00
Henrique Dias
f89435c068
chore: fix taskfile 2025-11-16 14:28:48 +01:00
Henrique Dias
fb8d41eb9a
chore(release): 2.47.0 2025-11-16 14:28:15 +01:00
Henrique Dias
0fadaccaa2
chore(docs): update CLI documentation 2025-11-16 14:28:03 +01:00
Henrique Dias
e24e1f1aba
feat: add TUS settings to the command line (#5556) 2025-11-16 14:13:58 +01:00
Henrique Dias
5de4099cba
fix: exit 0 when gracefully shutting down (#5555) 2025-11-16 14:13:21 +01:00
Henrique Dias
d01493106d
docs: improved config 2025-11-16 10:31:08 +01:00
Henrique Dias
2d9689dd6a
docs: add CLI usage and integrate generation in release 2025-11-16 10:14:59 +01:00
Henrique Dias
c4c1cea230
docs: remove partially incorrect env variables info 2025-11-16 09:01:54 +01:00
Henrique Dias
ceb5e723f3
feat: remove importer of v1 config (#5550) 2025-11-16 07:52:53 +01:00
renovate[bot]
ebc7d2303d
chore(deps): update dependency vue-tsc to v3.1.4 (#5551)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-15 20:14:10 +01:00
Henrique Dias
23c4e4565b
chore: remove 'nolint' comments 2025-11-15 09:01:21 +01:00
Henrique Dias
17f1e08a58
chore(release): 2.46.1 2025-11-15 08:51:04 +01:00
Henrique Dias
ffc850454e
fix: remove duplicated 'hide-defaults' flag (is 'hideDefaults') (#5548) 2025-11-15 08:50:22 +01:00
Henrique Dias
13814e1119
fix: env key replacer and remove unused function (#5547) 2025-11-15 08:40:37 +01:00
Henrique Dias
4e9e312984
chore(release): 2.46.0 2025-11-14 18:15:33 +01:00
Henrique Dias
ce3b407c51
docs: clarify status 2025-11-14 17:49:52 +01:00
transifex-integration[bot]
fb5d099f85
feat: Updates for project File Browser (#5544) 2025-11-14 17:47:21 +01:00
Omar Hussein
1ace579a55
feat: add context menu (#3343)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-14 16:53:16 +01:00
Lucky Jain
ac7b49c148
feat: add option to hide the login button from public-facing pages (#3922)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-14 16:21:08 +01:00
Henrique Dias
9d44932dba
chore: use more standard golangci-lint options 2025-11-14 16:18:12 +01:00
Ahmad Hesam
0d973d3aad
feat: add 'hide-dotfiles' as command line parameter (#3802)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-14 08:19:03 +01:00
Henrique Dias
cacc0999e9
chore: let functions be longer 2025-11-14 08:11:10 +01:00
Henrique Dias
42d1b6f3ae
docs: fix badge in readme 2025-11-13 18:03:51 +01:00
Henrique Dias
bb10c3dfa9
docs: clarify release 2025-11-13 17:39:51 +01:00
Henrique Dias
ce76aa23a6
chore(release): 2.45.3 2025-11-13 17:39:11 +01:00
Henrique Dias
94b635daf8
ci: fix workflow command 2025-11-13 17:37:50 +01:00
Henrique Dias
31871aaa4b
docs: update project status (#5513) 2025-11-13 17:34:52 +01:00
Henrique Dias
9d465663db
chore(release): 2.45.3 2025-11-13 17:32:46 +01:00
Henrique Dias
70081f2647
docs: add note about flags and env (#5542) 2025-11-13 17:31:12 +01:00
Henrique Dias
fa9d2f266f
ci: simplify the workflows (#5541) 2025-11-13 17:25:59 +01:00
Henrique Dias
8fcfb502ca
docs: improve contribution documentation (#5540) 2025-11-13 17:16:50 +01:00
Henrique Dias
0bab2aba9e
chore: use Task, split workflows 2025-11-13 16:51:32 +01:00
renovate[bot]
38951d950f
chore(deps): update module github.com/golang-jwt/jwt/v4 to v5 (#5535)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-11-13 16:07:53 +01:00
renovate[bot]
dda8fdbcb2
chore(deps): update module golang.org/x/tools to v0.39.0 (#5522)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-13 14:28:28 +01:00
Henrique Dias
bf3ba65782
chore: bump @vue/tsconfig
Signed-off-by: Henrique Dias <mail@hacdias.com>
2025-11-13 14:21:30 +01:00
Henrique Dias
f35b7c9d9d
chore: remove unused tests
Signed-off-by: Henrique Dias <mail@hacdias.com>
2025-11-13 14:21:11 +01:00
Henrique Dias
e9506c3eae
chore: remove unused dependencies
Signed-off-by: Henrique Dias <mail@hacdias.com>
2025-11-13 14:19:08 +01:00
Henrique Dias
bb4465548b
chore: use 'chore' instead of 'fix' in renovate 2025-11-13 14:10:06 +01:00
Henrique Dias
cf8b5ca768
docs: fix duplicated changelog entry 2025-11-13 14:05:50 +01:00
Henrique Dias
f93d760b1b
chore(release): 2.45.2 2025-11-13 14:03:52 +01:00
Henrique Dias
1495ee8dd8
chore: replace release-please with commit-and-tag-version 2025-11-13 14:03:41 +01:00
FileBrowser Robot
8a7279e3ee
chore(master): release 2.45.2 (#5538) 2025-11-13 13:51:22 +01:00
renovate[bot]
fdff7a38f4
fix(deps): update module github.com/shirou/gopsutil/v3 to v4 (#5536)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-13 13:48:34 +01:00
renovate[bot]
f26a68587d
fix(deps): update module gopkg.in/yaml.v2 to v3 (#5537)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-13 13:47:39 +01:00
Henrique Dias
1c62038344
chore: delete commitlint 2025-11-13 09:41:33 +01:00
Henrique Dias
6eb7b4b8ec
ci: replace standard-version with release please (#5533) 2025-11-13 09:34:59 +01:00
Henrique Dias
f11fc37409
chore: bump to Node 24, pnpm 10, multiple GH actions (#5532) 2025-11-13 07:50:00 +01:00
renovate[bot]
d12a3dc8a8
chore(deps): update amannn/action-semantic-pull-request action to v6 (#5523)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 22:28:24 +01:00
Henrique Dias
0cfab8770a chore: some dependency updates 2025-11-12 22:25:18 +01:00
renovate[bot]
3876ae8fe8 chore(deps): update actions/setup-go action to v6 2025-11-12 15:15:46 +01:00
renovate[bot]
77644e4425 chore(deps): update actions/setup-node action to v6 2025-11-12 15:15:36 +01:00
renovate[bot]
6592782dc0
chore: update minor and patch dependencies, go 1.25 2025-11-12 15:12:28 +01:00
renovate[bot]
d6dc250ed4 chore(deps): update actions/checkout action to v5 2025-11-12 14:54:45 +01:00
Henrique Dias
9579f14c34
chore: add renovate.json 2025-11-12 14:49:22 +01:00
Henrique Dias
c5acbffe3f
docs: import logo and banner (#5514) 2025-11-11 18:32:41 +01:00
Henrique Dias
63142042bc
docs: remove unmaintained badges 2025-11-11 18:10:55 +01:00
Henrique Dias
1ac0305ed0
docs: add notice about releases page 2025-11-11 17:40:33 +01:00
Henrique Dias
7860013aa9
chore: update CODEOWNERS to use team (#5512) 2025-11-11 17:39:24 +01:00
Henrique Dias
7a5b964611
chore(release): 2.45.1 2025-11-11 08:10:41 +01:00
Jagadam Dinesh Reddy
6950c2e4d2
fix: share page preview items to contain baseUrl (#5510)
Co-authored-by: jagadam97 <dineshjagadam@hmail.com>
2025-11-11 08:09:19 +01:00
Henrique Dias
291223b3ce
Merge commit from fork 2025-11-11 08:06:16 +01:00
Henrique Dias
99aeb766c3
chore(release): 2.45.0 2025-11-01 09:57:04 +01:00
Henrique Dias
93fe31cc55
fix: support croatian (#5502) 2025-11-01 08:53:50 +01:00
transifex-integration[bot]
b9a03fabd9
feat: update translations (#5458) 2025-11-01 08:38:55 +01:00
jagadam97
d00b3ea8f8 fix(img):Prevent thumbnail generation for large images 2025-11-01 08:37:50 +01:00
Henrique Dias
c18afcddc4
chore(release): 2.44.2 2025-10-22 10:39:43 +02:00
Henrique Dias
57db25d08a
fix(http): remove auth query parameter 2025-10-22 10:38:30 +02:00
dependabot[bot]
b8f64a1c1b build(deps-dev): bump vite from 6.3.6 to 6.4.1 in /frontend
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.6 to 6.4.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@6.4.1/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.4.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-22 08:54:36 +02:00
Henrique Dias
de35dee1c5
chore(release): 2.44.1 2025-10-17 17:41:27 +02:00
MSomnium Studios
dd883985bb
fix(auth): prevent integer overflow in logout timer using safeTimeout (#5470) 2025-10-17 17:38:57 +02:00
rocksload
97b8911ba8
refactor: use slices.Contains to simplify code (#5483) 2025-10-17 16:45:47 +02:00
Ryan
a397e7305d
fix: editor discard prompt doesn't save nor discard
Co-authored-by: Ryan Miller <ryan.miller@infinitetactics.com>
2025-10-17 16:45:36 +02:00
Ryan
d0039afbb7
fix: wrong url on settings branding link 2025-10-03 10:42:24 +02:00
Henrique Dias
878cdfbc52
chore(release): 2.44.0 2025-09-25 17:20:12 +02:00
transifex-integration[bot]
1165f00bd4
feat: Updates for project File Browser (#5457)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-09-25 17:19:21 +02:00
Henrique Dias
949ddffef2
fix: some formatting issues with i18n files 2025-09-25 17:13:30 +02:00
Henrique Dias
c4725428e0
fix: computation of file path 2025-09-25 17:09:16 +02:00
MSomnium Studios
d29ad356d1
feat: Improved path display in the new file and directory modal (#5451) 2025-09-25 16:57:30 +02:00
MSomnium Studios
692ca5eaf0
fix(upload): throttle upload speed calculation to 100ms to avoid Infinity MB/s (#5456)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-09-25 16:54:28 +02:00
Adam
b9787c78f3
feat: allow setting ace editor theme (#3826)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-09-25 16:47:00 +02:00
transifex-integration[bot]
dec7a02737 feat: Translate frontend/src/i18n/en.json in no
100% translated source file: 'frontend/src/i18n/en.json'
on 'no'.
2025-09-25 16:46:45 +02:00
transifex-integration[bot]
0eade717ce
feat: Updates for project File Browser (#5450)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-09-19 21:32:15 +02:00
MSomnium Studios
e6c674b3c6
fix: show login when session token expires 2025-09-19 15:09:26 +02:00
transifex-integration[bot]
4ff247e134
feat: Updates for project File Browser (#5446)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-09-18 13:10:27 +02:00
Henrique Dias
2f0c1f5fa2
chore(release): 2.43.0 2025-09-13 09:04:12 +02:00
Henrique Dias
07692653ff
revert: build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 2025-09-13 09:03:12 +02:00
Henrique Dias
82dc57ad43
chore(release): 2.43.0 2025-09-13 08:44:52 +02:00
Jorge
84e8632b98
feat: "save changes" button to discard changes dialog 2025-09-13 08:07:05 +02:00
transifex-integration[bot]
571ce6cb0d feat: Translate frontend/src/i18n/en.json in es
94% of minimum 50% translated source file: 'frontend/src/i18n/en.json'
on 'es'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format
2025-09-13 07:59:33 +02:00
wuwenbin
783503aece
fix: optimize markdown preview height 2025-09-13 07:58:43 +02:00
cui
b482a9bf0d
refactor: to use strings.Lines 2025-09-13 07:57:18 +02:00
dependabot[bot]
36c6cc203e build(deps-dev): bump vite from 6.1.6 to 6.3.6 in /frontend
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.1.6 to 6.3.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.3.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.3.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-10 14:27:17 +02:00
transifex-integration[bot]
8950585141
feat: Updates for project File Browser (#5427) 2025-09-08 07:48:31 +02:00
dependabot[bot]
950028abeb build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14
Bumps [github.com/ulikunitz/xz](https://github.com/ulikunitz/xz) from 0.5.12 to 0.5.14.
- [Commits](https://github.com/ulikunitz/xz/compare/v0.5.12...v0.5.14)

---
updated-dependencies:
- dependency-name: github.com/ulikunitz/xz
  dependency-version: 0.5.14
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-30 08:00:45 +02:00
dependabot[bot]
280fa562a6 build(deps): bump github.com/go-viper/mapstructure/v2 in /tools
Bumps [github.com/go-viper/mapstructure/v2](https://github.com/go-viper/mapstructure) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/go-viper/mapstructure/releases)
- [Changelog](https://github.com/go-viper/mapstructure/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-viper/mapstructure/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: github.com/go-viper/mapstructure/v2
  dependency-version: 2.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-22 09:02:02 +02:00
transifex-integration[bot]
6b1fa87ad3
feat: Translate frontend/src/i18n/en.json in fr
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-20 14:33:09 +02:00
Henrique Dias
cacfb2bc08
chore(release): 2.42.5 2025-08-16 09:42:55 +02:00
Jagadam Dinesh Reddy
3107ae4147
fix: "new folder" button not working in the move and copy popup (#5368) 2025-08-16 09:42:05 +02:00
Henrique Dias
c182114883 chore(release): 2.42.4 2025-08-16 08:05:47 +02:00
Henrique Dias
342b239ac6 fix: add libcap to Dockerfile.s6 2025-08-16 08:01:18 +02:00
Henrique Dias
0f41aac20b
chore(release): 2.42.3 2025-08-09 08:46:10 +02:00
wx-11
cd51a59e72
fix: add missing CLI flags for user management (#5351) 2025-08-09 07:42:42 +02:00
Henrique Dias
c829330b53
chore(release): 2.42.2 2025-08-06 16:48:24 +02:00
Ramires Viana
c14cf86f83
refactor: upload progress calculation (#5350) 2025-08-06 16:47:48 +02:00
Henrique Dias
6d620c00a1
docs: reword configuration intro 2025-08-04 08:11:40 +02:00
Ramires Viana
06e8713fa5
fix: show file upload errors 2025-08-01 18:44:38 +02:00
Henrique Dias
af9b42549f
chore(release): 2.42.1 2025-07-31 07:28:32 +02:00
transifex-integration[bot]
75baf7ce33 feat: Translate frontend/src/i18n/en.json in vi
100% translated source file: 'frontend/src/i18n/en.json'
on 'vi'.
2025-07-31 07:27:15 +02:00
Henrique Dias
4ff6347155 fix: directory mode on config init 2025-07-31 07:27:05 +02:00
transifex-integration[bot]
14ee054359
feat: Translate frontend/src/i18n/en.json in sk 2025-07-27 18:06:44 +02:00
Henrique Dias
7f559ffd07
chore(release): 2.42.0 2025-07-27 13:38:09 +02:00
Henrique Dias
619f6837b0
fix: norsk loading 2025-07-27 13:37:43 +02:00
Henrique Dias
d778c192ae
Revert "chore(release): 2.42.0"
This reverts commit a290c6d7db.
2025-07-27 13:31:12 +02:00
Henrique Dias
a290c6d7db
chore(release): 2.42.0 2025-07-27 13:14:20 +02:00
Henrique Dias
c1b0207800 build: bump to go 1.24 2025-07-27 13:14:03 +02:00
Christopher Campo
c7a5c7efee build: bump go version to 1.23.11 2025-07-27 13:09:05 +02:00
Ramires Viana
cbeec6d225
feat: select item on file list after navigating back (#5329) 2025-07-27 13:03:00 +02:00
Henrique Dias
25e47c3ce8
feat: add Norwegian support (#5332) 2025-07-26 07:35:46 +02:00
transifex-integration[bot]
5eb3bf4058
feat: Translate frontend/src/i18n/en.json in no 2025-07-26 07:30:10 +02:00
transifex-integration[bot]
07dfdce8e4 feat: Translate frontend/src/i18n/en.json in sk
91% of minimum 50% translated source file: 'frontend/src/i18n/en.json'
on 'sk'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format
2025-07-25 08:50:31 +02:00
Henrique Dias
e5e1b6dee4
chore(release): 2.41.0 2025-07-22 08:28:22 +02:00
Jagadam Dinesh Reddy
1582b8b2cd
feat: better error handling for sys kill signals 2025-07-22 08:25:21 +02:00
Vincent Lee
21ad653b7e feat: Allow file and directory creation modes to be configured
The defaults remain the same as before.
For now, the config options are global instead of per-user.
Note also that the BoltDB creation maintains the old default mode of 0640
since it's not really a user-facing filesystem manipulation.
Fixes #5316, #5200
2025-07-22 07:56:52 +02:00
Henrique Dias
5b7ea9f95a
chore(release): 2.40.2 2025-07-17 18:09:15 +02:00
Henrique Dias
607f5708a2
fix: Location header on TUS endpoint (#5302) 2025-07-17 18:06:59 +02:00
dependabot[bot]
d61110e4d7 build(deps): bump vue-i18n from 11.1.9 to 11.1.10 in /frontend
Bumps [vue-i18n](https://github.com/intlify/vue-i18n/tree/HEAD/packages/vue-i18n) from 11.1.9 to 11.1.10.
- [Release notes](https://github.com/intlify/vue-i18n/releases)
- [Changelog](https://github.com/intlify/vue-i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n/commits/v11.1.10/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-version: 11.1.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-17 06:49:33 +02:00
Henrique Dias
7e758357d1
chore: update bug_report.yml 2025-07-16 16:57:35 +02:00
Henrique Dias
3faec03ed7
chore: update bug_report.yml 2025-07-16 16:57:02 +02:00
Henrique Dias
a7a68f74ae
chore: update minor dependencies (#5295) 2025-07-15 20:02:06 +02:00
Henrique Dias
6425cc58b4
chore(release): 2.40.1 2025-07-15 08:23:35 +02:00
Henrique Dias
88f1442932
fix: print correct user on setup 2025-07-15 08:18:38 +02:00
Henrique Dias
545c972214
chore(release): 2.40.0 2025-07-13 21:29:02 +02:00
Henrique Dias
124abc7643
chore: remove ln from init.sh 2025-07-13 21:28:46 +02:00
jagadam97
b8454bb2e4 fix: Only left click should drag the image in extended image view 2025-07-13 20:47:09 +02:00
outlook84
035084d8e8
feat: add font size botton to text editor (#5290) 2025-07-13 20:44:50 +02:00
Ramires Viana
9072cbce34 fix: invalid path when uploading files 2025-07-13 20:39:43 +02:00
Henrique Dias
e6ffb65374
chore(release): 2.39.0 2025-07-13 08:42:18 +02:00
outlook84
5c5942d995
build: lightweight busybox-based container build (#5285) 2025-07-13 08:37:20 +02:00
Henrique Dias
1a5c83bcfe
build: remove upx 2025-07-13 08:24:55 +02:00
Henrique Dias
5a8e7171b1 fix: Settings button in the sidebar 2025-07-13 08:18:06 +02:00
Ramires Viana
0f27c91eca
fix: drop modify permission for uploading new file (#5270) 2025-07-13 08:16:01 +02:00
Jagadam Dinesh Reddy
7c716862c1
feat: rewrite the archiver and added support for zstd and brotli (#5283) 2025-07-12 14:27:08 +02:00
outlook84
01c814cf98
feat: Improve Docker entrypoint and config handling 2025-07-12 13:30:36 +02:00
jagadam97
35ca24adb8 build: improve docker image and binary sizes 2025-07-12 08:46:22 +02:00
Henrique Dias
14b0dfec34
chore(release): 2.38.0 2025-07-12 08:02:41 +02:00
Jonathan Bout
528ce92fad
feat: Show the current users name in the sidebar (#2821)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-07-12 07:59:50 +02:00
Ryan
fbe169b84f
fix: prevent page change if there are outstanding edits (#5260) 2025-07-12 07:52:41 +02:00
transifex-integration[bot]
b4eddf45e4
feat: Updates for project File Browser
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-07-10 12:50:10 +02:00
Henrique Dias
0614dcd89b
chore(release): 2.37.0 2025-07-08 18:42:38 +02:00
Henrique Dias
fcb248a5fe fix: long file name overlap 2025-07-08 08:30:42 +02:00
Henrique Dias
bf73e4dea3 fix: preview PDF is correctly displayed 2025-07-08 08:20:43 +02:00
transifex-integration[bot]
b28952cb25 feat: Translate frontend/src/i18n/en.json in zh_TW
100% translated source file: 'frontend/src/i18n/en.json'
on 'zh_TW'.
2025-07-06 21:55:12 +02:00
transifex-integration[bot]
1e96fd9035 feat: Translate frontend/src/i18n/en.json in zh_TW
99% of minimum 50% translated source file: 'frontend/src/i18n/en.json'
on 'zh_TW'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format
2025-07-06 21:55:12 +02:00
jagadam97
e423395ef0 fix: Upload progress size calculation 2025-07-06 17:43:44 +02:00
transifex-integration[bot]
65bbf44e3c feat: Translate frontend/src/i18n/en.json in zh_CN
100% translated source file: 'frontend/src/i18n/en.json'
on 'zh_CN'.
2025-07-06 17:39:35 +02:00
Henrique Dias
200b9a6c26
chore(release): 2.36.3 2025-07-06 12:20:49 +02:00
Henrique Dias
3645b578cd
fix: log error if branding file exists but cannot be loaded 2025-07-06 12:12:57 +02:00
Henrique Dias
cc6db83988
chore(release): 2.36.2 2025-07-06 08:53:05 +02:00
Ryan
046d6193c5
fix: lookup directory name if blank when downloading shared directory 2025-07-05 08:15:17 +02:00
Henrique Dias
244fda2f2c
chore: base s6 image has now manifest for arm64 2025-07-03 16:22:24 +02:00
Henrique Dias
e36a9b40a0
chore(release): 2.36.1 2025-07-03 16:14:05 +02:00
Henrique Dias
a756e02142
docs: fix typo 2025-07-03 16:11:37 +02:00
Henrique Dias
b6394745a3
docs: docker caveat with bind mounts 2025-07-03 16:00:54 +02:00
Stavros Tsioulis
e99e0b3028
fix: remove associated shares when deleting file/folder 2025-07-03 06:42:55 +02:00
Henrique Dias
47b3e218ad
docs: remove note about fixed issue 2025-07-02 08:54:27 +02:00
Henrique Dias
0c34b79a99
chore(release): 2.36.0 2025-07-02 08:33:36 +02:00
Henrique Dias
04166e81e5 feat: update icons, remove deprecated Microsoft Tiles 2025-07-02 08:33:12 +02:00
Henrique Dias
fae410ce6e docs: improve custom branding info 2025-07-02 08:33:12 +02:00
Henrique Dias
9da01be7fc
docs: add update instructions to Docker 2025-07-02 07:45:39 +02:00
Henrique Dias
e9e7c68557
chore: remove symlink in Dockerfile 2025-07-02 07:39:01 +02:00
Henrique Dias
8ef8f2c098
chore(release): 2.35.0 2025-06-30 17:03:16 +02:00
Henrique Dias
3b3df83d64 docs: add warning to command runner 2025-06-30 17:01:02 +02:00
Henrique Dias
38d0366acf fix: update documentation links 2025-06-30 17:01:02 +02:00
Henrique Dias
4403cd3572 fix: shell value must be joined by blank space 2025-06-30 17:01:02 +02:00
Foxy Hunter
8d7522049c
feat: Long press selects item in single click mode 2025-06-30 16:14:09 +02:00
Henrique Dias
7b43cfb1dc
docs: improve fail2ban filter 2025-06-29 17:24:17 +02:00
Henrique Dias
d644744417
docs: add fail2ban instructions 2025-06-29 16:34:50 +02:00
Henrique Dias
d1a73a8b18
chore(release): 2.34.2 2025-06-29 16:12:09 +02:00
Henrique Dias
2b5d6cbb99 fix: mitigate unprotected shares 2025-06-29 16:06:20 +02:00
Henrique Dias
364f391017
docs: cleanup installation 2025-06-29 15:53:02 +02:00
Henrique Dias
c13861e13c
docs: clarify admin password 2025-06-29 15:36:58 +02:00
Henrique Dias
e6b750add5
chore: make more fields in bug report mandatory 2025-06-29 15:06:18 +02:00
Henrique Dias
70d59ec03e
chore(release): 2.34.1 2025-06-29 11:28:57 +02:00
Henrique Dias
bf37f88c32
fix: passthrough the minimum password length (#5236) 2025-06-29 11:28:32 +02:00
Foxy Hunter
7354eb6cf9
fix: exclude to-be-moved folder from move dialog (#5235) 2025-06-29 11:23:06 +02:00
Henrique Dias
10684e5390
docs: bring the maintenance warning higher in the page 2025-06-29 10:13:39 +02:00
Henrique Dias
58fe817349
docs: add link to contributing and license in readme 2025-06-29 10:13:01 +02:00
Henrique Dias
d8472e767b
chore(release): 2.34.0 2025-06-29 09:54:35 +02:00
Henrique Dias
8700cb30ff
chore: reuse docker flags 2025-06-29 09:51:44 +02:00
manx98
93c4b2e03c
fix: abort ongoing requests when changing pages (#3927) 2025-06-29 09:38:03 +02:00
Henrique Dias
2d1a82b73f
docs: improvements to building and docs (#5234) 2025-06-29 09:28:39 +02:00
dependabot[bot]
5a07291306
build(deps): bump brace-expansion from 1.1.11 to 1.1.12 in /tools (#5228)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-29 09:20:44 +02:00
transifex-integration[bot]
09f679fae4
feat: Translate frontend/src/i18n/en.json in fa (#5233)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-29 09:17:05 +02:00
Oleg Lobanov
9e273cd947
Revert "docs: change cloudflare environment (#5231)" (#5232)
This reverts commit 77d266bc00.
2025-06-28 22:38:51 +02:00
Oleg Lobanov
77d266bc00
docs: change cloudflare environment (#5231) 2025-06-28 22:30:37 +02:00
Oleg Lobanov
8861933cf8
build: publish docs to cloudflare pages (#5230) 2025-06-28 22:20:26 +02:00
transifex-integration[bot]
a5ea2a266b
feat: update translations for project File Browser (#5226)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-28 19:56:56 +02:00
Oleg Lobanov
f5e531c8ae
build: add an arm64 target for the site image (#5229) 2025-06-28 19:47:55 +02:00
Oleg Lobanov
6072540c3e
docs: migrate to MkDocs for site generation (#5227) 2025-06-28 19:34:34 +02:00
Henrique Dias
464b644adf
fix: add configurable minimum password length (#5225) 2025-06-28 10:07:34 +02:00
Henrique Dias
089255997a
fix: do not expose the name of the root directory (#5224) 2025-06-28 08:40:07 +02:00
dependabot[bot]
5331969163 build(deps): bump github.com/go-viper/mapstructure/v2 in /tools
Bumps [github.com/go-viper/mapstructure/v2](https://github.com/go-viper/mapstructure) from 2.2.1 to 2.3.0.
- [Release notes](https://github.com/go-viper/mapstructure/releases)
- [Changelog](https://github.com/go-viper/mapstructure/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-viper/mapstructure/compare/v2.2.1...v2.3.0)

---
updated-dependencies:
- dependency-name: github.com/go-viper/mapstructure/v2
  dependency-version: 2.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-27 21:52:15 +02:00
dependabot[bot]
f32f27383d build(deps): bump github.com/go-viper/mapstructure/v2
Bumps [github.com/go-viper/mapstructure/v2](https://github.com/go-viper/mapstructure) from 2.2.1 to 2.3.0.
- [Release notes](https://github.com/go-viper/mapstructure/releases)
- [Changelog](https://github.com/go-viper/mapstructure/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-viper/mapstructure/compare/v2.2.1...v2.3.0)

---
updated-dependencies:
- dependency-name: github.com/go-viper/mapstructure/v2
  dependency-version: 2.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-27 21:44:29 +02:00
Henrique Dias
0acd69c537
feat: Translate frontend/src/i18n/en.json in fa 2025-06-27 18:09:32 +02:00
Henrique Dias
ae4fb0ea25 chore: make as exception to mnd 2025-06-27 08:19:34 +02:00
Adrien Kohlbecker
8230eb7ab5 fix: Graceful shutdown 2025-06-27 08:19:34 +02:00
Henrique Dias
8b8fb3343f
ci: remove goconst 2025-06-27 08:03:11 +02:00
Oleksandr Redko
1d494ff315
build: bump golangci-lint to 2.1.6 2025-06-27 07:56:15 +02:00
Henrique Dias
da03728cd7
chore(release): 2.33.10 2025-06-26 21:23:35 +02:00
Henrique Dias
e735491c57
fix: ignore linting error 2025-06-26 21:12:24 +02:00
Henrique Dias
4d830f707f
fix: correctly check if command is allowed when using shell 2025-06-26 21:09:16 +02:00
Henrique Dias
f84a6db680
fix: correctly split shell 2025-06-26 21:07:45 +02:00
Henrique Dias
a430eb2e60
chore(release): 2.33.9 2025-06-26 19:45:36 +02:00
Henrique Dias
c232d41f90
fix: remove unused import 2025-06-26 19:43:20 +02:00
Henrique Dias
c1e4fd648b
docs: add warning regarding the custom commands feature 2025-06-26 19:42:13 +02:00
Henrique Dias
d5b39a14fd
fix: remove auth token from /api/command 2025-06-26 19:42:13 +02:00
Henrique Dias
e2e1e49130
fix: check exact match on command allow list 2025-06-26 19:42:12 +02:00
Henrique Dias
b0f92dd2d7
chore(release): 2.33.8 2025-06-25 20:53:47 +02:00
Henrique Dias
21b0827808
Merge commit from fork 2025-06-25 20:50:38 +02:00
Henrique Dias
d6d84e2b48
chore(release): 2.33.7 2025-06-25 17:47:23 +02:00
Henrique Dias
ca86f91621
Merge commit from fork 2025-06-25 17:42:39 +02:00
Henrique Dias
4bfbf33249
fix: linting issues 2025-06-25 17:37:18 +02:00
Henrique Dias
f19943a42e
Merge commit from fork 2025-06-25 17:35:15 +02:00
Henrique Dias
e74c958862
fix: linting issues 2025-06-25 17:34:00 +02:00
Henrique Dias
221451a517
fix: correctly parse negative boolean flags 2025-06-25 17:24:06 +02:00
Henrique Dias
f46641b038
chore(release): 2.33.6 2025-06-24 22:00:57 +02:00
Henrique Dias
23bd8f6715 fix: remove incorrect default for password flag 2025-06-24 21:43:44 +02:00
Henrique Dias
506fc08577
chore(release): 2.33.5 2025-06-24 17:11:40 +02:00
transifex-integration[bot]
f33076462a
feat: update languages for project File Browser (#5190)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-24 17:08:28 +02:00
Henrique Dias
6c29fabdc8
chore: remove cz_CS from transifex.yaml 2025-06-24 17:05:12 +02:00
Adam
0268506f80
fix: actually register the czech language (#5189) 2025-06-24 17:02:01 +02:00
Henrique Dias
ad864a97e9
chore(release): 2.33.4 2025-06-22 17:59:45 +02:00
transifex-integration[bot]
f714e71a35
feat: translation updates for project File Browser (#5179)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-22 17:59:23 +02:00
Henrique Dias
dbdbbab4d7
chore(release): 2.33.3 2025-06-22 17:57:34 +02:00
Henrique Dias
7c0c7820ef
fix: keep command behavior in Dockerfile 2025-06-22 17:55:57 +02:00
Arion2000
2741616473
fix: update search hotkey in help prompt (#5178) 2025-06-22 12:45:21 +02:00
Henrique Dias
ffb858e4ef
chore(release): 2.33.2 2025-06-21 10:37:30 +02:00
Henrique Dias
0ca8059d8d
fix: create user dir on signup 2025-06-21 10:32:50 +02:00
Henrique Dias
8ca080422f
chore(release): 2.33.1 2025-06-21 09:25:18 +02:00
Henrique Dias
cbb712484d fix: remove auth query parameter from download and preview links
macOS saves the download URL in the metadata of the downloaded file.
This means that the downloaded file contains a metadata item with the JWT
token of the user. If the user were to share this file with someone else,
they would have access to their account using the JWT in the metadata
during the validity of the JWT.

The JWT has been removed from the URLs. Since the user is logged in, there
is an authentication cookie set. A JWT in the URL is not necessary.
2025-06-21 09:21:39 +02:00
Patrick Wang
8a14018861
fix: downloadUrl of file preview (#3728) 2025-06-21 09:21:17 +02:00
Henrique Dias
a493ec90ff
docs: add more docker notes 2025-06-21 08:45:53 +02:00
Henrique Dias
33113036cd
docs: update security.md 2025-06-20 21:41:46 +02:00
contributor
a02b2972eb
fix: search uses ctrl+shift+f instead of hijacking browser's ctrl+f (#4638) 2025-06-19 21:57:57 +02:00
Henrique Dias
e9bb3dc243
chore(release): 2.33.0 2025-06-18 21:58:42 +02:00
Henrique Dias
2e26393a02
feat: improved docker image volumes and permissions (#5160) 2025-06-18 21:53:02 +02:00
Henrique Dias
04a13f086f
chore(release): 2.32.3 2025-06-17 16:47:53 +02:00
Henrique Dias
1cc539eb8a
ci: fix the post install tap command 2025-06-17 16:47:34 +02:00
Henrique Dias
6ebfdcceaa
chore(release): 2.32.2 2025-06-17 16:34:37 +02:00
Henrique Dias
db671c227b
ci: update gorelease homebrew 2025-06-17 16:34:04 +02:00
Henrique Dias
4aee14de44
ci: add @hacdias as codeowner 2025-06-17 16:30:02 +02:00
Henrique Dias
0cca7d8dc0
docs: move most docs to main repository (#5141) 2025-06-17 11:37:15 +02:00
transifex-integration[bot]
c34c0afecf
feat: updated for project File Browser (#5159)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-17 09:05:21 +02:00
Henrique Dias
56a0f9244b
chore(release): 2.32.1 2025-06-16 20:18:42 +02:00
michioxd
56b80b6d9b
feat: add Vietnamese translation (#3840) 2025-06-16 18:47:20 +02:00
Dev_Nergis
d9ebd65ffc
feat: update translation ko.json (#3852) 2025-06-16 18:35:50 +02:00
SOMA
a882fb6c85
feat: improve pt-br translations with new keys and refinements (#4903) 2025-06-16 17:39:57 +02:00
Henrique Dias
5daae69a6d
chore: revert only translated mode to transifex 2025-06-15 21:05:30 +02:00
Henrique Dias
54a1ae0fa0
chore: add only translated mode to transifex 2025-06-15 20:48:01 +02:00
Henrique Dias
b6b4fb5da7
ci: remove manual .tx config 2025-06-15 20:13:21 +02:00
Henrique Dias
6d82a27f9a
ci: add transifex.yml 2025-06-15 20:13:03 +02:00
Henrique Dias
31a326606d chore: updated readme and template 2025-06-13 22:46:22 +02:00
Henrique Dias
abbf203bdd chore: updated readme and templates 2025-06-13 22:46:22 +02:00
Henrique Dias
e82e2392a4 chore: update Go dependencies 2025-06-11 18:51:01 +02:00
Henrique Dias
f4a8420bf3
docs: add maintenance warning to readme 2025-06-11 17:44:32 +02:00
Simon
71a8f5662c
fix: set videojs locale (#3742)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-06-05 15:53:29 +02:00
Henrique Dias
48f894740f
chore: remove stale bot 2025-06-04 19:08:43 +02:00
Henrique Dias
b883e287a0
chore: migrate transifex settings 2025-06-04 18:58:48 +02:00
Henrique Dias
5d9f0977d6
Merge pull request #3675 from bo0tzz/fix/random-password 2025-06-04 17:39:32 +02:00
bo0tzz
c606a01a2d fix: err shadowing lint 2025-06-04 17:36:55 +02:00
bo0tzz
54b91b8ff0 fix: imports lint 2025-06-04 17:36:55 +02:00
bo0tzz
a46acba5f9 fix: generate random admin password on quick setup
This should help mitigate issues like #3646
2025-06-04 17:36:55 +02:00
Henrique Dias
1d14798653
Merge pull request #3776 from Matthaiks/pl 2025-06-04 17:35:00 +02:00
Matthaiks
6d55cc59f7 chore: Update Polish translation 2025-06-04 17:32:41 +02:00
Matthaiks
495e731ee7 Update Polish translation 2025-06-04 17:32:41 +02:00
Henrique Dias
ff1579b950
Merge pull request #3793 from Kcchouette/patch-1 2025-06-04 17:24:12 +02:00
Kcchouette
7a48fd0c3e
Merge branch 'master' into patch-1 2025-05-20 11:23:27 +00:00
dependabot[bot]
cfea84fd5e
build(deps): bump golang.org/x/net from 0.33.0 to 0.38.0 (#3869) 2025-05-19 12:27:04 +00:00
dependabot[bot]
0ba9505a19
build(deps): bump golang.org/x/crypto from 0.31.0 to 0.35.0 (#3865)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.31.0 to 0.35.0.
- [Commits](https://github.com/golang/crypto/compare/v0.31.0...v0.35.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.35.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-19 14:24:09 +02:00
dependabot[bot]
5355629fd1
build(deps-dev): bump vite from 6.0.11 to 6.1.6 in /frontend (#3886)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.0.11 to 6.1.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.1.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.1.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.1.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-19 13:49:42 +02:00
Kcchouette
f8a16a6aca
Merge branch 'master' into patch-1 2025-04-19 09:22:44 +00:00
dependabot[bot]
35d1c09243
build(deps): bump vue-i18n from 11.0.1 to 11.1.2 in /frontend (#3786)
Bumps [vue-i18n](https://github.com/intlify/vue-i18n/tree/HEAD/packages/vue-i18n) from 11.0.1 to 11.1.2.
- [Release notes](https://github.com/intlify/vue-i18n/releases)
- [Changelog](https://github.com/intlify/vue-i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n/commits/v11.1.2/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 17:03:45 +01:00
Kcchouette
99c64c12ed
Update french translation 2025-03-10 21:04:12 +00:00
Oleg Lobanov
3d6c5152fe
chore(release): 2.32.0 2025-01-31 09:48:22 +01:00
Oleg Lobanov
ba797cda31
build: fix go releaser 2025-01-31 09:48:08 +01:00
Arran Hobson Sayers
5300d00d2e
fix: Fix user creation on proxy auth (#3666)
* Fix user creation on proxy auth

* Refactoring

---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-30 11:28:19 +01:00
elmodor
bbdd313705
fix: disk usage refreshing (#3692)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-30 10:32:05 +01:00
Eden Yemini
045064f8b8
fix: add proper healthcheck for S6 containers (#3691)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-30 10:29:14 +01:00
정성민
252f0a7533
chore: update ko.json (#3688) 2025-01-30 10:24:44 +01:00
dependabot[bot]
1194cfe009
build(deps): bump golang.org/x/net from 0.23.0 to 0.33.0 (#3712)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.23.0 to 0.33.0.
- [Commits](https://github.com/golang/net/compare/v0.23.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-30 10:22:04 +01:00
kloon15
0201f9c5c4
refactor: Fix eslint warnings (#3698)
* Update dependencies and remove typescript version pinning (fixed upstream)

* Fix esling warnings (disabled any and script lang checks)
Rewrote clipboard copy (Fixes #3407)
Run prettier

---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-30 10:18:48 +01:00
Juan Bernárdez
cc331383fb
chore: add translation for the "Hide dot files setting" in "es" (Spanish) language (#3704) 2025-01-30 10:16:40 +01:00
Ryan
d1c84a8412
fix: prompts disappearing on copy / move / upload (#3537)
---------

Co-authored-by: Ryan Miller <ryan.miller@infinitetactics.com>
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-21 00:05:59 +01:00
dependabot[bot]
e92dbb4bb8
build(deps): bump golang.org/x/crypto from 0.26.0 to 0.31.0 (#3634)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.26.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.26.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-16 22:07:57 +01:00
Arran Hobson Sayers
209acf2429
feat: create user on proxy authentication if user does not exist (#3569)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2024-12-16 22:05:13 +01:00
dependabot[bot]
25372edb5c
build(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /tools (#3601)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 18:02:05 +01:00
kloon15
d51a343820
build: update to node 22 and pnpm (#3616)
This commit brings the project to support node 22 which became LTS and
fixes broken builds with typescript 5.7+ until vue-tsc is updated and
replaces npm with pnpm.

- Update tsconfig for node 22
- Pin typescript to 5.6.x to not break vue-tsc
- Replace npm with pnpm (corepack recommended)
- Update Makefile and main workflow for pnpm
- Migrate to eslint 9 flat config
- Fix broken imports
- Exclude non-TS vue files for vue-tsc
2024-12-09 12:27:18 +01:00
dependabot[bot]
065959451d
build(deps): bump vue-i18n from 9.10.2 to 9.14.2 in /frontend (#3618)
Bumps [vue-i18n](https://github.com/intlify/vue-i18n/tree/HEAD/packages/vue-i18n) from 9.10.2 to 9.14.2.
- [Release notes](https://github.com/intlify/vue-i18n/releases)
- [Changelog](https://github.com/intlify/vue-i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n/commits/v9.14.2/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 12:54:38 +01:00
dependabot[bot]
2fdea73430
build(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 (#3574) 2024-11-05 06:49:45 +01:00
Oleg Lobanov
129a4fd39d
chore(release): 2.31.2 2024-10-03 15:11:19 +02:00
Elisabeth Ryder
64400ffda8
fix: files list alignment (#3494) 2024-09-30 11:40:20 +02:00
dependabot[bot]
03d74ee758
build(deps): bump rollup from 4.21.3 to 4.22.4 in /frontend (#3504)
Bumps [rollup](https://github.com/rollup/rollup) from 4.21.3 to 4.22.4.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.21.3...v4.22.4)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-30 11:05:41 +02:00
Angelfisch
2b37e696c9
fix: added whitespace before version (#3510) 2024-09-30 11:05:23 +02:00
Andreas Deininger
21d5ee1b97
chore: bump 'actions/stale' to latest version (#3489) 2024-09-30 11:01:43 +02:00
dependabot[bot]
ec7b643e8e
build(deps-dev): bump vite from 5.2.7 to 5.4.6 in /frontend (#3496)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.2.7 to 5.4.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-23 19:29:28 +02:00
Andreas Deininger
d729701bd4
chore: fix typos (#3490) 2024-09-23 11:55:07 +02:00
Marek Ištok
406d4f7884
fix: change location of custom init scripts (#3493)
Co-authored-by: niraami <contact@niraami.com>
2024-09-23 11:34:39 +02:00
knrdl
1e7c41505f
fix: german translation spelling typos (#3469) 2024-09-23 11:25:53 +02:00
Oleg Lobanov
bb5d192095
chore(release): 2.31.1 2024-08-30 21:25:29 +02:00
n-i-x
121d9abecd
fix: command not found in shell (#3438) 2024-08-30 21:24:45 +02:00
Oleg Lobanov
7de6bc4a91
build: update to alpine 3.20 (#3447)
* add execute permission to s6 scripts

* update s6 base image to 3.20

* Update aarch64 docker image

---------

Co-authored-by: Ryan Winter <ryanwinter@outlook.com>
2024-08-30 21:18:19 +02:00
Oleg Lobanov
2369e5c0ed
chore(release): 2.31.0 2024-08-30 00:01:22 +02:00
Oleg Lobanov
056cfa8fac
build: fix goreleaser file 2024-08-30 00:01:11 +02:00
Oleg Lobanov
e7d77106ab
Merge pull request #3436 from filebrowser/go_1.23.0 2024-08-29 23:49:37 +02:00
Oleg Lobanov
a6347c8858
build: bump golangci-lint to 1.60.3 2024-08-29 23:47:12 +02:00
Oleg Lobanov
b596567c61
build: bump go libs 2024-08-29 23:42:07 +02:00
Oleg Lobanov
364fdaaf0c
build: bump go version to 1.23.0 2024-08-29 23:33:55 +02:00
Oleg Lobanov
8b75aefb1c
chore: fix frontend audit 2024-08-29 23:31:35 +02:00
ultwcz
b0f4604f44
feat: implement markdown file preview in Ace editor (#3431)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2024-08-29 23:04:10 +02:00
Enzo Hamelin
f6f7e5fea3
feat: support mime type for epub extension (#3425) 2024-08-29 22:45:05 +02:00
quandaledingle44
043cdbf402
chore: minor fixup to Ukrainian translation (#3421) 2024-08-28 21:12:32 +02:00
Adam
8e67a12f26
feat: add Czech translation (#3416) 2024-08-27 10:49:33 +02:00
Oleg Lobanov
83898d616f
chore: fix frontend lint 2024-08-18 13:51:16 +02:00
Oleg Lobanov
090272e3b7
fix: fix catalan i18n file 2024-08-17 19:30:22 +02:00
Mercury233
10bf3cffbf
fix(frontend): N files selected hint use i18n (#3390) 2024-08-17 19:09:38 +02:00
Dmitriy
99a6382b32
feat: Added epub preview. Resolves #3375 (#3376) 2024-08-17 19:07:55 +02:00
rogodra
a53aac1c30
chore: Add Catalan Language (#3347) 2024-08-17 18:58:11 +02:00
Daniel
21783ed91a
fix: pull down to refresh within editor (#3378)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2024-07-30 22:14:41 +02:00
Alex Yong
7be5644952
fix: fixing an issue where the upload indicator would "jump" around in the UI (#3354) 2024-07-30 22:11:44 +02:00
dependabot[bot]
30a8ddf113
build(deps): bump golang.org/x/image from 0.15.0 to 0.18.0 (#3335)
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.15.0 to 0.18.0.
- [Commits](https://github.com/golang/image/compare/v0.15.0...v0.18.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-29 20:26:47 +02:00
dependabot[bot]
c3465f9913
build(deps-dev): bump ws from 8.16.0 to 8.17.1 in /frontend (#3321)
Bumps [ws](https://github.com/websockets/ws) from 8.16.0 to 8.17.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.16.0...8.17.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 14:51:09 +02:00
dependabot[bot]
e8589be640
build(deps-dev): bump braces from 3.0.2 to 3.0.3 in /frontend (#3316)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 14:50:51 +02:00
Oleg Lobanov
eb3978ea55
chore(frontend): fix formatting 2024-06-08 22:20:58 +02:00
Beeant
d6cdf0e435
chore: listing.list name auto wrap (#3208) 2024-06-08 22:09:10 +02:00
kloon15
1fccc5d649
fix: clipboard copy in safari (#3261) 2024-06-08 21:56:48 +02:00
Andrés Bono
a8388689f3
fix: pdf preview header (#3274) 2024-06-08 21:55:46 +02:00
Andrés Bono
2a90cdfdaf
fix: CSS selectors for listing icons (#3277) 2024-06-08 21:54:06 +02:00
Oleg Lobanov
6ca3d5a573
chore(release): 2.30.0 2024-05-19 12:01:40 +02:00
kloon15
3b48f75301
fix: add overlay for sidebar on mobile (#3197) 2024-05-19 12:00:31 +02:00
古大羊
4c5b612cb2
fix: shell window size (#3198) 2024-05-19 12:00:10 +02:00
古大羊
e336a25ad2
fix: current folder name in page title (#3200) 2024-05-11 22:27:06 +02:00
古大羊
c9e05f98c4
chore: Optimize upload indicator display (#3202) 2024-05-11 22:22:17 +02:00
古大羊
be62f56782
feat: Enhance MIME Type Detection for Additional File Extensions (#3183) 2024-05-03 19:59:45 +02:00
Andrés Bono
2e47a038d6
feat: allow multi-select with SHIFT key in singleClick mode (#3185) 2024-05-03 12:40:39 +02:00
古大羊
a9c327cc06
fix: The file type icon in the file list is sensitive to the case of the suffix name (#3187) 2024-05-03 11:31:07 +02:00
古大羊
782375b1cb
fix: Fixing the inability to play MKV video files online and enhancing the auxiliary features of the VideoPlayer. (#3181) 2024-05-03 11:29:21 +02:00
古大羊
5d5e8ed422
chore: update zh-cn.json and zh-tw.json (#3186) 2024-05-02 14:53:41 +02:00
Oleg Lobanov
5f57cf9e41
chore(release): 2.29.0 2024-04-30 14:40:28 +02:00
古大羊
4786187852
fix: the copy method in clipboard.ts (#3177) 2024-04-30 14:35:55 +02:00
Alex Yong
236ca637f9
feat: Display Upload Progress as Percentage and File Size / Total File Size (#3111) 2024-04-28 20:40:24 +02:00
Piotr Markiewicz
e2d72706cc
Fixed preview for pdf and missing video coded message (#3163)
Co-authored-by: Piotr Markiewicz <piotr.markiewicz@vaimo.com>
2024-04-28 20:02:26 +02:00
Piotr Markiewicz
da5a6e051f
fix: don't redirect to login when no auth (#3165)
Co-authored-by: Piotr Markiewicz <piotr.markiewicz@vaimo.com>
2024-04-28 20:00:42 +02:00
古大羊
bee71d93fe
Fix: Frontend bug, administrators unable to delete users (#3170) 2024-04-28 19:52:05 +02:00
kloon15
821f51ea5a
fix: apply proper zindex to modal dialogs (#3172) 2024-04-28 19:49:25 +02:00
Alex Yong
434e49bf59
fix: abort upload behavior to properly handle server-side deletion and frontend state reset (#3114)
* Fixed an issue where aborting an upload would not delete the partial upload from the server. Also fixed an issue where the abortAll function wasn't resetting and reloading the frontend properly

* Add server-side tus delete handler

---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2024-04-25 01:23:44 +02:00
loselarry
61f25086c3
chore: fix some typos in comments (#3108)
Signed-off-by: loselarry <bikangning@yeah.net>
2024-04-24 23:15:18 +02:00
Andrew Kennedy
18f04a7d26
fix: handle quotes in healthcheck.sh (#3130)
This file as is makes a value of `"localhost"` as the address in the .filebrowser.json file read in as `"localhost"` instead of `localhost`. These quotes break the curl command. Using `-r` with jq fixes this.
2024-04-24 23:13:56 +02:00
trmdi
22a05e1f02
fix: correct list item selector (#3126) (#3147) 2024-04-24 23:12:46 +02:00
Oleg Lobanov
b4b4b0efc9
ci: fix permission for pr-lint 2024-04-24 23:10:41 +02:00
Oleg Lobanov
8fd6c55a0e
ci: refactor pr-lint workflow 2024-04-24 23:09:55 +02:00
Oleg Lobanov
a9da7fd56c
build: bump go version to 1.22.2 (#3158) 2024-04-24 23:08:12 +02:00
dependabot[bot]
6b77b8d683
build(deps): bump golang.org/x/net from 0.22.0 to 0.23.0 (#3133)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-24 23:02:21 +02:00
Oleg Lobanov
e39ea73095
ci: add pr lint workflow (#3157) 2024-04-24 22:51:37 +02:00
Sergey Ponomarev
0e0b0c8095
chore: remove language names from translations (#3140)
---------

Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
2024-04-24 22:41:40 +02:00
Oleg Lobanov
ae0af1f996
chore: fix golangci-lint errors 2024-04-01 18:24:06 +02:00
Oleg Lobanov
d194d71293
deps: upgrade go libs 2024-04-01 17:28:30 +02:00
Oleg Lobanov
bbd0abbdfd
build: bump go version to 1.22.1 2024-04-01 17:26:56 +02:00
kloon15
5100e587d7
feat: migrate to vue 3 (#2689)
---------

Co-authored-by: Joep <jcbuhre@gmail.com>
Co-authored-by: Omar Hussein <omarmohammad1951@gmail.com>
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2024-04-01 17:18:22 +02:00
Oleg Lobanov
0e3b35b30e
chore(release): 2.28.0 2024-04-01 16:22:00 +02:00
dependabot[bot]
05bfae264a
build(deps): bump google.golang.org/protobuf from 1.31.0 to 1.33.0 (#3045)
Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-17 21:58:00 +01:00
niubility000
4c233c3db3
feat: enable preview in shared folder (#3055) 2024-03-17 21:53:33 +01:00
dependabot[bot]
7797a4ef18
build(deps): bump google.golang.org/protobuf in /tools (#3044)
Bumps google.golang.org/protobuf from 1.28.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-14 11:36:17 +01:00
niubility000
d70650689c
feat: auto hiding header bar in preview to enlarge the preview window (#3024) 2024-03-07 11:25:01 +01:00
niubility000
8dddc8a450
chore: show the current used filebrowser.db in cmd window (#3028) 2024-03-07 11:16:41 +01:00
niubility000
cdf8def330
fix: stay in the same position after renaming or deleting (#3039) 2024-03-07 11:14:40 +01:00
niubility000
e167c3e1ef
feat: freezing the list in the backgroud while previewing a file (#3004) 2024-02-22 19:42:36 +01:00
ねらひかだ
fe5ca74aa1
fix: fix lint warnings (#2976) 2024-02-09 11:05:35 +01:00
ねらひかだ
dfad87386f
chore: update github action versions (#2977) 2024-02-09 11:05:09 +01:00
Shlomo
6d7ba65faf
fix: shell direction (#2980) 2024-02-09 11:04:02 +01:00
Feriman
d5487ba6fa
chore: add noindex (#2981) 2024-02-09 11:03:06 +01:00
zoui
34a08170c8
fix: editor discard prompt (#2990) 2024-02-09 11:01:41 +01:00
Shlomo
d49c3dfacf
feat: select multiple files with ctrl even with singleClick option (#2953) 2024-01-30 10:49:35 +01:00
Shlomo
2cfee2183c
fix: dashboard buttons position in rtl layout (#2949) 2024-01-30 10:48:32 +01:00
Shlomo
fb1a09c7c1
feat: prompt to confirm discard editor changes (#2948)
* chore: update he.json

* feat: prompt to confirm discard editor changes

---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2024-01-30 10:48:03 +01:00
Shlomo
b19710efca
feat: focus editor when opened (#2946) 2024-01-30 10:44:20 +01:00
Shlomo
ff9502ff34
fix: keyboard shortcut to confirm prompts (#2932) 2024-01-30 10:44:00 +01:00
Shlomo
62f0dfb302
chore: update he.json (#2933) 2024-01-30 10:37:47 +01:00
Quentin McGaw
81cd8fc6d3
fix(healthcheck): use address configured if not empty (#2938) 2024-01-30 10:37:17 +01:00
Shlomo
70c826133b
feat: close editor when click escape key (#2947) 2024-01-30 10:29:37 +01:00
Shlomo
2f6c473977
chore: update pull request template (#2950) 2024-01-30 10:23:41 +01:00
dependabot[bot]
bf36cc00f1
build(deps-dev): bump vite from 4.4.12 to 4.5.2 in /frontend (#2951)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.12 to 4.5.2.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v4.5.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.5.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-30 10:22:48 +01:00
Shlomo
883383a571
fix: moment locale (#2952) 2024-01-30 10:16:32 +01:00
ねらひかだ
0a05f8c01f
chore(i18n): improvement of Japanese translation (#2962) 2024-01-30 10:15:27 +01:00
ねらひかだ
a4b089a6db
feat: allow to configure if home directory is automatically created from cli (#2963) 2024-01-30 10:14:50 +01:00
ねらひかだ
5c5ab6b875
fix: files and directories are created with the correct permissions (#2966) 2024-01-30 10:12:38 +01:00
Oleg Lobanov
04e03a83b4
chore(release): 2.27.0 2024-01-02 18:29:29 +04:00
Yogesh
c4e955acf4
fix: typo in build error #2903 (#2904) 2023-12-31 14:32:54 +01:00
People-11
fc04578e28
Update zh-cn.json (#2875) 2023-12-28 10:30:52 +01:00
Shlomo
3264cea830
fix: delete message when delete file from preview 2023-12-28 10:11:53 +01:00
Yarden Shoham
748af7172c
feat: allow setting theme via cli (#2881) 2023-12-28 09:52:40 +01:00
Shlomo
da595326ee
chore: update he.json (#2877) 2023-12-28 09:44:58 +01:00
dependabot[bot]
821fba41a2
build(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#2890)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-28 09:44:24 +01:00
Omar Hussein
cfafefa35a
chore: update Arabic and English translations (#2823) 2023-12-06 11:21:04 +01:00
Fritz Lin
391a078cd4
feat: make user session timeout configurable by flags (#2845) 2023-12-06 11:19:30 +01:00
dependabot[bot]
fc2ee37353
build(deps-dev): bump vite from 4.4.9 to 4.4.12 in /frontend (#2862)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.9 to 4.4.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v4.4.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.4.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-06 11:09:33 +01:00
M A E R Y O
a09dfa8d9f
feat: display image resolutions in file details (#2830)
---------

Co-authored-by: MAERYO <maeryo@hanwha.com>
2023-11-25 13:35:00 +01:00
ねらひかだ
4dbc802972
fix: fix typo (#2843) 2023-11-25 13:29:43 +01:00
Emmanuel Frecon
d59ad594b8
fix: set correct port in docker healthcheck (#2812)
When the `FB_PORT` environment variable is set, respect its value. Otherwise, pick the port from the configuration.
2023-11-08 17:59:46 +01:00
Oleg Lobanov
a4cb813ddf
chore(release): 2.26.0 2023-11-02 22:49:15 +01:00
Oleg Lobanov
4d0a68e787
fix: goreleaser yaml 2023-11-02 22:48:29 +01:00
dependabot[bot]
a744bd224f
build(deps): bump golang.org/x/image from 0.5.0 to 0.10.0 (#2800)
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.5.0 to 0.10.0.
- [Commits](https://github.com/golang/image/compare/v0.5.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 22:36:32 +01:00
Oleg Lobanov
da1fe7c9d7
fix: disable static resource files listing 2023-11-02 22:23:20 +01:00
Dardan
7fabadc871
feat: make user session timeout configurable (#2753)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2023-11-02 22:01:56 +01:00
Isaak Tsalicoglou
c3079d30e2
feat: add modern greek translation (#2778)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2023-11-02 21:55:22 +01:00
shonge
6a31af6c0a
fix: solve docker build failed issue (#2797) 2023-11-02 21:38:00 +01:00
dependabot[bot]
21d361ad30
build(deps-dev): bump postcss from 8.4.27 to 8.4.31 in /frontend (#2749)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.27 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.27...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 09:09:01 +01:00
dependabot[bot]
d574fb6d1a
build(deps): bump golang.org/x/net from 0.11.0 to 0.17.0 (#2758)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.11.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.11.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 09:03:48 +01:00
dependabot[bot]
bb4bb508a9
build(deps): bump @babel/traverse in /frontend (#2775)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.10 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 09:03:28 +01:00
bufubaoni
edd808f124
fix: avoid the front-end calling api/renew loop (#2792) 2023-11-02 09:02:51 +01:00
kloon15
cdcd9a313a
fix: display file size as base 2 (KiB instead of KB) (#2779) 2023-11-02 08:47:55 +01:00
Isaak Tsalicoglou
d0c3aeace1
chore: update en translation (#2777) 2023-11-02 08:43:50 +01:00
Isaak Tsalicoglou
9484454584
chore: update en translation (#2776) 2023-11-02 08:43:32 +01:00
kloon15
bd3c1941ff
fix: revert fetchURL changes in auth (Fixes #2729) (#2739) 2023-10-01 18:09:13 +02:00
Oleg Lobanov
01f7842a18
docs: add demo url to README 2023-09-15 01:11:47 +02:00
Oleg Lobanov
38f7788255
build: fix deprecated goreleaser config options 2023-09-15 00:59:16 +02:00
Oleg Lobanov
c1fb4004f7
chore(release): 2.25.0 2023-09-15 00:51:58 +02:00
Cameron
584b706b1e
feat: added shell resizing (#2648) 2023-09-15 00:50:40 +02:00
M A E R Y O
ecdd684bf1
feat: implement upload speed calculation and ETA estimation (#2677) 2023-09-15 00:41:36 +02:00
Oleg Lobanov
36af01daa6
fix: tus upload with cloudflare proxy
closes #2593
2023-09-15 00:39:37 +02:00
Thomas
d0c3b8033d
chore: update German translation (#2616) 2023-09-10 14:35:51 +02:00
kloon15
aa00c1c89c
chore: fixes for vite dev server (#2678) 2023-08-29 20:14:45 +02:00
M A E R Y O
a404fb043d
feat: implement abort upload functionality (#2673) 2023-08-27 23:59:49 +02:00
M A E R Y O
95fec7f694
fix: refactor path resolution logic for project root (#2674)
---------

Co-authored-by: MAERYO <maeryo@hanwha.com>
2023-08-27 23:52:33 +02:00
ArthurMousatov
5994224468
feat: add new folder button to move/create dialogs (#2667)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2023-08-27 00:28:58 +02:00
古大羊
374bbd3ec1
perf(backend): optimize subtitles detection performance (#2637) 2023-08-26 14:53:18 +02:00
Oleg Lobanov
2c97573301
build: bump go version to 1.21.0 (#2672) 2023-08-26 14:16:10 +02:00
Oleg Lobanov
70eba7ecc9
build: bump node version to 18 (#2671) 2023-08-26 14:10:07 +02:00
Oleg Lobanov
7a4d0c0c08
chore: fix frontend dev proxy settings 2023-08-26 14:01:01 +02:00
kloon15
8838a09cf5
refactor: migrate frontend tooling to vite 4 (#2645)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2023-08-26 13:55:51 +02:00
Oleg Lobanov
184b7c14f2
chore(release): 2.24.2 2023-08-08 22:30:21 +02:00
M A E R Y O
289c8e6f32
fix: 403 error error when uploading (#2598)
Co-authored-by: 김종성 <ziippy@naver.com>
2023-08-08 22:29:03 +02:00
putty182
ff1e0b8185
fix: config init for branding.disableUsedPercentage (#2576) (#2596) 2023-08-05 11:53:42 +02:00
MichaIng
0ac39684f1
build: add riscv64 binary releases (#2587)
Signed-off-by: MichaIng <micha@dietpi.com>
2023-08-01 15:00:42 +02:00
Oleg Lobanov
fa390c498d
chore(release): 2.24.1 2023-07-31 13:33:09 +02:00
M A E R Y O
4b72bbfc7f
Remove redundant calls to baseURL/url #2581 (#2579)
---------

Co-authored-by: 이광오 <maeryo@hanwha.com>
Co-authored-by: Oleg Lobanov <oleg.lobanov@bitvavo.com>
2023-07-31 13:27:24 +02:00
M A E R Y O
2a4a46c61a
fix: resolved CSS rendering issue in Chrome browser (#2582)
Co-authored-by: 이광오 <maeryo@hanwha.com>
2023-07-31 13:08:30 +02:00
Oleg Lobanov
efd41cc4c1
build(backend): upgrade golangci-lint to v1.53.3 2023-07-31 12:51:00 +02:00
M A E R Y O
912f27a9e3
fix: add directory creation code to partial upload handler (#2575) (#2580) 2023-07-31 12:38:11 +02:00
M A E R Y O
4e28cc13c9
chore: removed duplicate z-index (#2583)
Co-authored-by: 이광오 <maeryo@hanwha.com>
2023-07-31 11:21:58 +02:00
Oleg Lobanov
f37513c45e
chore(release): 2.24.0 2023-07-29 11:32:30 +02:00
Oleg Lobanov
4d77ce0955
build: remove armv7-s6 docker target 2023-07-29 11:30:50 +02:00
Oleg Lobanov
66dfbb303c
build: remove armv6-s6 docker target 2023-07-29 00:26:32 +02:00
Oleg Lobanov
9bf6b856e5
build(backend): bump go version to 1.20.6 2023-07-28 23:56:57 +02:00
Oleg Lobanov
051104bfa0
fix: goreleaser docker build 2023-07-28 23:54:39 +02:00
Vinicius Almendra
b8ee3404ee
fix: solve broken Docker build with alpine image (#2486) 2023-07-28 18:34:21 +02:00
slhmy
853ec906ef
fix: error while using fallback of dir move (#2349) 2023-07-28 18:24:42 +02:00
Tobias Goerke
7b35815754
feat: integrate tus.io for resumable and chunked uploads (#2145) 2023-07-28 18:15:44 +02:00
ArthurMousatov
2744f7d5b9
fix: added an early return on non-existent items (#2571) 2023-07-27 18:03:49 +02:00
Anchit Bajaj
b508ac3d4f
fix: xss vulnerability in /api/raw (#2570) (#2572) 2023-07-27 11:42:27 +02:00
Andrew Kennedy
ff4375cf6c
feat: add a healthcheck script that works with a dynamic port (#2510) 2023-07-22 23:07:15 +02:00
dependabot[bot]
a664ba1f9d
build(deps): bump minimatch from 3.0.4 to 3.1.2 in /tools (#2561)
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-22 22:38:34 +02:00
dependabot[bot]
bb3486286c
build(deps-dev): bump word-wrap from 1.2.3 to 1.2.4 in /frontend (#2556)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-22 21:24:50 +02:00
ChengDaqi2023
ecfcbfd216
chore: update golang.org/x/net v0.6.0 to 0.7.0 (#2559) 2023-07-22 21:24:28 +02:00
Daniel Li
9bcfa900f9
fix: filter ANSI color for shell (#2529)
* feat: filter ANSI color for shell

* chore: fix formatting

---------

Co-authored-by: Oleg Lobanov <oleg.lobanov@bitvavo.com>
2023-07-20 17:38:53 +02:00
dependabot[bot]
c2f1423c02
build(deps): bump semver from 5.7.1 to 5.7.2 in /tools (#2546)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-17 11:47:56 +02:00
ULiiAn
6744cd47ce
fix: video preview click next or prev button subtitles not update (#2423) 2023-05-01 13:09:44 +02:00
Yeicor
a4ef02a47b
feat: add option to copy download links from shares (#2442) 2023-05-01 13:07:01 +02:00
Oleg Lobanov
1a5b999545
Merge pull request #2345 from filebrowser/go_1.20.1
build(backend): bump go version to 1.20.1
2023-02-16 09:22:57 +01:00
Oleg Lobanov
10d628aecc
chore: upgrade golangci-lint to 1.51.1 2023-02-16 09:19:44 +01:00
Oleg Lobanov
fa95299df4
build(backend): bump go version to 1.20.1 2023-02-15 23:43:20 +01:00
Oleg Lobanov
fd22e0b163
chore(backend): upgrade deps 2023-02-15 23:39:52 +01:00
Gabriel Alencar
428c1c606d
feat: add a new setting that disables the display of the disk usage (#2136) 2023-02-15 23:30:48 +01:00
Yonas Yanfa
60d1e2d291
fix: build on FreeBSD and non-Linux platforms (#2332) 2023-02-06 18:34:25 +01:00
Gyuris Gellért
11e9202160
feat: add Hungarian translation (#2232) 2022-12-26 22:36:03 +01:00
Davide Quaranta
59619ba34f
chore: update Italian translation (#2260) 2022-12-23 13:07:06 +01:00
brlarini
73dd066670
chore: update pt-br translations (#2248) 2022-12-23 13:06:19 +01:00
Yasin Silavi
2b2c1085fb
refactor: replace username old focus logic with the autofocus attribute (#2223) 2022-11-25 12:26:07 +01:00
Oleg Lobanov
02db83c72e
chore(release): 2.23.0 2022-11-05 18:53:29 +01:00
dependabot[bot]
3a0dace9a9
build(deps): bump ansi-html and webpack-dev-server in /frontend (#2184)
Removes [ansi-html](https://github.com/Tjatse/ansi-html). It's no longer used after updating ancestor dependency [webpack-dev-server](https://github.com/webpack/webpack-dev-server). These dependencies need to be updated together.


Removes `ansi-html`

Updates `webpack-dev-server` from 3.11.2 to 3.11.3
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/v3.11.3/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v3.11.2...v3.11.3)

---
updated-dependencies:
- dependency-name: ansi-html
  dependency-type: indirect
- dependency-name: webpack-dev-server
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-22 15:50:34 +02:00
thewh1teagle
a5757b94e8
fix: missing video controls on mobile (#2180) 2022-10-22 11:16:59 +02:00
leplan73
1ebfc64ea1
chore: updated golang.org/x/text to v0.4.0 (#2176) 2022-10-22 11:11:02 +02:00
thewh1teagle
2c14146a31
feat: add rtl support (#2178) 2022-10-21 18:07:11 +02:00
thewh1teagle
a49105db1d
feat: hebrew translation (#2168) 2022-10-20 12:27:59 +02:00
Ltzhu76
0401adf7f4
fix: modify the delete confirmation interface logic. (#2138) 2022-09-24 19:05:50 +02:00
Oleg Lobanov
c1e6d5869a
ci: increase operations-per-run param to 100 2022-08-30 10:18:12 +02:00
Oleg Lobanov
db0a23aec0
chore: fix exempt-issue-labels of the stale action 2022-08-29 20:02:13 +02:00
Oleg Lobanov
350c73d78e
ci: fix stale action permissions 2022-08-29 19:38:30 +02:00
Oleg Lobanov
daf36b28fd
ci: close stale issues and PRs 2022-08-29 19:25:50 +02:00
Marcelina Hołub
57c99e0e26
feat: update Polish translation (#2089) 2022-08-17 20:18:51 +02:00
dependabot[bot]
aaed985699
build(deps): bump terser from 4.8.0 to 4.8.1 in /frontend (#2054)
Bumps [terser](https://github.com/terser/terser) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-22 15:32:39 +02:00
Oleg Lobanov
0ed32c6af8
Merge pull request #1554 from ramiresviana/auth-hook
Hook authentication method
2022-07-22 15:31:28 +02:00
Ramires Viana
dda9a389f3 feat: hook authentication method 2022-07-20 16:40:49 +02:00
Ángel Fernández Sánchez
f80b016ef0
chore: update es translation (#2046) 2022-07-20 12:17:52 +02:00
Oleg Lobanov
ceec4dcfe6
chore(release): 2.22.4 2022-07-19 00:59:29 +02:00
Oleg Lobanov
7177184678
chore: remove dependency on caddy server 2022-07-19 00:58:50 +02:00
Oleg Lobanov
0523b31b96
Merge pull request #2044 from filebrowser/security_fix 2022-07-19 00:42:45 +02:00
Oleg Lobanov
80030dee32
fix: disable cookie auth for non GET requests 2022-07-19 00:39:02 +02:00
dependabot[bot]
cb43770025
build(deps): bump moment from 2.29.2 to 2.29.4 in /frontend (#2036)
Bumps [moment](https://github.com/moment/moment) from 2.29.2 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.2...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-12 12:09:06 +02:00
dependabot[bot]
eaba7e5255
build(deps): bump shell-quote from 1.7.2 to 1.7.3 in /frontend (#2025)
Bumps [shell-quote](https://github.com/substack/node-shell-quote) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/substack/node-shell-quote/releases)
- [Changelog](https://github.com/substack/node-shell-quote/blob/master/CHANGELOG.md)
- [Commits](https://github.com/substack/node-shell-quote/compare/v1.7.2...1.7.3)

---
updated-dependencies:
- dependency-name: shell-quote
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-12 11:49:36 +02:00
Oleg Lobanov
49dbacdccd
chore(release): 2.22.3 2022-07-05 16:58:52 +02:00
Oleg Lobanov
d94acdd89a
fix: use correct field name in user put api (#2026) 2022-07-05 16:55:31 +02:00
源文雨
06d9c03e92
chore(deps): move golang.org/x/text to direct (#2021) 2022-07-05 16:27:33 +02:00
Oleg Lobanov
9d54046140
chore(release): 2.22.2 2022-07-01 17:21:46 +02:00
Oleg Lobanov
dec3d629d4
fix: display disk capacity in a correct format (#2013) 2022-07-01 16:31:49 +02:00
Oleg Lobanov
8118afd0ac
build(backend): upgrade golangci-lint to 1.46.2 (#1991) 2022-06-13 16:13:10 +02:00
langren1353
577c0efa9c
fix: don't calculate usage for files (#1973)
* fix: use incorrect suffix and return no 500(#1972、#1967)

* chore: set progress bar to small

Co-authored-by: Ramires Viana <59319979+ramiresviana@users.noreply.github.com>

* chore: refactoring

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
Co-authored-by: Ramires Viana <59319979+ramiresviana@users.noreply.github.com>
2022-06-13 12:50:39 +02:00
Po Chen
dcf0bc65bf
fix: preview url building fix (#1976) 2022-06-10 12:05:05 +02:00
Oleg Lobanov
c211b96719
chore(release): 2.22.1 2022-06-06 16:59:25 +02:00
Jeffrey Schiller
1e7d3b25c2
fix: use correct basepath prefix for preview urls (#1971) 2022-06-06 16:57:19 +02:00
Oleg Lobanov
b16982df0f
build(backend): bump go version to 1.8.3 2022-06-03 16:13:56 +02:00
Oleg Lobanov
540ddf47a7
chore(release): 2.22.0 2022-06-03 16:11:07 +02:00
Oleg Lobanov
02730bb9bf
fix: set correct scope when user home creation is enabled 2022-06-03 16:04:15 +02:00
Oleg Lobanov
d1d8e3e340
feat: add disk usage information to the sidebar 2022-06-02 13:16:37 +02:00
Oleg Lobanov
42a39b3f1d
Merge pull request #1965 from filebrowser/dependabot/npm_and_yarn/frontend/eventsource-1.1.1
build(deps): bump eventsource from 1.1.0 to 1.1.1 in /frontend
2022-06-02 11:18:53 +02:00
dependabot[bot]
dd503695a1
build(deps): bump eventsource from 1.1.0 to 1.1.1 in /frontend
Bumps [eventsource](https://github.com/EventSource/eventsource) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/EventSource/eventsource/releases)
- [Changelog](https://github.com/EventSource/eventsource/blob/master/HISTORY.md)
- [Commits](https://github.com/EventSource/eventsource/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: eventsource
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 22:10:09 +00:00
Oleg Lobanov
1d66bbe40a
Merge pull request #1942 from ramiresviana/fixes-12 2022-05-13 10:42:51 +02:00
Ramires Viana
5da9d74da6 fix: allow CSP inline styling 2022-05-05 15:38:39 +00:00
Ramires Viana
b14b9114f8 feat: invalid symlink icon 2022-05-05 15:14:40 +00:00
Ramires Viana
8a43413f88 feat: page title localization 2022-05-04 13:16:16 +00:00
Ramires Viana
c3bd1188aa fix: expired token error 2022-05-04 12:58:19 +00:00
Ramires Viana
fc209f64de fix: network error object message 2022-05-04 12:36:13 +00:00
Ramires Viana
96afaca0ad chore: refactor response error handling 2022-05-04 12:11:36 +00:00
Oleg Lobanov
f663237a16
chore: bump github.com/miekg/dns to v1.1.25 2022-05-04 01:52:05 +04:00
Oleg Lobanov
ac3ead8dce
build(frontend): bump node version from 14 to 16 2022-05-04 01:49:33 +04:00
Oleg Lobanov
7c9a75e725
build(backend): bump dependency versions 2022-05-04 01:00:42 +04:00
Oleg Lobanov
596c73288f
feat: automatically focus username field on login page 2022-05-04 00:45:17 +04:00
Ramires Viana
d1d7b23da6 fix: folder info on upload list 2022-05-02 15:03:02 +00:00
Ramires Viana
e677c78471 fix: drag-and-drop folder upload 2022-05-02 15:01:39 +00:00
Ramires Viana
9734f707f0 chore: refactor url creation 2022-05-02 13:47:22 +00:00
dependabot[bot]
e5fa96b666
build(deps): bump async from 2.6.3 to 2.6.4 in /frontend (#1933)
Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-30 13:52:07 +04:00
Oleg Lobanov
bcef7d3f73
chore: make linter happy 2022-04-30 13:49:33 +04:00
Oleg Lobanov
aed3af5838
fix: disable autocapitalize of login input (closes #1910) 2022-04-30 13:37:32 +04:00
Oleg Lobanov
6bd34c7632
build: upgrade go version to 1.18.1 2022-04-30 13:33:56 +04:00
dependabot[bot]
040584c865
build(deps): bump moment from 2.29.1 to 2.29.2 in /frontend (#1900)
Bumps [moment](https://github.com/moment/moment) from 2.29.1 to 2.29.2.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.1...2.29.2)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-09 20:36:45 +02:00
Jonathan Zernik
ecb2d1d81b
chore: fix readme, remove section about middleware. (#1897) 2022-04-04 21:03:59 +02:00
dependabot[bot]
a74c72db45
build(deps): bump minimist from 1.2.5 to 1.2.6 in /frontend (#1889)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-02 14:35:39 +02:00
dependabot[bot]
f5b1e10618
build(deps): bump minimist from 1.2.5 to 1.2.6 in /tools (#1891)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-01 17:02:17 +02:00
Jan Lucansky
e7fed5a45b
chore: fix typo in slovak translation (#1885) 2022-03-30 16:40:29 +02:00
Felix Nüsse
f8dfbf7eee
feat: add branding to the window title (#1850) 2022-03-24 12:01:19 +01:00
Sinux
fca5fc5b87
chore: enhance translations for French language (#1876)
Signed-off-by: Simon LEONARD <git-1001af4@sinux.sh>
2022-03-24 11:56:53 +01:00
Daniel
4ee19be63d
chore: update german translation (#1855) 2022-03-24 11:56:14 +01:00
dependabot[bot]
b2ad3f7368
build(deps): bump url-parse from 1.5.7 to 1.5.10 in /frontend (#1841)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.7 to 1.5.10.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.7...1.5.10)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-02 15:57:18 +01:00
Oleg Lobanov
b73d278ded
chore(release): 2.21.1 2022-02-22 10:58:44 +01:00
Oleg Lobanov
6366cf0b18
fix: display user scope for admin users (#1834) 2022-02-22 10:58:22 +01:00
Oleg Lobanov
f73518029c
chore(release): 2.21.0 2022-02-21 20:49:31 +01:00
Oleg Lobanov
c782f21b0f
fix: correctly handle non-ascii passwords for shared resources 2022-02-21 20:47:28 +01:00
Oleg Lobanov
0942fc7042
fix: don't expose scope for non-admin users 2022-02-21 20:17:42 +01:00
Oleg Lobanov
c1987237d0
feat: use real image path to calculate cache key 2022-02-21 19:59:22 +01:00
Filippo Finke
cf85404dd2
feat: add upload file list with progress (#1825) 2022-02-21 19:30:42 +01:00
Oleg Lobanov
6f226fa549
Merge pull request #1832 from filebrowser/dependabot/npm_and_yarn/frontend/url-parse-1.5.7
build(deps): bump url-parse from 1.5.4 to 1.5.7 in /frontend
2022-02-20 12:23:22 +01:00
dependabot[bot]
228ebea66c
build(deps): bump url-parse from 1.5.4 to 1.5.7 in /frontend
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.4 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.4...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-19 16:43:38 +00:00
Oleg Lobanov
bb19834042
Merge pull request #1777 from adrium/feat-gallery
Add gallery view mode
2022-02-10 17:39:59 +01:00
Adrian
7870e89bc0 feat: smaller column width to fit 2 columns in landscape mobiles 2022-02-10 17:11:24 +01:00
Adrian
8888b9f446 feat: add gallery view mode 2022-02-10 17:11:24 +01:00
Oleg Lobanov
f6e5c6f0de
Merge pull request #1822 from filebrowser/dependabot/npm_and_yarn/frontend/hosted-git-info-2.8.9
build(deps): bump hosted-git-info from 2.8.8 to 2.8.9 in /frontend
2022-02-09 10:38:25 +01:00
dependabot[bot]
e7659ea36b
build(deps): bump hosted-git-info from 2.8.8 to 2.8.9 in /frontend
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

---
updated-dependencies:
- dependency-name: hosted-git-info
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-09 09:33:46 +00:00
Oleg Lobanov
7730ccd611
Merge pull request #1819 from filebrowser/dependabot/npm_and_yarn/frontend/browserslist-4.19.1
build(deps): bump browserslist from 4.16.3 to 4.19.1 in /frontend
2022-02-09 10:31:07 +01:00
dependabot[bot]
80890075e8
build(deps): bump browserslist from 4.16.3 to 4.19.1 in /frontend
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.16.3 to 4.19.1.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.16.3...4.19.1)

---
updated-dependencies:
- dependency-name: browserslist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 20:02:42 +00:00
Oleg Lobanov
9b04004120
Merge pull request #1818 from filebrowser/dependabot/npm_and_yarn/frontend/dns-packet-1.3.4
build(deps): bump dns-packet from 1.3.1 to 1.3.4 in /frontend
2022-02-08 21:01:42 +01:00
dependabot[bot]
a73d7f14b7
build(deps): bump dns-packet from 1.3.1 to 1.3.4 in /frontend
Bumps [dns-packet](https://github.com/mafintosh/dns-packet) from 1.3.1 to 1.3.4.
- [Release notes](https://github.com/mafintosh/dns-packet/releases)
- [Changelog](https://github.com/mafintosh/dns-packet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mafintosh/dns-packet/compare/v1.3.1...v1.3.4)

---
updated-dependencies:
- dependency-name: dns-packet
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:55:47 +00:00
Oleg Lobanov
ffe960a8c2
Merge pull request #1817 from filebrowser/dependabot/npm_and_yarn/frontend/ws-6.2.2
build(deps): bump ws from 6.2.1 to 6.2.2 in /frontend
2022-02-08 20:55:07 +01:00
dependabot[bot]
73c80732d9
build(deps): bump ws from 6.2.1 to 6.2.2 in /frontend
Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/6.2.1...6.2.2)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:53:09 +00:00
Oleg Lobanov
8e2663bf7b
Merge pull request #1816 from filebrowser/dependabot/npm_and_yarn/frontend/path-parse-1.0.7
build(deps): bump path-parse from 1.0.6 to 1.0.7 in /frontend
2022-02-08 20:53:01 +01:00
Oleg Lobanov
e697e58164
Merge pull request #1815 from filebrowser/dependabot/npm_and_yarn/frontend/url-parse-1.5.4
build(deps): bump url-parse from 1.5.1 to 1.5.4 in /frontend
2022-02-08 20:52:24 +01:00
dependabot[bot]
c01496624a
build(deps): bump path-parse from 1.0.6 to 1.0.7 in /frontend
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:29:52 +00:00
dependabot[bot]
8906408a8f
build(deps): bump url-parse from 1.5.1 to 1.5.4 in /frontend
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.4.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.4)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:29:52 +00:00
Oleg Lobanov
3ec7951380
Merge pull request #1813 from filebrowser/dependabot/npm_and_yarn/frontend/postcss-7.0.39
build(deps): bump postcss from 7.0.35 to 7.0.39 in /frontend
2022-02-08 20:29:21 +01:00
Oleg Lobanov
b30aefa522
Merge pull request #1812 from filebrowser/dependabot/npm_and_yarn/frontend/follow-redirects-1.14.8
build(deps): bump follow-redirects from 1.13.3 to 1.14.8 in /frontend
2022-02-08 20:29:04 +01:00
Oleg Lobanov
bc8a750dfe
Merge pull request #1814 from filebrowser/dependabot/npm_and_yarn/frontend/tar-6.1.11
build(deps): bump tar from 6.1.0 to 6.1.11 in /frontend
2022-02-08 20:28:47 +01:00
dependabot[bot]
f1f7f17ade
build(deps): bump follow-redirects from 1.13.3 to 1.14.8 in /frontend
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.13.3 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.13.3...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:27:05 +00:00
dependabot[bot]
9182d33e1c
build(deps): bump postcss from 7.0.35 to 7.0.39 in /frontend
Bumps [postcss](https://github.com/postcss/postcss) from 7.0.35 to 7.0.39.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/7.0.39/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/7.0.35...7.0.39)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:26:52 +00:00
Oleg Lobanov
7d836a3728
Merge pull request #1786 from Jmainguy/typos
fix typos
2022-02-08 20:25:30 +01:00
dependabot[bot]
010d16fc1d
build(deps): bump tar from 6.1.0 to 6.1.11 in /frontend
Bumps [tar](https://github.com/npm/node-tar) from 6.1.0 to 6.1.11.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.0...v6.1.11)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:25:15 +00:00
Oleg Lobanov
fa89ba4665
Merge branch 'master' into typos 2022-02-08 20:25:14 +01:00
Oleg Lobanov
a0752904c1
Merge pull request #1811 from filebrowser/dependabot/npm_and_yarn/frontend/ssri-6.0.2
build(deps): bump ssri from 6.0.1 to 6.0.2 in /frontend
2022-02-08 20:24:18 +01:00
dependabot[bot]
371718634b
build(deps): bump ssri from 6.0.1 to 6.0.2 in /frontend
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: ssri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:09:43 +00:00
Oleg Lobanov
0f4f8751f2
Merge pull request #1769 from adrium/feat-icons
Add colorized file type icons
2022-02-08 20:08:52 +01:00
sejinP
ec45ee471f
chore: remove GOMAXPROCS setting (#1803) 2022-02-08 19:56:04 +01:00
Jonathan Seth Mainguy
6fffcbac4e chore: fix typos 2022-01-28 09:46:21 -05:00
Adrian
2948589fcd feat: add colorized file type icons 2022-01-18 08:40:06 +01:00
Adrian
ecd0b2ee0d chore: update Material Icons 2022-01-17 23:21:45 +01:00
on4r
205f11d677
chore: rotate the spinner clockwise (#1765) 2022-01-11 21:23:46 +01:00
niubility000
949f0f277f
fix: open all the pdf files correctly (#1742) 2022-01-10 17:01:21 +01:00
Anton Grouchtchak
665e45889c
feat: add Ukrainian translation / update Russian translation (#1753) 2022-01-07 12:29:57 +01:00
Oleg Lobanov
8d87e0d5f9
chore(release): 2.20.1 2021-12-21 14:40:04 +01:00
Oleg Lobanov
46d80464d2
build: revert to using the default alpine based docker image
Build both standard and linuxserver based images.
linuxserver based images can be accessed by adding `-s6` suffix to the docker image name
2021-12-21 14:39:34 +01:00
Oleg Lobanov
829ed9fb6d
chore(release): 2.20.0 2021-12-21 00:48:46 +01:00
Oleg Lobanov
988d3e5bdd
fix: set correct default database path in the config 2021-12-21 00:47:40 +01:00
Oleg Lobanov
6eb3ab0635
fix: upgrade vulnerable versions of the library 2021-12-21 00:17:26 +01:00
Mazen Besher
c2e03bbfab
feat: detect multiple subtitle languages (#1723) 2021-12-21 00:07:43 +01:00
Oleg Lobanov
608a0015ee
Merge pull request #1729 from filebrowser/add_linuxserver
Refactoring
2021-12-20 23:40:11 +01:00
Oleg Lobanov
f81857acce
build: refactor makefile 2021-12-20 23:36:50 +01:00
Oleg Lobanov
b1e0d5b39f
chore: add make fmt target 2021-12-20 22:39:00 +01:00
Oleg Lobanov
68cf7a2173
chore: upgrade go to 1.17 2021-12-20 22:31:53 +01:00
Oleg Lobanov
89d1c06441
ci: run CI linters concurrently 2021-12-20 22:31:52 +01:00
Oleg Lobanov
2bebb5f0f8
ci: fix frontend formatting 2021-12-20 22:29:41 +01:00
Oleg Lobanov
683b11d265
chore: add dist folder to .gitignore 2021-12-20 22:29:40 +01:00
Oleg Lobanov
4d1b9dd211
build: remove deprecated goreleaser use_buildx param 2021-12-20 22:29:39 +01:00
Oleg Lobanov
b8f35ce932
feat: use linuxserver based docker image 2021-12-20 22:29:39 +01:00
Oleg Lobanov
a078f0b787
chore(release): 2.19.0 2021-11-24 21:30:26 +01:00
niubility000
7401d16e45
feat: prefetch previous and next images in preview. (#1627) 2021-11-15 14:54:28 +01:00
Oleg Lobanov
958a44f95e
Merge pull request #1662 from ramiresviana/fixes-11 2021-11-11 16:45:53 +01:00
Ramires Viana
e08239781f fix: empty file listing on share 2021-11-11 13:06:04 +00:00
Ramires Viana
c29698dffa fix: relative font sizes 2021-11-11 12:54:30 +00:00
coxde
81de95632a
chore: update zh-cn.json (#1656) 2021-11-10 15:07:53 +01:00
Oleg Lobanov
7f2d221083
chore(release): 2.18.0 2021-10-31 17:18:01 +01:00
Oleg Lobanov
74b7cd8e81
fix: security issue in command runner (closes #1621) 2021-10-31 17:13:16 +01:00
niubility000
6cb51b4eb4
Add files via upload (#1615) 2021-10-24 13:35:29 +04:00
niubility000
f09bf3e1d0
fix: fix sidebar navigation on mobile devices (#1618) 2021-10-19 20:37:12 +04:00
niubility000
6f345be3e4
fix: search box is misaligned when the browser preferred font size is other than 16px (#1613) 2021-10-19 20:34:17 +04:00
niubility000
ddd4ffa4ca
fix: set correct editor height regardless of preferred font size (#1614) 2021-10-19 20:32:25 +04:00
niubility000
deabc80fd7
fix: back button behaviour in preview (#1573) 2021-10-12 13:09:05 +02:00
niubility000
b6a51bed51
fix: zoom pics when dlclick at first time (#1561) 2021-09-23 10:21:17 +02:00
lilihx
0426629a59
feat: add ability to select file modified time format (#1536) 2021-09-11 14:12:51 +02:00
Ryan Qian
0358e42d2c
feat: add manifest theme color param (#1542) 2021-09-10 17:08:15 +02:00
Filip Hanes
3768e3345f
chore: add slovak translation (#1534) 2021-09-03 12:03:50 +02:00
ahmetlutfu
16e434be66
chore: add turkish translation (#1524) 2021-08-31 11:49:33 +02:00
Oleg Lobanov
bf303c536a
chore(release): 2.17.2 2021-08-27 12:40:51 +02:00
Andrew Kennedy
43a460993c
fix: bug with inlineLink not creating url properly (#1515) 2021-08-26 12:43:37 +02:00
Oleg Lobanov
7f0673ee70
chore(release): 2.17.1 2021-08-23 10:03:31 +02:00
Oleg Lobanov
4c3099a086
fix: internal server error if --disable-preview-resize flag is set (closes #1510) 2021-08-23 10:03:11 +02:00
Oleg Lobanov
f0bc9167b1
chore(release): 2.17.0 2021-08-21 16:51:34 +02:00
Ramires Viana
23d646c456 fix: escape quote on index template
fixes #1501
2021-08-20 14:43:06 +02:00
Ramires Viana
76add9e527 feat: open file option on preview 2021-08-20 14:43:06 +02:00
Ramires Viana
c63cc5a2d2 fix: file caching directive 2021-08-20 14:43:06 +02:00
Andrew Kennedy
25c8788390
fix: 401 error in share view open file button (#1495) 2021-08-19 14:35:24 +02:00
Oleg Lobanov
aa52b07bb1
chore(release): 2.16.1 2021-08-04 11:44:29 +02:00
Oleg Lobanov
76b466f649
fix: check symlink target type (closes #1488) 2021-08-04 11:44:02 +02:00
Oleg Lobanov
8ecc2da947
chore(release): 2.16.0 2021-07-26 13:03:53 +02:00
Oleg Lobanov
8650d2ffe7
fix: failure on broken symlink deletion 2021-07-26 13:02:11 +02:00
Oleg Lobanov
34d7d2c8c4
chore: upgrade golangci-lint 2021-07-26 12:00:05 +02:00
Oleg Lobanov
201329abce
chore: add Content-Security-Policy header 2021-07-26 11:08:39 +02:00
Oleg Lobanov
f2b5dd3787
chore: don't break folder download if any file processing causes an error 2021-07-26 10:41:56 +02:00
Oleg Lobanov
5072bbb2cb
fix: break resource create/update handlers on error (closes #1464) 2021-07-24 15:33:54 +02:00
Oleg Lobanov
6b19ab6613
fix: don't remove files on unsuccessful updates (closes #1456) 2021-07-24 15:32:24 +02:00
Oleg Lobanov
730be5ef6b
Create SECURITY.md 2021-07-03 16:56:27 +02:00
laggardkernel
46ee595389
fix: short commit sha and typo fix in Makefile (#1411) 2021-05-25 11:29:38 +02:00
Oleg Lobanov
dee465ab86
Merge pull request #1373 from ramiresviana/fixes-9
Some fixes
2021-05-03 23:29:12 +02:00
Ramires Viana
209f9fa77f fix: omit file content 2021-04-23 12:04:02 +00:00
Ramires Viana
ba8c09f454 feat: show more button on share 2021-04-23 11:59:34 +00:00
Ramires Viana
16a34defc0 feat: file name on page title 2021-04-23 11:59:04 +00:00
Ramires Viana
7d1e03075d feat: mod time title on file info 2021-04-23 11:57:56 +00:00
Ramires Viana
1c25f6ee69 feat: open file option on share 2021-04-23 11:55:56 +00:00
Ramires Viana
aa172b8bb5 feat: gzip encoding for static js files 2021-04-22 12:48:45 +00:00
Ramires Viana
4711e7bcd5 chore: set public path on the fly 2021-04-20 19:51:10 +00:00
Ramires Viana
8a47aee137 chore: split preview creation logic 2021-04-19 13:16:48 +00:00
Ramires Viana
190cb99a79 feat: browser cache directives 2021-04-19 12:49:40 +00:00
Ramires Viana
603203848a feat: display error messages on settings 2021-04-16 15:07:05 +00:00
Ramires Viana
5e6f14b5dc feat: message for connection error 2021-04-16 14:01:10 +00:00
Ramires Viana
976eb5583d feat: loading spinner on views navigation 2021-04-16 12:47:50 +00:00
Ramires Viana
b92152693f chore: split action on resource patch handler 2021-04-16 12:04:06 +00:00
Ramires Viana
7ec24d9d77 feat: support for IE11 browser 2021-04-15 12:28:19 +00:00
Ramires Viana
20ebbf6611 fix: copying files with special characters 2021-04-15 11:50:30 +00:00
Ramires Viana
ba7e71a7c3 fix: inconsistent double click on listing item 2021-04-14 15:29:06 +00:00
Ramires Viana
8973c4598f fix: delete image cache when moving 2021-04-14 15:20:38 +00:00
Ramires Viana
18889ad725 fix: no items displayed on file listing 2021-04-14 11:51:33 +00:00
Oleg Lobanov
73ccbe912f
chore(release): 2.15.0 2021-04-06 13:57:29 +02:00
Oleg Lobanov
84e3a98303
Merge pull request #1353 from ramiresviana/fixes-8
Some fixes
2021-03-30 09:43:27 +02:00
adrium
7dd5b34d42
feat: add EXIF thumbnail support for JPEG files (#1234) 2021-03-29 11:40:00 +02:00
Alexis Lefebvre
4470d0a704
chore: update issue templates (#1355) 2021-03-28 12:52:03 +02:00
Ramires Viana
a76e01d2b7 feat: dynamic autoplay on previewer 2021-03-26 17:31:27 +00:00
Ramires Viana
2697093ac1 fix: empty archive name on directory download 2021-03-26 14:45:18 +00:00
Ramires Viana
59f9964e80 fix: check modify permission on file overwrite 2021-03-26 13:30:14 +00:00
Ramires Viana
1516d9932b fix: buttons without permission on header 2021-03-26 12:45:17 +00:00
Ramires Viana
fcb115f42d fix: mouse wheel zoom on previewer 2021-03-25 19:37:54 +00:00
Ramires Viana
e410272e6b feat: dynamic zoom limit on previewer 2021-03-25 19:36:53 +00:00
Ramires Viana
87f1881b42 fix: list item interactions on share 2021-03-25 15:47:49 +00:00
Ramires Viana
c0d85f3d85 fix: image quality switch on previewer 2021-03-25 14:24:46 +00:00
Ramires Viana
98d79b8ed9 fix: missing bold variation for Roboto font 2021-03-24 19:06:56 +00:00
Ramires Viana
fe80730bb1 fix: no header button animations on file listing 2021-03-24 19:05:15 +00:00
Ramires Viana
6c8ee96e6a feat: dynamic item count on file listing 2021-03-24 17:50:16 +00:00
Ramires Viana
b521dec8f9 fix: hidden editor header on Safari 2021-03-24 12:23:05 +00:00
Ramires Viana
e9baf0c4b6 fix: empty text file on editor 2021-03-23 18:18:02 +00:00
Ramires Viana
e1a6f593e1 fix: error causes panic on upload 2021-03-23 13:13:46 +00:00
Oleg Lobanov
4b068b3058
chore(release): 2.14.1 2021-03-21 14:24:33 +01:00
Oleg Lobanov
da54bd6c21
fix: display public routes with header proxy auth 2021-03-21 14:24:23 +01:00
Oleg Lobanov
0d179eca4d
chore(release): 2.14.0 2021-03-21 13:19:53 +01:00
Oleg Lobanov
dacd511d24
chore: run npm update 2021-03-21 13:05:22 +01:00
Oleg Lobanov
c44b37c50c
chore: add prettier frontent linter 2021-03-21 12:51:58 +01:00
Oleg Lobanov
a721dc1f31
feat: add health check handler 2021-03-21 12:30:48 +01:00
Oleg Lobanov
d2e6d23741
Merge pull request #1339 from ramiresviana/fixes-7
Some fixes
2021-03-19 17:32:41 +01:00
Ramires Viana
5f4a0317ab fix: hide dotfile error on share 2021-03-18 18:24:24 +00:00
Ramires Viana
22f4be8f54 fix: qr code url on share 2021-03-18 13:10:10 +00:00
Ramires Viana
eeadc532fe fix: text file detection on editor 2021-03-17 18:06:56 +00:00
Ramires Viana
93a35ad251 fix: prefix handling on http router 2021-03-17 17:54:25 +00:00
Oleg Lobanov
99787287bb
Merge pull request #1331 from ramiresviana/tweaks-2
Some development tweaks
2021-03-15 16:56:20 +01:00
Ramires Viana
bdd523190e chore: frontend DirFS for development 2021-03-15 14:06:21 +00:00
Ramires Viana
4c1dd5c097 chore: automatic output name on build 2021-03-15 14:00:23 +00:00
Oleg Lobanov
e1f658633d
chore(release): 2.13.0 2021-03-14 20:02:02 +01:00
Oleg Lobanov
9c79105c02
chore: prevent deleting .gitignore from dist folder 2021-03-14 19:59:55 +01:00
Jürgen Hötzel
6d5ceae8b4
fix: wait for async command exit (#1326)
This prevents the accumulation of zombie processes when using
async (&) event commands. Also log async command failures.
2021-03-14 19:32:14 +01:00
Oleg Lobanov
381f09087a
Merge pull request #1321 from ramiresviana/fixes-6 2021-03-14 14:19:50 +01:00
Ramires Viana
426b38bb33 fix: root path name on archive 2021-03-12 15:52:52 +00:00
Ramires Viana
488d98045e fix: download current dir on file listing 2021-03-12 15:28:49 +00:00
Ramires Viana
7955e0720b fix: encoded file path on share 2021-03-12 15:15:56 +00:00
Ramires Viana
e017a19985 fix: full file path on share 2021-03-12 12:14:58 +00:00
Ramires Viana
f8df76f526 fix: header dropdown icon color on previewer 2021-03-11 16:01:54 +00:00
Ramires Viana
11ebaec5f0 fix: modified time on info prompt 2021-03-11 15:20:37 +00:00
Ramires Viana
326b35a7ac fix: item dragging on file listing 2021-03-11 12:09:12 +00:00
Ramires Viana
5bf15548d0 fix: check rules on http resource handlers 2021-03-10 17:38:11 +00:00
Ramires Viana
6a734c0139 fix: stuck icon on header button 2021-03-10 15:32:10 +00:00
Ramires Viana
81b6f4d6f6 fix: update image cache when replacing 2021-03-10 15:14:01 +00:00
Ramires Viana
0b92d94570 chore: split POST method on resource http handler 2021-03-10 13:32:11 +00:00
Oleg Lobanov
fc5506179a
refactor: migrate from rice to embed.FS 2021-03-09 19:09:32 +01:00
Oleg Lobanov
0fe34ad224
Merge pull request #1307 from ramiresviana/tweaks-1
Frontend code quality changes
2021-03-09 18:26:46 +01:00
Ramires Viana
54f35701a2 fix: archive contains parent path on Windows 2021-03-09 15:54:54 +00:00
FrzMtrsprt
a809404ce1
chore: update zh-cn.json (#1311) 2021-03-08 10:24:16 +01:00
Po Chen
fb32e44b47
chore: update zh-cn.json (#1309) 2021-03-07 15:41:05 +01:00
Oleg Lobanov
e9c0369062
chore(release): 2.12.1 2021-03-07 15:25:34 +01:00
Oleg Lobanov
7358b3fe31
fix: add missing default config into the docker image 2021-03-07 15:23:12 +01:00
Ramires Viana
2a1f759e9e chore: remove prompts events 2021-03-04 14:40:18 +00:00
Oleg Lobanov
2fccb8c367
chore(release): 2.12.0 2021-03-04 13:12:19 +01:00
Oleg Lobanov
e039d95192
chore: fix major docker tag name 2021-03-04 13:12:03 +01:00
Oleg Lobanov
0f96031d6f
Merge pull request #1305 from filebrowser/github_actions 2021-03-04 11:39:30 +01:00
Oleg Lobanov
6214fc84fa
chore: add github action badge 2021-03-04 11:35:52 +01:00
Oleg Lobanov
47578e02e3
ci: migrate to github actions 2021-03-04 11:35:52 +01:00
Oleg Lobanov
35a4379b67
chore: go mod tidy 2021-03-04 00:57:35 +01:00
Oleg Lobanov
23f84642e6
build: use make for building the project (#1304) 2021-03-04 00:10:08 +01:00
Ramires Viana
edb9e85efd chore: share view logic responsability 2021-03-03 17:46:37 +00:00
Oleg Lobanov
2d2c598fa6
feat: add homebrew tap 2021-03-03 16:25:03 +01:00
Oleg Lobanov
cf4836dc75
feat: build multi-arch docker images 2021-03-03 13:46:22 +01:00
Ramires Viana
d8306559fd chore: breadcrumbs component 2021-03-03 12:25:59 +00:00
WeidiDeng
e8c9d1c539
feat: added tiff files preview support (#1222) 2021-03-02 12:14:32 +01:00
Alvaro Aleman
d8f415f8ab
feat: allow to password protect shares (#1252)
This changes allows to password protect shares. It works by:
* Allowing to optionally pass a password when creating a share
* If set, the password + salt that is configured via a new flag will be
  hashed via bcrypt and the hash stored together with the rest of the
  share
* Additionally, a random 96 byte long token gets generated and stored
  as part of the share
* When the backend retrieves an unauthenticated request for a share that
  has authentication configured, it will return a http 401
* The frontend detects this and will show a login prompt
* The actual download links are protected via an url arg that contains
  the previously generated token. This allows us to avoid buffering the
  download in the browser and allows pasting the link without breaking
  it
2021-03-02 12:00:18 +01:00
Ramires Viana
7b6579ac8a chore: files view dynamic component 2021-03-01 16:12:17 +00:00
Ramires Viana
057307181e chore: removed header buttons components 2021-03-01 13:41:35 +00:00
Ramires Viana
4fb832c042 feat: increased header button counter size 2021-03-01 12:57:39 +00:00
Ramires Viana
e503cb69f2 chore: files pages logic responsability 2021-02-26 15:10:21 +00:00
Ramires Viana
95811e99bc chore: header bar component 2021-02-25 18:37:07 +00:00
Ramires Viana
62fff5ca60 feat: larger previewer content 2021-02-22 16:01:13 +00:00
Ramires Viana
5b28aa0848 feat: improved settings navbar 2021-02-19 16:01:43 +00:00
Ramires Viana
db5aad8eb6 feat: dual pane settings view 2021-02-19 13:15:46 +00:00
Alvaro Aleman
977ec33918
chore: close preview on esc key press (#1288) 2021-02-16 17:15:04 +01:00
Ramires Viana
1819377897 feat: improved sharing prompt 2021-02-16 15:39:11 +00:00
niubility000
f1b7bd59f6
fix: double click to zoom pics in phone's browser (#1274)
fixed this : https://github.com/filebrowser/filebrowser/issues/1266
2021-02-08 09:54:40 +01:00
WeidiDeng
f3afd5cb79
fix: environmental variables not expanded in command (#1241) 2021-01-19 17:02:46 +01:00
Oleg Lobanov
e6a5bf116e
chore: remove empty string from locales (closes #1245) 2021-01-19 16:56:06 +01:00
Oleg Lobanov
21b5a76fa7
chore: refactor search function 2021-01-12 19:14:23 +01:00
WeidiDeng
b6263eb607
chore: search by type with empty file name (#1228) 2021-01-12 18:08:23 +01:00
WeidiDeng
c8257e848e
chore: move single click to user profile page (#1236)
Single clicks applies to FileList component.
2021-01-12 00:15:26 +01:00
叫我彭一凡
05bb7c8553
fix: fetch resource api once when sorting (closes #1172) (#1202) 2021-01-12 00:00:40 +01:00
WeidiDeng
b600b11415
feat: share management delete confirm (#1212) 2021-01-11 23:54:16 +01:00
Oleg Lobanov
019ce80fc5
fix: don't allow to remove root user 2021-01-11 22:33:36 +01:00
Adam Dobrawy
8cea2f75b3
chore: fix url to documentation in templates (#1231) 2021-01-07 11:48:53 +01:00
WeidiDeng
6914063853
feat: allow disabling file detections by reading header (#1175) 2021-01-07 11:30:17 +01:00
Oleg Lobanov
43e0d4a856
chore: fix translation files indent 2020-12-31 12:31:26 +01:00
Oleg Lobanov
066d8e8d6c
chore: add ru translation 2020-12-31 12:26:49 +01:00
Oleg Lobanov
948e05c083
chore(release): 2.11.0 2020-12-28 17:37:19 +01:00
WeidiDeng
fb5b28d9cb
feat: download shared subdirectory (#1184)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2020-12-28 17:35:29 +01:00
WeidiDeng
677bce376b
feat: add sharing management (#1178) (closes #1000) 2020-12-24 19:02:28 +01:00
Alexis Lefebvre
8faa96f5e6
chore: fix typo costumize -> costumize (#1194) 2020-12-24 18:24:15 +01:00
WeidiDeng
f62806f6c9
fix: check user input to prevent permission elevation (#1196) (closes #1195) 2020-12-24 18:22:48 +01:00
Oleg Lobanov
58835b7e53
fix: move files between different volumes (closes #1177) 2020-12-24 17:50:27 +01:00
WeidiDeng
7a5298a755
fix: delete extra remove prefix (#1186)
Fix file actions within /files dir
2020-12-16 16:08:56 +01:00
WeidiDeng
bc4a6462ce
chore: use command key to select multiple files on mac (#1183) 2020-12-12 14:09:50 +01:00
WeidiDeng
ac3673e111
fix: recaptcha race condition (#1176) 2020-12-08 11:26:29 +01:00
Oleg Lobanov
c746c1931d
chore(release): 2.10.0 2020-11-24 12:00:10 +01:00
Oleg Lobanov
586d198d47
fix: fix hanging when reading a named pipe file (closes #1155) 2020-11-24 11:37:31 +01:00
Matt Doyle
9515ceeb42
feat: automatically jump to the next photo when deleting while previewing (#1143) 2020-11-23 19:08:14 +01:00
Julien Loir
e8b4e9af46
feat: add single click mode (#1139) 2020-11-23 19:06:37 +01:00
Tiger Nie
10e399b3c3
feat: add hide dotfiles param (#1148) 2020-11-20 11:51:28 +01:00
Oleg Lobanov
dcbc3286e2
Merge pull request #1133 from ramiresviana/fixes-5
Some fixes and shared view improvements
2020-11-04 17:58:18 +01:00
xufanglu
b185f9b56e
chore: fix typo in config_init.go (#1131) 2020-11-04 17:47:36 +01:00
Ramires Viana
7096b3dab9 fix: empty folder in archive 2020-11-04 15:56:27 +00:00
Ramires Viana
36cacdf598 feat: shared item information 2020-11-04 15:56:27 +00:00
Ramires Viana
4e48ffc14d fix: previewer title overflow 2020-11-04 15:56:27 +00:00
Ramires Viana
e119bc55ea feat: shared folder file listing 2020-11-04 15:56:05 +00:00
Ramires Viana
1ce3068a99 fix: resource rename action invalid path 2020-11-03 12:30:56 +00:00
Liubomyr Piadyk
d562d1a60d
chore: fix readme typo (#1128)
Commander runner -> Command runner
At other places it's referenced as Command runner.
2020-10-29 17:29:29 +01:00
Oleg Lobanov
9f858398ab
chore(release): 2.9.0 2020-10-21 16:52:29 +02:00
Aiden McClelland
0ac80e8387
feat: support WKWebview custom protocol (#1113) 2020-10-21 16:41:09 +02:00
Hissy
0dca0b92d1
chore: update zh-cn and zh-tw (#1121) 2020-10-21 16:39:41 +02:00
Oleg Lobanov
c9b36ba32e
Merge pull request #1124 from ramiresviana/fixes-4 2020-10-21 16:37:39 +02:00
Ramires Viana
f2c4e78381 fix: allow start from Windows explorer 2020-10-19 13:41:40 +00:00
Ramires Viana
05bff54b71 fix: preview case sensitive file extension 2020-10-19 13:25:09 +00:00
Ramires Viana
2bd163d92a fix: search missing path slash 2020-10-19 13:14:36 +00:00
Ramires Viana
5e27ba5c8c fix: file upload missing path slash 2020-10-19 13:11:26 +00:00
Oleg Lobanov
5aaeb3b76d
chore(release): 2.8.0 2020-10-05 09:53:09 +02:00
Daniel Pham
36fb9f562a
fix: fix empty command name (#1106) 2020-10-05 09:52:27 +02:00
Xabi
ad99bf1801
fix: fix panic when accessing nonexistent .js file in static path (#1105) 2020-10-02 15:09:03 +02:00
Oleg Lobanov
4c2a094255
Merge pull request #1100 from ramiresviana/fixes-3 2020-10-01 16:53:35 +02:00
Keagan McClelland
97693cc611
feat: add disable exec flag (#1090) 2020-10-01 16:45:24 +02:00
Ramires Viana
c6d4fcd08f fix: empty commands setting 2020-09-29 14:05:03 +00:00
Ramires Viana
dd7b9ddd85 fix: preview key shortcut conflict 2020-09-29 14:04:55 +00:00
Ramires Viana
26d62e4117 fix: search results absolute url 2020-09-29 14:04:43 +00:00
Ramires Viana
babd7783af fix: file upload path encoding 2020-09-29 14:04:03 +00:00
Oleg Lobanov
1529e796df
chore(release): 2.7.0 2020-09-11 19:21:08 +02:00
Oleg Lobanov
d4b904b92b
chore: pass docker password via stdin 2020-09-11 18:57:14 +02:00
Oleg Lobanov
12d4177823
build: bump go version to 1.15.2 (#1081) 2020-09-11 18:07:01 +02:00
Oleg Lobanov
8142b32f38
feat: put selected files in the root of the archive (closes #1065) 2020-09-11 16:54:22 +02:00
Oleg Lobanov
c5abbb4e1c
chore: fix lint errors 2020-09-11 16:02:16 +02:00
Oleg Lobanov
65ac73414f
feat: add --socket-perm flag to control unix socket file permissions (closes #1060) 2020-09-11 15:59:06 +02:00
Oleg Lobanov
ede4213c8e
chore: fix french translation (closes #1071) 2020-09-11 15:16:58 +02:00
Agneev Mukherjee
b60d291490
chore: fix URLs for assets (#1074) 2020-09-05 15:23:42 +02:00
Oleg Lobanov
b9ede79888
Merge pull request #1066 from ramiresviana/preview-mobile-dropdown 2020-08-25 16:33:57 +02:00
Ramires Viana
3d2cb838d1 feat: preview size button 2020-08-25 14:14:15 +00:00
Ramires Viana
778734419d feat: preview mobile dropdown 2020-08-18 12:47:23 +00:00
Oleg Lobanov
be8683f556
chore(release): 2.6.2 2020-08-05 11:55:16 +02:00
Davide Maggio
c3450f4614
chore: return text/plain header in auth response (#1051) 2020-08-05 10:48:03 +02:00
Oleg Lobanov
5881bc9ab0
chore: fix preview of files with non-latin names (closes #1056) 2020-08-05 10:40:03 +02:00
Oleg Lobanov
a2fb499a20
chore(release): 2.6.1 2020-07-28 13:40:19 +02:00
Oleg Lobanov
411a928fea
chore: fix lint errors 2020-07-28 13:40:06 +02:00
Oleg Lobanov
f5d02cdde9
fix: delete cached previews when deleting file 2020-07-28 11:59:55 +02:00
Oleg Lobanov
c9340af8d0
fix: escape special characters in preview url (closes #1002) 2020-07-28 11:59:32 +02:00
Oleg Lobanov
a722bcc13f
chore(release): 2.6.0 2020-07-27 19:52:48 +02:00
Oleg Lobanov
77fe3cfc60
ci: fix go version on release step 2020-07-27 19:51:09 +02:00
Oleg Lobanov
470f93cefc
Merge pull request #1044 from filebrowser/fix_img_resize 2020-07-27 19:39:08 +02:00
Oleg Lobanov
92fde4dd12
build: set limit for vuejs build threads 2020-07-27 19:35:02 +02:00
Oleg Lobanov
95bc92955f
feat: cache resized images 2020-07-27 19:26:45 +02:00
Oleg Lobanov
f2f914221c
chore: bump go to 1.14.6 2020-07-27 19:26:45 +02:00
Oleg Lobanov
c2d8038c63
chore: add testing step to ci 2020-07-27 19:26:44 +02:00
Oleg Lobanov
cb8ac5ebf1
chore: add resize tests 2020-07-27 19:26:44 +02:00
Oleg Lobanov
aa78e3ab1f
feat: add param to disable img resizing 2020-07-27 19:26:44 +02:00
Oleg Lobanov
bc00165094
feat: add lazy load of image thumbnails 2020-07-27 19:26:44 +02:00
Oleg Lobanov
94ef59602f
feat: limit image resize workers 2020-07-27 19:26:44 +02:00
Oleg Lobanov
14e2f84ceb
Merge pull request #1042 from ramiresviana/fixes-2 2020-07-23 15:03:10 +02:00
Ramires Viana
f228fa5540 fix: conflict handling on upload button 2020-07-23 12:02:09 +00:00
Ramires Viana
f2d2c1cbf8 fix: drop feedback 2020-07-23 12:02:09 +00:00
Ramires Viana
d9be370e24 fix: missing error message 2020-07-23 12:02:09 +00:00
Ramires Viana
727c63b98e fix: parent verification on copy 2020-07-23 12:02:02 +00:00
Ramires Viana
34dfb49b71 fix: path separator inconsistency on rename 2020-07-20 17:45:45 +00:00
Henrique Dias
0b0a704d44
chore: remove hacdias/fileutils dep (#1037) 2020-07-18 20:10:22 +02:00
Oleg Lobanov
2d99d0bf13
chore(release): 2.5.0 2020-07-17 18:12:00 +02:00
Oleg Lobanov
1790df2090
Merge pull request #1026 from ramiresviana/fixes 2020-07-17 17:41:17 +02:00
Ramires Viana
10570ade44 fix: reset clipboard after pasting cutted files 2020-07-17 14:11:23 +00:00
Ramires Viana
43526d9d1a feat: duplicate files in the same directory 2020-07-17 14:11:23 +00:00
Ramires Viana
2636f876ab feat: rename option on replace prompt 2020-07-17 14:11:15 +00:00
Ramires Viana
eed9da1471 feat: file copy, move and paste conflict checking 2020-07-17 12:37:52 +00:00
Ramires Viana
9a2ebbabe2 fix: blinking previewer 2020-07-17 12:37:52 +00:00
Ramires Viana
716396a726 feat: add previewer title and loading indicator 2020-07-17 12:32:21 +00:00
Ramires Viana
0727496601 fix: remove incomplete uploaded files 2020-07-14 00:21:15 +00:00
Ramires Viana
194030fcfc fix: prompt before closing window 2020-07-14 00:12:41 +00:00
Ramires Viana
b3b644527d fix: dark theme colors 2020-07-14 00:12:33 +00:00
Ramires Viana
7e5beeff46 fix: directory conflict checking 2020-07-13 14:20:56 +00:00
Oleg Lobanov
a47b69bcec
Merge pull request #1021 from ramiresviana/upload-queue 2020-07-13 11:20:59 +02:00
Ramires Viana
6ec6a23861 feat: upload queue 2020-07-10 00:01:37 +00:00
Ramires Viana
c9cc0d3d5d refactor: upload vuex module 2020-07-10 00:01:37 +00:00
Ramires Viana
28d2b35718 refactor: upload utils 2020-07-10 00:01:37 +00:00
Ramires Viana
b4f131be50 refactor: uploading counters vuex state 2020-07-10 00:01:37 +00:00
Oleg Lobanov
d0b359561f
chore(release): 2.4.0 2020-07-07 16:53:51 +02:00
Fabian Fritzsche
453636dfe2
fix: add preview bypass for .gif files (#1012) 2020-07-07 16:47:11 +02:00
Oleg Lobanov
b1605aa6d3
Merge pull request #1014 from ramiresviana/full-screen-editor 2020-07-06 17:06:12 +02:00
Oleg Lobanov
23503b80a4
Merge pull request #1015 from ramiresviana/prompt-key-shortcut-conflict 2020-07-06 17:03:05 +02:00
Ramires Viana
0d69fbd9a3 fix: prompt key shortcut conflict 2020-07-04 14:19:03 +00:00
Ramires Viana
0d665e528f feat: full screen editor 2020-07-04 03:11:51 +00:00
Oleg Lobanov
de0b8bb7b2
chore(release): 2.3.0 2020-06-26 12:14:44 +02:00
Thomas Queste
84da110085
fix: typo in image_templates (apline -> alpine) (#1005) 2020-06-25 09:37:55 +02:00
monkeyWie
6b0d49b1fc
feat: add image thumbnails support (#980)
* set max image preview size to 1080x1080px
2020-06-25 09:37:13 +02:00
Oleg Lobanov
4c20772e11
chore(release): 2.2.0 2020-06-22 19:12:12 +02:00
Oleg Lobanov
68f8348dde
fix: apply all fs user rulles 2020-06-22 18:46:22 +02:00
Oleg Lobanov
5023e77296
Merge pull request #995 from ramiresviana/key-shortcuts 2020-06-22 13:48:56 +02:00
Ramires Viana
95316cbe8c feat: add key shortcuts
- 'Ctrl + a' selects all files in listing.
- 'Enter' to confirm a prompt.
2020-06-21 21:54:23 +00:00
Ramires Viana
cd454bae51
feat: upload progress based on total size (#993) 2020-06-19 09:46:33 +02:00
Oleg Lobanov
241201657c
fix: add a workaround to fix window freezing when viewing a large file #992 2020-06-18 19:21:02 +02:00
Hampton
9eefaddd9b
chore: fix documentation links on README (#987) 2020-06-18 17:54:37 +02:00
Oleg Lobanov
d6d47bbd6b
Merge pull request #991 from ramiresviana/small-fixes 2020-06-18 09:59:27 +02:00
Ramires Viana
82c883f95e fix: save event hook
fix filebrowser/filebrowser#696
2020-06-17 22:57:13 +00:00
Ramires Viana
dd40b0d9b9 fix: frontend token validation
fix filebrowser/filebrowser#638
2020-06-17 22:57:07 +00:00
Ramires Viana
963837ef1d fix: multiple selection count
- Only add files to selected list that arent on it.
- Only shift key select when there are selected files.
2020-06-17 22:56:55 +00:00
Oleg Lobanov
66863b72f7
feat: add alpine and debian docker images 2020-06-16 23:18:22 +02:00
Ramires Viana
89773447a5
feat: add folder upload (#981)
* feat: folder upload
fix filebrowser/filebrowser#741

* fix: apply gofmt formater

* feat: upload button prompt

* feat: empty folder upload
2020-06-16 21:56:44 +02:00
457 changed files with 146121 additions and 23871 deletions

View file

@ -1,79 +0,0 @@
version: 2
jobs:
lint:
docker:
- image: golangci/golangci-lint:v1.27.0
steps:
- checkout
- run: golangci-lint run -v
build-node:
docker:
- image: circleci/node
steps:
- checkout
- run:
name: "Build"
command: ./wizard.sh -a
- run:
name: "Cleanup"
command: rm -rf frontend/node_modules
- persist_to_workspace:
root: .
paths:
- '*'
build-go:
docker:
- image: circleci/golang:1.14.3
steps:
- attach_workspace:
at: '~/project'
- run:
name: "Compile"
command: GOOS=linux GOARCH=amd64 ./wizard.sh -c
- run:
name: "Cleanup"
command: |
rm -rf frontend/build
git checkout -- go.sum # TODO: why is it being changed?
- persist_to_workspace:
root: .
paths:
- '*'
release:
docker:
- image: circleci/golang:1.14.3
steps:
- attach_workspace:
at: '~/project'
- setup_remote_docker
- run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
- run: curl -sL https://git.io/goreleaser | bash
- run: docker logout
workflows:
version: 2
build-workflow:
jobs:
- lint:
filters:
tags:
only: /.*/
- build-node:
filters:
tags:
only: /.*/
- build-go:
filters:
tags:
only: /.*/
requires:
- build-node
- lint
- release:
context: deploy
requires:
- build-go
filters:
tags:
only: /^v.*/
branches:
ignore: /.*/

160
.claude/CLAUDE.md Normal file
View file

@ -0,0 +1,160 @@
# CLAUDE.md
Guidance for Claude when working in this repository (File Browser, `filebrowser/filebrowser`).
## Repo orientation
- Go backend (`github.com/filebrowser/filebrowser/v2`, ecosystem `go`) + Vue frontend under `frontend/`.
- The project is in **maintenance-only mode** (see `SECURITY.md`). Prefer small, surgical, well-tested changes.
- Version scheme: `v2.63.x`. Conventional-commit messages (`fix(scope): …`, `feat: …`, `chore: …`).
- Verify with `go build ./...`, `go vet ./...`, `go test ./...`. Reuse existing test harnesses (e.g. `signToken`, `scopedUserStorage`, `handle`, `customFSUser`, `mockUserStore`).
---
# Handling security advisories
Use this playbook when asked to triage, verify, fix, or manage GitHub security advisories.
All advisory state lives on GitHub and is driven with the `gh` CLI. States are
`triage → draft → published`, plus `closed`.
## 1. Fetch
```bash
# List by state (also: published, draft, closed)
gh api '/repos/filebrowser/filebrowser/security-advisories?state=triage&per_page=100' \
--jq '.[] | {ghsa_id, severity, summary, state}'
# Full report for one advisory (read .summary and .description)
gh api /repos/filebrowser/filebrowser/security-advisories/GHSA-xxxx-xxxx-xxxx \
--jq '.summary, "---", .description'
```
Always pull the **published** set too — you need it to dedup against.
## 2. Verify each report — do NOT trust the report text
Read the actual source **at HEAD** and reach one verdict per advisory:
- **CONFIRMED** — defect exists at HEAD. Quote the exact `file:line`.
- **FIXED** — already patched (find the fix commit).
- **FALSE / NOT APPLICABLE** — claim is wrong, or targets a different project.
- **NOT EXPLOITABLE** — pattern exists but no code path can reach the precondition.
- **DUPLICATE** — of a published advisory, or of another triage advisory.
Common traps — check each before accepting a report:
- **"Incomplete fix of a prior advisory."** Read the original fix commit and confirm the *specific*
sibling code path is actually still unguarded — a prior fix may already cover a related path.
- **Wrong project.** Confirm the referenced files, symbols, and endpoints exist in this repo; reports
sometimes describe a fork. If the cited code isn't here, close as not applicable.
- **"Legacy / upgraded / imported records are affected."** Trace the field's git history and confirm that
some released version could actually produce such a record before believing it
(`git log -S'Field' -- path`, `git show <commit>`, `git tag --contains <commit>`).
- **Overlapping reports.** Two triage advisories may share one root cause — consolidate and fix once.
- **Known, intentionally-unaddressed classes.** Some areas are known and tracked but not fixed (see
`SECURITY.md`'s Known Issues); matching reports are duplicates.
Record, per advisory: verdict, the `file:line` evidence, exploitability preconditions
(default config? platform-specific? auth required?), and the disposition.
## 3. Fix (one commit per advisory)
- Branch off `master` first; never commit fixes directly to `master`.
- **One commit per fix**, each referencing the GHSA in the body (`Refs GHSA-xxxx-xxxx-xxxx`).
- When several advisories share a root cause because parallel code paths diverged, **centralize** the logic
(e.g. `settings.CreateUserHome` used by signup, proxy, and hook provisioning) so they cannot drift again.
- Keep it surgical; match surrounding style.
## 4. Add a regression test per fix
- Reuse the existing harnesses; add a focused test asserting the fixed behavior (and that the legitimate
path still works). Commit tests alongside the fixes (`test(scope): …`, `Refs GHSA-…`).
- Run `go test ./... && go vet ./...` before finishing.
## 5. Severity — set a CVSS vector, don't hand-assert
Set a CVSS v3.1 vector; GitHub derives the score **and** severity from it (overriding the plain `severity`
field). Encode the real preconditions in the vector so the band is defensible:
- Requires a specific target configuration/platform (e.g. case-insensitive FS) → **AC:H**.
- Unauthenticated vs needs an account → **PR:N / PR:L**.
- Keep it consistent with the **predecessor CVE's** rating (an incomplete-fix follow-up should not outrank
its parent). Bands: `0.13.9` low, `4.06.9` medium, `7.08.9` high, `9.010.0` critical.
```bash
gh api -X PATCH /repos/filebrowser/filebrowser/security-advisories/GHSA-xxxx-xxxx-xxxx \
-f cvss_vector_string='CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H' \
--jq '{ghsa_id, severity, score: .cvss.score, vector: .cvss.vector_string}'
```
## 6. Clean up the title
Rewrite reporter titles to the concise, sentence-case, backtick-free style of the published advisories
(state the vuln; drop "Incomplete fix of…" prefixes and jargon). The title is the `summary` field:
```bash
gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx \
-f summary='Proxy-auth auto-provisioning ignores createUserDir and grants the server root scope'
```
## 7. Rewrite the body into the standard structure
Reporter reports arrive in whatever shape the reporter used. Before drafting, rewrite the
`description` into the sections below — **reusing the reporter's own wording wherever it is
accurate**, rather than paraphrasing it. Drop the greeting, the offer to help, and any claim the
verification in step 2 disproved. Keep sections in this order and omit the ones that don't apply:
| Section | Contents |
| --- | --- |
| `## Summary` | What the defect is, in two or three sentences. Note the version it was reported against and the range it was verified over. |
| `## Details` | Root cause, naming `file.go`, the function, and a short quote of the **pre-fix** code. |
| `## PoC` | The reporter's reproduction steps and observed result, trimmed to the essentials. |
| `## Impact` | Who can exploit it (privilege level, preconditions) and what they get. |
| `## Patches` | Fixed version plus a link to the fix commit, and one sentence on what the fix does. Mention it if the reporter re-tested and confirmed. |
| `## Workarounds` | Real mitigations, or `None. Upgrade to vX.Y.Z.` |
| `## Out of scope` | Anything in the original report deliberately **not** treated as a vulnerability, with the reasoning. Needed whenever the advisory is narrower than the report. |
| `## References` | Fix and regression-test commit links. |
Use `##` headings (matching the published advisories) and keep the body in the maintainer's voice —
first person ("I reproduced…") belongs only inside quoted PoC steps.
Send it as a file so the Markdown survives shell quoting:
```bash
jq -Rs '{description: .}' desc.md \
| gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx --input -
```
## 8. Set affected & patched versions
The package is always `{ecosystem: "go", name: "github.com/filebrowser/filebrowser/v2"}`.
- `vulnerable_version_range``<= <latest released version>` (the newest tag; find it with
`git tag --list 'v2.*' --sort=-version:refname | head -1`).
- `patched_versions` — the **next** release that will actually ship the fix. It doesn't exist just
because the branch does; it still has to be cut. **When unsure which version that will be, ask.**
Replace the placeholder versions below before sending:
```bash
printf '%s' '{"vulnerabilities":[{"package":{"ecosystem":"go","name":"github.com/filebrowser/filebrowser/v2"},"vulnerable_version_range":"<= <latest>","patched_versions":"<next>","vulnerable_functions":[]}]}' \
| gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx --input -
```
## 9. Move state / close, by disposition
```bash
gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx -f state=draft # fixed, awaiting release
gh api -X PATCH .../security-advisories/GHSA-xxxx-xxxx-xxxx -f state=closed # duplicate / N-A / not-exploitable
```
- **CONFIRMED & fixed** → metadata done → **draft**. Publish after the patched release ships.
- **DUPLICATE / NOT APPLICABLE / NOT EXPLOITABLE****closed**.
- **DEFERRED** (confirmed but not yet fixed) → leave in **triage** with a note.
- The REST API **cannot post advisory comments** — replies to reporters (dup notice, evidence, links to
the relevant tracking issue) must be posted manually in the advisory UI. Draft the text for the maintainer.
## 10. Release & publish
Push the branch, open a PR, merge, tag/release the `patched_versions` you set, then publish the drafts.
Confirm outward-facing/irreversible advisory actions (close, publish) with the maintainer before doing them.

View file

@ -1,3 +1,7 @@
testdata/ .venv
.github/ dist
**.git .idea
frontend/node_modules
frontend/dist
filebrowser.db
docs/index.md

1
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1 @@
* @filebrowser/maintainers

View file

@ -1,22 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Description**
A clear and concise description of what the issue is about. What are you trying to do?
**Expected behaviour**
What did you expect to happen?
**What is happening instead?**
Please, give full error messages and/or log.
**Additional context**
Add any other context about the problem here. If applicable, add screenshots to help explain your problem.
**How to reproduce?**
Tell us how to reproduce this issue. How can someone who is starting from scratch reproduce this behaviour as minimally as possible?
**Files**
A list of relevant files for this issue. Large files can be uploaded one-by-one or in a tarball/zipfile.

53
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View file

@ -0,0 +1,53 @@
name: Bug Report
description: Report a bug in FileBrowser.
labels: [bug, 'waiting: triage']
body:
- type: checkboxes
attributes:
label: Checklist
description: Please verify that you've followed these steps
options:
- label: This is a bug report, not a question.
required: true
- label: I have searched on the [issue tracker](https://github.com/filebrowser/filebrowser/issues?q=is%3Aissue) for my bug.
required: true
- label: I am running the latest [FileBrowser version](https://github.com/filebrowser/filebrowser/releases) or have an issue updating.
required: true
- type: textarea
id: version
attributes:
label: Version
render: Text
description: |
Enter the version of FileBrowser you are using.
validations:
required: true
- type: textarea
attributes:
label: Description
description: |
A clear and concise description of what the issue is about. What are you trying to do?
validations:
required: true
- type: textarea
attributes:
label: What did you expect to happen?
validations:
required: true
- type: textarea
attributes:
label: What actually happened?
validations:
required: true
- type: textarea
attributes:
label: Reproduction Steps
description: |
Tell us how to reproduce this issue. How can someone who is starting from scratch reproduce this behavior as minimally as possible?
validations:
required: true
- type: textarea
attributes:
label: Files
description: |
A list of relevant files for this issue. Large files can be uploaded one-by-one or in a tarball/zipfile.

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: GitHub Discussions
url: https://github.com/filebrowser/filebrowser/discussions
about: Please ask questions and discuss features here.

View file

@ -1,16 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
Add a clear and concise description of what the problem is. E.g. *I'm always frustrated when [...]*
**Describe the solution you'd like**
Add a clear and concise description of what you want to happen.
**Describe alternatives you've considered**
Add a clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -1,16 +1,16 @@
**Description** ## Description
Please explain the changes you made here.
If the feature changes current behaviour, explain why your solution is better.
:rotating_light: Before submitting your PR, please read [community](https://github.com/filebrowser/community), and indicate which issues (in any of the repos) are either fixed or closed by this PR. See [GitHub Help: Closing issues using keywords](https://help.github.com/articles/closing-issues-via-commit-messages/). <!-- Please explain the changes you made here. -->
- [ ] DO make sure you are requesting to **pull a topic/feature/bugfix branch** (right side). Don't request your master! ## Additional Information
- [ ] DO make sure you are making a pull request against the **master branch** (left side). Also you should start *your branch* off *our master*.
- [ ] DO make sure that File Browser can be successfully built. See [builds](https://github.com/filebrowser/community/blob/master/builds.md) and [development](https://github.com/filebrowser/community/blob/master/development.md).
- [ ] DO make sure that related issues are opened in other repositories. I.e., the frontend, caddy plugins or the web page need to be updated accordingly.
- [ ] AVOID breaking the continuous integration build.
**Further comments** <!-- If it is a relatively large or complex change, please add more information to explain what you did, how you did it, if you considered any alternatives, etc. -->
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did, what alternatives you considered, etc.
:heart: Thank you! ## Checklist
Before submitting your PR, please indicate which issues are either fixed or closed by this PR. See [GitHub Help: Closing issues using keywords](https://help.github.com/articles/closing-issues-via-commit-messages/).
- [ ] I am aware this project is being **archived on 2026-09-01** and that no further changes will be merged, including bug fixes. See [README](https://github.com/filebrowser/filebrowser/blob/master/README.md)
- [ ] I am aware that translations MUST be made through [Transifex](https://app.transifex.com/file-browser/file-browser/) and that this PR is NOT a translation update
- [ ] I am making a PR against the `master` branch.
- [ ] I am sure File Browser can be successfully built. See [CONTRIBUTING.md](https://github.com/filebrowser/filebrowser/blob/master/CONTRIBUTING.md).

133
.github/workflows/ci.yaml vendored Normal file
View file

@ -0,0 +1,133 @@
name: Continuous Integration
on:
push:
branches:
- "master"
tags:
- "v*"
pull_request:
jobs:
lint-frontend:
name: Lint Frontend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v6
with:
node-version: "24.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- working-directory: frontend
run: |
pnpm install --frozen-lockfile
pnpm run lint
test-frontend:
name: Test Frontend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v6
with:
node-version: "24.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- working-directory: frontend
run: |
pnpm install --frozen-lockfile
pnpm run test
lint-backend:
name: Lint Backend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: "1.26.x"
- uses: golangci/golangci-lint-action@v9
with:
version: "latest"
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: "1.26.x"
- run: go test --race ./...
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-go@v6
with:
go-version: '1.26'
- uses: pnpm/action-setup@v6
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v6
with:
node-version: "24.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- name: Install Task
uses: go-task/setup-task@v2
- run: task build
release:
name: Release
needs: ["lint-frontend", "lint-backend", "test", "build"]
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-go@v6
with:
go-version: '1.26'
- uses: pnpm/action-setup@v6
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v6
with:
node-version: "24.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Install Task
uses: go-task/setup-task@v2
- run: task build:frontend
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v7
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}

46
.github/workflows/lint-pr.yaml vendored Normal file
View file

@ -0,0 +1,46 @@
name: "Lint PR"
on:
pull_request_target:
types:
- opened
- reopened
- edited
- synchronize
permissions:
pull-requests: write
jobs:
main:
name: Validate Title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v6
id: lint_pr_title
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: marocchino/sticky-pull-request-comment@v3
# When the previous steps fails, the workflow would stop. By adding this
# condition you can continue the execution with the populated error message.
if: always() && (steps.lint_pr_title.outputs.error_message != null)
with:
header: pr-title-lint-error
message: |
Hey there and thank you for opening this pull request! 👋🏼
We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted.
Details:
```
${{ steps.lint_pr_title.outputs.error_message }}
```
# Delete a previous comment when the issue has been resolved
- if: ${{ steps.lint_pr_title.outputs.error_message == null }}
uses: marocchino/sticky-pull-request-comment@v3
with:
header: pr-title-lint-error
delete: true

17
.gitignore vendored
View file

@ -1,15 +1,15 @@
*.db *.db
*.lock
*.bak *.bak
_old _old
rice-box.go rice-box.go
.idea/ .idea/
filebrowser /filebrowser
dist/ /filebrowser.exe
/dist
.venv
.DS_Store .DS_Store
node_modules node_modules
/frontend/dist
# local env files # local env files
.env.local .env.local
@ -28,3 +28,12 @@ yarn-error.log*
*.njsproj *.njsproj
*.sln *.sln
*.sw* *.sw*
bin/
build/
# Vue distributable files
/frontend/dist/*
!/frontend/dist/.gitkeep
default.nix
Dockerfile.dev

View file

@ -1,132 +1,14 @@
linters-settings: version: "2"
dupl:
threshold: 100
exhaustive:
default-signifies-exhaustive: false
funlen:
lines: 100
statements: 50
goconst:
min-len: 2
min-occurrences: 2
gocritic:
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
disabled-checks:
- dupImport # https://github.com/go-critic/go-critic/issues/845
- ifElseChain
- octalLiteral
- whyNoLint
- wrapperFunc
gocyclo:
min-complexity: 15
goimports:
local-prefixes: github.com/filebrowser/filebrowser
golint:
min-confidence: 0
gomnd:
settings:
mnd:
# don't include the "operation" and "assign"
checks: argument,case,condition,return
govet:
check-shadowing: true
lll:
line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
nolintlint:
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
allow-unused: false # report any unused nolint directives
require-explanation: false # don't require an explanation for nolint directives
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
linters: linters:
# please, do not use `enable-all`: it's deprecated and will be removed soon. default: standard
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
disable-all: true
enable: enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- funlen
- gochecknoinits
- goconst
- gocritic - gocritic
- gocyclo
- gofmt
- goimports
- golint
- gomnd
- goprintffuncname
- gosec
- gosimple
- govet - govet
- ineffassign - revive
- interfacer exclusions:
- lll presets:
- misspell - std-error-handling
- nakedret - comments
- nolintlint paths:
- rowserrcheck - frontend/
- scopelint
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
- prealloc
# don't enable:
# - asciicheck
# - exhaustive (TODO: enable after next release; current release at time of writing is v1.27)
# - gochecknoglobals
# - gocognit
# - godot
# - godox
# - goerr113
# - maligned
# - nestif
# - testpackage
# - wsl
issues:
exclude-rules:
- path: cmd/.*.go
linters:
- gochecknoinits
- path: .*_test.go
linters:
- lll
- gochecknoinits
- gocyclo
- funlen
- dupl
- scopelint
- text: "Auther"
linters:
- misspell
run:
skip-dirs:
- frontend/
skip-files:
- http/rice-box.go
# golangci.com configuration
# https://github.com/golangci/golangci/wiki/Configuration
service:
golangci-lint-version: 1.27.x # use the fixed version to not introduce new linters unexpectedly

View file

@ -1,81 +1,204 @@
version: 2
project_name: filebrowser project_name: filebrowser
env: env:
- GO111MODULE=on - GO111MODULE=on
before: builds:
hooks: - env:
- go mod download - CGO_ENABLED=0
ldflags:
build: - -s -w -X github.com/filebrowser/filebrowser/v2/version.Version={{ .Version }} -X github.com/filebrowser/filebrowser/v2/version.CommitSHA={{ .ShortCommit }}
env: main: main.go
- CGO_ENABLED=0 binary: filebrowser
ldflags: goos:
- -s -w -X github.com/filebrowser/filebrowser/v2/version.Version={{ .Version }} -X github.com/filebrowser/filebrowser/v2/version.CommitSHA={{ .ShortCommit }} - darwin
main: main.go - linux
binary: filebrowser - windows
goos: - freebsd
- darwin - openbsd
- linux goarch:
- windows - amd64
- freebsd - "386"
- netbsd - arm
- openbsd - arm64
- dragonfly - riscv64
- solaris goarm:
goarch: - "5"
- amd64 - "6"
- 386 - "7"
- arm ignore:
- arm64 - goos: darwin
goarm: goarch: "386"
- 5 # Experimental, may not work properly
- 6 - goos: openbsd
- 7 goarch: riscv64
ignore: # Broken as of Go 1.24, deprecated as of Go 1.26
- goos: darwin - goos: windows
goarch: 386 goarch: arm
- goos: openbsd - goos: freebsd
goarch: arm goarch: arm
- goos: freebsd
goarch: arm
- goos: netbsd
goarch: arm
- goos: solaris
goarch: arm
archives: archives:
- - name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}" formats: ["tar.gz"]
format: tar.gz
format_overrides: format_overrides:
- goos: windows - goos: windows
format: zip formats: ["zip"]
dockers: dockers:
- # Alpine docker images
dockerfile: Dockerfile - dockerfile: Dockerfile
binaries: use: buildx
- filebrowser build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/amd64"
goos: linux goos: linux
goarch: amd64 goarch: amd64
goarm: ''
image_templates: image_templates:
- "filebrowser/filebrowser:latest" - "filebrowser/filebrowser:{{ .Tag }}-amd64"
- "filebrowser/filebrowser:{{ .Tag }}" - "filebrowser/filebrowser:v{{ .Major }}-amd64"
- "filebrowser/filebrowser:v{{ .Major }}"
extra_files: extra_files:
- .docker.json - docker
- - dockerfile: Dockerfile
dockerfile: Dockerfile use: buildx
binaries: build_flag_templates:
- filebrowser - "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm64"
goos: linux
goarch: arm64
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
extra_files:
- docker
- dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm/v6"
goos: linux goos: linux
goarch: arm goarch: arm
goarm: '5' goarm: "6"
image_templates: image_templates:
- "filebrowser/filebrowser:pi" - "filebrowser/filebrowser:{{ .Tag }}-armv6"
- "filebrowser/filebrowser:{{ .Tag }}-pi" - "filebrowser/filebrowser:v{{ .Major }}-armv6"
- "filebrowser/filebrowser:v{{ .Major }}-pi"
extra_files: extra_files:
- .docker.json - docker
- dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm/v7"
goos: linux
goarch: arm
goarm: "7"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
extra_files:
- docker
## s6-overlay docker images
- dockerfile: Dockerfile.s6
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/amd64"
goos: linux
goarch: amd64
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
extra_files:
- docker
- dockerfile: Dockerfile.s6
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm64"
goos: linux
goarch: arm64
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-arm64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
extra_files:
- docker
docker_manifests:
- name_template: "filebrowser/filebrowser:latest"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
- name_template: "filebrowser/filebrowser:{{ .Tag }}"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
- name_template: "filebrowser/filebrowser:v{{ .Major }}"
image_templates:
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
## s6 image manifests
- name_template: "filebrowser/filebrowser:s6"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
- "filebrowser/filebrowser:{{ .Tag }}-arm64-s6"
- name_template: "filebrowser/filebrowser:{{ .Tag }}-s6"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
- "filebrowser/filebrowser:{{ .Tag }}-arm64-s6"
- name_template: "filebrowser/filebrowser:v{{ .Major }}-s6"
image_templates:
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
homebrew_casks:
- name: filebrowser
repository:
owner: filebrowser
name: homebrew-tap
commit_author:
name: FileBrowser Robot
email: robot@filebrowser.org
homepage: https://github.com/filebrowser/filebrowser
description: File Browser is a create-your-own-cloud-kind of software where you can install it on a server, direct it to a path and then access your files through a nice web interface
hooks:
post:
install: |
if system_command("/usr/bin/xattr", args: ["-h"]).exit_status == 0
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/filebrowser"]
end

View file

@ -1,10 +0,0 @@
[main]
host = https://www.transifex.com
lang_map = pt_BR: pt-br, zh_CN: zh-cn, zh_HK: zh-hk, zh_TW: zh-tw, nl_BE: nl-be, sv_SE: sv-se
[file-browser.file-browser]
file_filter = frontend/src/i18n/<lang>.json
minimum_perc = 50
source_file = frontend/src/i18n/en.json
source_lang = en
type = KEYVALUEJSON

14
.versionrc Normal file
View file

@ -0,0 +1,14 @@
{
"types": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance improvements" },
{ "type": "revert", "section": "Reverts" },
{ "type": "refactor", "section": "Refactorings" },
{ "type": "build", "section": "Build" },
{ "type": "ci", "hidden": true },
{ "type": "test", "hidden": true },
{ "type": "chore", "hidden": true },
{ "type": "docs", "hidden": true }
]
}

1931
CHANGELOG.md Normal file

File diff suppressed because it is too large Load diff

46
CODE-OF-CONDUCT.md Normal file
View file

@ -0,0 +1,46 @@
# Code of Conduct
## Contributor Covenant Code of Conduct
### Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hacdias@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available at [https://contributor-covenant.org/version/1/4](https://contributor-covenant.org/version/1/4).

115
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,115 @@
# Building File Browser
This project is archived on 2026-09-01. Pull requests are not accepted and no further changes are merged. This document is kept as build documentation for anyone wishing to build the project from source.
## Project Structure
The backend side of the application is written in [Go](https://golang.org/), while the frontend (located on a subdirectory of the same name) is written in [Vue.js](https://vuejs.org/). Due to the tight coupling required by some features, basic knowledge of both Go and Vue.js is recommended.
* Learn Go: [https://github.com/golang/go/wiki/Learn](https://github.com/golang/go/wiki/Learn)
* Learn Vue.js: [https://vuejs.org/guide/introduction.html](https://vuejs.org/guide/introduction.html)
We encourage you to use git to manage your fork. To clone the main repository, just run:
```bash
git clone https://github.com/filebrowser/filebrowser
```
We use [Taskfile](https://taskfile.dev/) to manage the different processes (building, releasing, etc) automatically.
## Build
You can fully build the project in order to produce a binary by running:
```bash
task build
```
## Development
For development, there are a few things to have in mind.
### Frontend
We use [Node.js](https://nodejs.org/en/) on the frontend to manage the build process. Prepare the frontend environment:
```bash
# From the root of the repo, go to frontend/
cd frontend
# Install the dependencies
pnpm install
```
If you just want to develop the backend, you can create a static build of the frontend:
```bash
pnpm run build
```
If you want to develop the frontend, start a development server which watches for changes:
```bash
pnpm run dev
```
Please note that you need to access File Browser's interface through the development server of the frontend.
### Backend
First prepare the backend environment by downloading all required dependencies:
```bash
go mod download
```
You can now build or run File Browser as any other Go project:
```bash
# Build
go build
# Run
go run .
```
## Documentation
Documentation lives in [`docs`](docs) as plain Markdown and is no longer built into a site. The command line reference in [`docs/cli`](docs/cli) is generated from the commands themselves:
```bash
task docs:cli:generate
```
## Release
To make a release, just run:
```bash
task release
```
## Translations
The Transifex integration stopped on 2026-09-01 and translations submitted there no longer reach this repository. Locale files live in [`frontend/src/i18n`](frontend/src/i18n) and can be edited directly.
## Authentication Provider
To build a new authentication provider, you need to implement the [Auther interface](https://github.com/filebrowser/filebrowser/blob/master/auth/auth.go), whose method will be called on the login page after the user has submitted their login data.
```go
// Auther is the authentication interface.
type Auther interface {
// Auth is called to authenticate a request.
Auth(r *http.Request, s *users.Storage, root string) (*users.User, error)
}
```
After implementing the interface you should:
1. Add it to [`auth` directory](https://github.com/filebrowser/filebrowser/blob/master/auth).
2. Add it to the [configuration parser](https://github.com/filebrowser/filebrowser/blob/master/cmd/config.go) for the CLI.
3. Add it to the [`authBackend.Get`](https://github.com/filebrowser/filebrowser/blob/master/storage/bolt/auth.go).
If you need to add more flags, please update the function `addConfigFlags`.

View file

@ -1,15 +1,46 @@
FROM alpine:latest as alpine ## Multistage build: First stage fetches dependencies
RUN apk --update add ca-certificates FROM alpine:3.23 AS fetcher
RUN apk --update add mailcap
FROM scratch # install and copy ca-certificates, mailcap, and tini-static; download JSON.sh
COPY --from=alpine /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt RUN apk update && \
COPY --from=alpine /etc/mime.types /etc/mime.types apk --no-cache add ca-certificates mailcap tini-static && \
wget -O /JSON.sh https://raw.githubusercontent.com/dominictarr/JSON.sh/0d5e5c77365f63809bf6e77ef44a1f34b0e05840/JSON.sh
## Second stage: Use lightweight BusyBox image for final runtime environment
FROM busybox:1.37.0-musl
# Define non-root user UID and GID
ENV UID=1000
ENV GID=1000
# Create user group and user
RUN addgroup -g $GID user && \
adduser -D -u $UID -G user user
# Copy binary, scripts, and configurations into image with proper ownership
COPY --chown=user:user filebrowser /bin/filebrowser
COPY --chown=user:user docker/common/ /
COPY --chown=user:user docker/alpine/ /
COPY --chown=user:user --from=fetcher /sbin/tini-static /bin/tini
COPY --from=fetcher /JSON.sh /JSON.sh
COPY --from=fetcher /etc/ca-certificates.conf /etc/ca-certificates.conf
COPY --from=fetcher /etc/ca-certificates /etc/ca-certificates
COPY --from=fetcher /etc/mime.types /etc/mime.types
COPY --from=fetcher /etc/ssl /etc/ssl
# Create data directories, set ownership, and ensure healthcheck script is executable
RUN mkdir -p /config /database /srv && \
chown -R user:user /config /database /srv \
&& chmod +x /healthcheck.sh
# Define healthcheck script
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh
# Set the user, volumes and exposed ports
USER user
VOLUME /srv /config /database
VOLUME /srv
EXPOSE 80 EXPOSE 80
COPY .docker.json /.filebrowser.json ENTRYPOINT [ "tini", "--", "/init.sh" ]
COPY filebrowser /filebrowser
ENTRYPOINT [ "/filebrowser" ]

24
Dockerfile.s6 Normal file
View file

@ -0,0 +1,24 @@
FROM ghcr.io/linuxserver/baseimage-alpine:3.23
RUN apk update && \
apk --no-cache add ca-certificates mailcap jq libcap
# Make user and create necessary directories
RUN mkdir -p /config /database /srv && \
chown -R abc:abc /config /database /srv
# Copy files and set permissions
COPY filebrowser /bin/filebrowser
COPY docker/common/ /
COPY docker/s6/ /
RUN chown -R abc:abc /bin/filebrowser /defaults healthcheck.sh && \
setcap 'cap_net_bind_service=+ep' /bin/filebrowser
# Define healthcheck script
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh
# Set the volumes and exposed ports
VOLUME /srv /config /database
EXPOSE 80

View file

@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright 2018 File Browser contributors Copyright 2018 File Browser Contributors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View file

@ -1,29 +1,36 @@
> [!WARNING]
>
> **File Browser is archived on 2026-09-01**. The last planned release has already shipped. There will be no further releases, bug fixes, or security fixes.
<p align="center"> <p align="center">
<img src="https://raw.githubusercontent.com/filebrowser/logo/master/banner.png" width="550"/> <img src="./branding/banner.png" width="550"/>
</p> </p>
![Preview](https://user-images.githubusercontent.com/5447088/50716739-ebd26700-107a-11e9-9817-14230c53efd2.gif) File Browser provides a file managing interface within a specified directory and it can be used to upload, delete, preview and edit your files. It is a **create-your-own-cloud**-kind of software where you can just install it on your server, direct it to a path and access your files through a nice web interface.
[![Travis](https://img.shields.io/travis/com/filebrowser/filebrowser.svg?style=flat-square)](https://travis-ci.com/filebrowser/filebrowser) **Background:** [Goodbye File Browser, for Real This Time](https://hacdias.com/2026/07/28/filebrowser/), July 2026.
[![Go Report Card](https://goreportcard.com/badge/github.com/filebrowser/filebrowser?style=flat-square)](https://goreportcard.com/report/github.com/filebrowser/filebrowser)
[![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/filebrowser/filebrowser)
[![Version](https://img.shields.io/github/release/filebrowser/filebrowser.svg?style=flat-square)](https://github.com/filebrowser/filebrowser/releases/latest)
[![Chat IRC](https://img.shields.io/badge/freenode-%23filebrowser-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23filebrowser)
filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app or as a middleware. ## Security
## Features Published advisories are listed under [security advisories](https://github.com/filebrowser/filebrowser/security/advisories),
and reporting instructions are in [SECURITY.md](SECURITY.md). Two known issue classes
remain unaddressed and will not be fixed:
Please refer to our docs at [filebrowser.xyz/features](https://github.com/filebrowser/docs/tree/master/features) - **Command execution, runner, and hooks.** This feature is plagued with vulnerabilities across many published advisories, and would need a full rewrite to be made safe. It is disabled by default; if you re-enable it with `--disable-exec=false`, treat the ability to run commands as equivalent to shell access on the host. Background: [#5199](https://github.com/filebrowser/filebrowser/issues/5199).
- **Session and JWT handling.** Sessions are self-contained JWTs rather than server-side identifiers, so they cannot be revoked, which means that logout, password changes, and renewal leave previously issued tokens valid until they expire, and the same refresh token can be redeemed repeatedly. Assume a leaked token is valid until expiry. Background: [#5216](https://github.com/filebrowser/filebrowser/issues/5216).
## Install If you keep running File Browser, treat it as unmaintained software:
Please refer to our docs at [filebrowser.xyz](https://github.com/filebrowser/docs/tree/master/). - **Do not expose it directly to the internet.** Put it behind a reverse proxy that terminates TLS and performs its own authentication.
- **Keep the command runner disabled.** It is off by default, so leave it off. See [#5199](https://github.com/filebrowser/filebrowser/issues/5199) and [`docs/command-execution.md`](docs/command-execution.md).
- **Run it unprivileged, inside a container**, with only the directory you intend to serve mounted into it.
## Usage ## Documentation
Please refer to our docs at [filebrowser.xyz/usage](https://github.com/filebrowser/docs/tree/master/usage). Documentation on how to install, configure, and build this project lives in [`docs`](docs) in this repository.
## Contributing [CONTRIBUTING.md](CONTRIBUTING.md) documents how to build and develop the project, which remains useful to anyone forking it.
Please refer to our docs at [filebrowser.xyz/contributing](https://github.com/filebrowser/docs/tree/master/contributing). ## License
[Apache License 2.0](LICENSE) © File Browser Contributors

30
SECURITY.md Normal file
View file

@ -0,0 +1,30 @@
# Security Policy
## Supported Versions
No version receives security fixes. The last planned release has already shipped and no further changes will be merged.
| Version | Supported |
| ------- | --------- |
| 2.x | ❌ |
| < 2.0 | |
## Before Reporting
This project is being wound down. To avoid duplicates, first check the [existing advisories](https://github.com/filebrowser/filebrowser/security/advisories) and open issues, and confirm:
- **It concerns this project, not a fork.** Reports about code, features, or endpoints that don't exist here belong to the relevant fork.
- **It isn't an already-known class** that remains unaddressed. Those are listed under [Security](README.md#security) in the README; reports covering them are likely to be closed as duplicates.
## Reporting a Vulnerability
Until 2026-09-01, report privately via the [Security](https://github.com/filebrowser/filebrowser/security) page. After that date this repository is read-only and reports can no longer be submitted.
Please include, where possible:
- The commit the issue was found at
- A plaintext proof of concept (no binaries)
- Steps to reproduce
- Recommended remediation, if any
No fix will ship for any report: the last planned release has already shipped and no further changes will be merged. Reports may still be published as advisories so that people running File Browser can assess their exposure.

57
Taskfile.yml Normal file
View file

@ -0,0 +1,57 @@
version: '3'
tasks:
build:frontend:
desc: Build frontend assets
dir: frontend
cmds:
- pnpm install --frozen-lockfile
- pnpm run build
build:backend:
desc: Build backend binary
cmds:
- go build -ldflags='-s -w -X "github.com/filebrowser/filebrowser/v2/version.Version={{.VERSION}}" -X "github.com/filebrowser/filebrowser/v2/version.CommitSHA={{.GIT_COMMIT}}"' -o filebrowser .
vars:
GIT_COMMIT:
sh: git log -n 1 --format=%h
VERSION:
sh: git describe --tags --abbrev=0 --match=v* | cut -c 2-
build:
desc: Build both frontend and backend
cmds:
- task: build:frontend
- task: build:backend
release:make:
internal: true
prompt: Do you wish to proceed?
cmds:
- pnpm dlx commit-and-tag-version -s
release:dry-run:
internal: true
cmds:
- pnpm dlx commit-and-tag-version --dry-run --skip
release:
desc: Create a new release
cmds:
- task: docs:cli:generate
- git add docs/cli
- |
if [[ `git status docs/cli --porcelain` ]]; then
git commit -m 'chore(docs): update CLI documentation'
fi
- task: release:dry-run
- task: release:make
docs:cli:generate:
cmds:
- rm -rf docs/cli
- mkdir -p docs/cli
- go run . docs
generates:
- docs/cli

View file

@ -3,13 +3,14 @@ package auth
import ( import (
"net/http" "net/http"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
) )
// Auther is the authentication interface. // Auther is the authentication interface.
type Auther interface { type Auther interface {
// Auth is called to authenticate a request. // Auth is called to authenticate a request.
Auth(r *http.Request, s *users.Storage, root string) (*users.User, error) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error)
// LoginPage indicates if this auther needs a login page. // LoginPage indicates if this auther needs a login page.
LoginPage() bool LoginPage() bool
} }

288
auth/hook.go Normal file
View file

@ -0,0 +1,288 @@
package auth
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"os"
"os/exec"
"slices"
"strings"
fberrors "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/files"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users"
)
// MethodHookAuth is used to identify hook auth.
const MethodHookAuth settings.AuthMethod = "hook"
type hookCred struct {
Password string `json:"password"`
Username string `json:"username"`
}
// HookAuth is a hook implementation of an Auther.
type HookAuth struct {
Users users.Store `json:"-"`
Settings *settings.Settings `json:"-"`
Server *settings.Server `json:"-"`
Cred hookCred `json:"-"`
Fields hookFields `json:"-"`
Command string `json:"command"`
}
// Auth authenticates the user via a json in content body.
func (a *HookAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
var cred hookCred
if r.Body == nil {
return nil, os.ErrPermission
}
err := json.NewDecoder(r.Body).Decode(&cred)
if err != nil {
return nil, os.ErrPermission
}
a.Users = usr
a.Settings = stg
a.Server = srv
a.Cred = cred
action, err := a.RunCommand()
if err != nil {
return nil, err
}
switch action {
case "auth":
u, err := a.SaveUser()
if err != nil {
return nil, err
}
return u, nil
case "block":
return nil, os.ErrPermission
case "pass":
u, err := a.Users.Get(a.Server.Root, a.Server.FollowExternalSymlinks, a.Cred.Username)
if err != nil || !users.CheckPwd(a.Cred.Password, u.Password) {
return nil, os.ErrPermission
}
return u, nil
default:
return nil, fmt.Errorf("invalid hook action: %s", action)
}
}
// LoginPage tells that hook auth requires a login page.
func (a *HookAuth) LoginPage() bool {
return true
}
// RunCommand starts the hook command and returns the action
func (a *HookAuth) RunCommand() (string, error) {
command := strings.Split(a.Command, " ")
cmd := exec.Command(command[0], command[1:]...)
cmd.Env = append(os.Environ(), fmt.Sprintf("USERNAME=%s", a.Cred.Username))
cmd.Env = append(cmd.Env, fmt.Sprintf("PASSWORD=%s", a.Cred.Password))
out, err := cmd.Output()
if err != nil {
return "", err
}
a.GetValues(string(out))
return a.Fields.Values["hook.action"], nil
}
// GetValues creates a map with values from the key-value format string
func (a *HookAuth) GetValues(s string) {
m := map[string]string{}
// make line breaks consistent on Windows platform
s = strings.ReplaceAll(s, "\r\n", "\n")
// iterate input lines
for val := range strings.Lines(s) {
v := strings.SplitN(val, "=", 2)
// skips non key and value format
if len(v) != 2 {
continue
}
fieldKey := strings.TrimSpace(v[0])
fieldValue := strings.TrimSpace(v[1])
if a.Fields.IsValid(fieldKey) {
m[fieldKey] = fieldValue
}
}
a.Fields.Values = m
}
// SaveUser updates the existing user or creates a new one when not found
func (a *HookAuth) SaveUser() (*users.User, error) {
u, err := a.Users.Get(a.Server.Root, a.Server.FollowExternalSymlinks, a.Cred.Username)
if err != nil && !errors.Is(err, fberrors.ErrNotExist) {
return nil, err
}
if u == nil {
pass, err := users.ValidateAndHashPwd(a.Cred.Password, a.Settings.MinimumPasswordLength)
if err != nil {
return nil, err
}
// create user with the provided credentials
d := &users.User{
Username: a.Cred.Username,
Password: pass,
Scope: a.Settings.Defaults.Scope,
Locale: a.Settings.Defaults.Locale,
ViewMode: a.Settings.Defaults.ViewMode,
SingleClick: a.Settings.Defaults.SingleClick,
RedirectAfterCopyMove: a.Settings.Defaults.RedirectAfterCopyMove,
Sorting: a.Settings.Defaults.Sorting,
Perm: a.Settings.Defaults.Perm,
Commands: a.Settings.Defaults.Commands,
DateFormat: a.Settings.Defaults.DateFormat,
HideDotfiles: a.Settings.Defaults.HideDotfiles,
}
u = a.GetUser(d)
// A scope explicitly returned by the hook takes precedence over the
// automatic per-user home directory derivation.
_, explicitScope := a.Fields.Values["user.scope"]
derivedScope, err := a.Settings.CreateUserHome(u, a.Server.Root, explicitScope)
if err != nil {
return nil, err
}
log.Printf("user: %s, home dir: [%s].", u.Username, u.Scope)
if err := a.Users.SaveProvisioned(u, derivedScope); err != nil {
return nil, err
}
} else if p := !users.CheckPwd(a.Cred.Password, u.Password); len(a.Fields.Values) > 1 || p {
u = a.GetUser(u)
// update the password when it doesn't match the current
if p {
pass, err := users.ValidateAndHashPwd(a.Cred.Password, a.Settings.MinimumPasswordLength)
if err != nil {
return nil, err
}
u.Password = pass
}
// update user with provided fields
err := a.Users.Update(u)
if err != nil {
return nil, err
}
}
return u, nil
}
// GetUser returns a User filled with hook values or provided defaults
func (a *HookAuth) GetUser(d *users.User) *users.User {
// adds all permissions when user is admin
isAdmin := a.Fields.GetBoolean("user.perm.admin", d.Perm.Admin)
perms := users.Permissions{
Admin: isAdmin,
Execute: isAdmin || a.Fields.GetBoolean("user.perm.execute", d.Perm.Execute),
Create: isAdmin || a.Fields.GetBoolean("user.perm.create", d.Perm.Create),
Rename: isAdmin || a.Fields.GetBoolean("user.perm.rename", d.Perm.Rename),
Modify: isAdmin || a.Fields.GetBoolean("user.perm.modify", d.Perm.Modify),
Delete: isAdmin || a.Fields.GetBoolean("user.perm.delete", d.Perm.Delete),
Share: isAdmin || a.Fields.GetBoolean("user.perm.share", d.Perm.Share),
Download: isAdmin || a.Fields.GetBoolean("user.perm.download", d.Perm.Download),
}
user := users.User{
ID: d.ID,
Username: d.Username,
Password: d.Password,
Scope: a.Fields.GetString("user.scope", d.Scope),
Locale: a.Fields.GetString("user.locale", d.Locale),
ViewMode: users.ViewMode(a.Fields.GetString("user.viewMode", string(d.ViewMode))),
SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick),
RedirectAfterCopyMove: a.Fields.GetBoolean("user.redirectAfterCopyMove", d.RedirectAfterCopyMove),
Sorting: files.Sorting{
Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc),
By: a.Fields.GetString("user.sorting.by", d.Sorting.By),
},
Commands: a.Fields.GetArray("user.commands", d.Commands),
DateFormat: a.Fields.GetBoolean("user.dateFormat", d.DateFormat),
HideDotfiles: a.Fields.GetBoolean("user.hideDotfiles", d.HideDotfiles),
Perm: perms,
LockPassword: true,
}
return &user
}
// hookFields is used to access fields from the hook
type hookFields struct {
Values map[string]string
}
// validHookFields contains names of the fields that can be used
var validHookFields = []string{
"hook.action",
"user.scope",
"user.locale",
"user.viewMode",
"user.singleClick",
"user.redirectAfterCopyMove",
"user.sorting.by",
"user.sorting.asc",
"user.commands",
"user.hideDotfiles",
"user.perm.admin",
"user.perm.execute",
"user.perm.create",
"user.perm.rename",
"user.perm.modify",
"user.perm.delete",
"user.perm.share",
"user.perm.download",
}
// IsValid checks if the provided field is on the valid fields list
func (hf *hookFields) IsValid(field string) bool {
return slices.Contains(validHookFields, field)
}
// GetString returns the string value or provided default
func (hf *hookFields) GetString(k, dv string) string {
val, ok := hf.Values[k]
if ok {
return val
}
return dv
}
// GetBoolean returns the bool value or provided default
func (hf *hookFields) GetBoolean(k string, dv bool) bool {
val, ok := hf.Values[k]
if ok {
return val == "true"
}
return dv
}
// GetArray returns the array value or provided default
func (hf *hookFields) GetArray(k string, dv []string) []string {
val, ok := hf.Values[k]
if ok && strings.TrimSpace(val) != "" {
return strings.Split(val, " ")
}
return dv
}

156
auth/hook_test.go Normal file
View file

@ -0,0 +1,156 @@
package auth
import (
"os"
"path/filepath"
"runtime"
"testing"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users"
)
// writeHookScript writes a POSIX shell script to a temp file and returns its
// path, marking it executable.
func writeHookScript(t *testing.T, body string) string {
t.Helper()
path := filepath.Join(t.TempDir(), "hook.sh")
if err := os.WriteFile(path, []byte("#!/bin/sh\n"+body), 0o700); err != nil {
t.Fatalf("failed to write hook script: %v", err)
}
return path
}
// TestRunCommandNoCredentialInjection ensures that attacker-controlled
// credentials submitted at the unauthenticated login endpoint cannot be
// injected into the hook command string. Credentials must only ever reach the
// hook through the USERNAME/PASSWORD environment variables, never via string
// substitution into the command itself (CWE-78/CWE-88).
func TestRunCommandNoCredentialInjection(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("uses POSIX shell")
}
marker := filepath.Join(t.TempDir(), "pwned")
// The hook simply blocks. If the credential were ever interpolated into the
// command string and evaluated by a shell, the embedded `touch` would
// create the marker file.
script := writeHookScript(t, "echo hook.action=block\n")
a := &HookAuth{
Command: script,
Cred: hookCred{
Username: `"; touch ` + marker + `; #`,
Password: `$(touch ` + marker + `)`,
},
}
action, err := a.RunCommand()
if err != nil {
t.Fatalf("RunCommand returned error: %v", err)
}
if action != "block" {
t.Fatalf("expected action %q, got %q", "block", action)
}
if _, err := os.Stat(marker); err == nil {
t.Fatalf("credential injection executed: marker file %q was created", marker)
}
}
// TestRunCommandReceivesCredentialsViaEnv verifies the supported contract: the
// hook receives credentials through the USERNAME and PASSWORD environment
// variables.
func TestRunCommandReceivesCredentialsViaEnv(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("uses POSIX shell")
}
script := writeHookScript(t, `if [ "$USERNAME" = alice ] && [ "$PASSWORD" = secret ]; then
echo hook.action=auth
else
echo hook.action=block
fi
`)
a := &HookAuth{
Command: script,
Cred: hookCred{
Username: "alice",
Password: "secret",
},
}
action, err := a.RunCommand()
if err != nil {
t.Fatalf("RunCommand returned error: %v", err)
}
if action != "auth" {
t.Fatalf("expected action %q, got %q", "auth", action)
}
}
// newHookAuth builds a HookAuth for a freshly provisioned user with the given
// parsed hook fields (hook.action=auth is added automatically).
func newHookAuth(store *mockUserStore, s *settings.Settings, srv *settings.Server, username string, fields map[string]string) *HookAuth {
fields["hook.action"] = "auth"
return &HookAuth{
Users: store,
Settings: s,
Server: srv,
Cred: hookCred{Username: username, Password: "a-strong-password"},
Fields: hookFields{Values: fields},
}
}
// With CreateUserDir enabled and no explicit scope from the hook, a provisioned
// hook user must receive its own home directory rather than the server root.
func TestHookSaveUserCreateUserDirIsolatesScope(t *testing.T) {
t.Parallel()
store := &mockUserStore{users: make(map[string]*users.User)}
srv := &settings.Server{Root: t.TempDir()}
s := &settings.Settings{
Key: []byte("key"),
CreateUserDir: true,
UserHomeBasePath: "/users",
Defaults: settings.UserDefaults{
Scope: ".",
Perm: users.Permissions{Create: true},
},
}
u, err := newHookAuth(store, s, srv, "alice", map[string]string{}).SaveUser()
if err != nil {
t.Fatalf("SaveUser error: %v", err)
}
if u.Scope != "/users/alice" {
t.Errorf("hook user without explicit scope: expected /users/alice, got %q", u.Scope)
}
}
// A scope explicitly returned by the hook takes precedence over the automatic
// per-user home directory derivation.
func TestHookSaveUserRespectsExplicitScope(t *testing.T) {
t.Parallel()
store := &mockUserStore{users: make(map[string]*users.User)}
srv := &settings.Server{Root: t.TempDir()}
s := &settings.Settings{
Key: []byte("key"),
CreateUserDir: true,
UserHomeBasePath: "/users",
Defaults: settings.UserDefaults{
Scope: ".",
Perm: users.Permissions{Create: true},
},
}
u, err := newHookAuth(store, s, srv, "teamlead", map[string]string{"user.scope": "/shared/team"}).SaveUser()
if err != nil {
t.Fatalf("SaveUser error: %v", err)
}
if u.Scope != "/shared/team" {
t.Errorf("explicit hook scope should win, got %q", u.Scope)
}
}

View file

@ -14,6 +14,10 @@ import (
// MethodJSONAuth is used to identify json auth. // MethodJSONAuth is used to identify json auth.
const MethodJSONAuth settings.AuthMethod = "json" const MethodJSONAuth settings.AuthMethod = "json"
// dummyHash is used to prevent user enumeration timing attacks.
// It MUST be a valid bcrypt hash.
const dummyHash = "$2a$10$O4mEMeOL/nit6zqe.WQXauLRbRlzb3IgLHsa26Pf0N/GiU9b.wK1m"
type jsonCred struct { type jsonCred struct {
Password string `json:"password"` Password string `json:"password"`
Username string `json:"username"` Username string `json:"username"`
@ -26,7 +30,7 @@ type JSONAuth struct {
} }
// Auth authenticates the user via a json in content body. // Auth authenticates the user via a json in content body.
func (a JSONAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) { func (a JSONAuth) Auth(r *http.Request, usr users.Store, _ *settings.Settings, srv *settings.Server) (*users.User, error) {
var cred jsonCred var cred jsonCred
if r.Body == nil { if r.Body == nil {
@ -39,8 +43,8 @@ func (a JSONAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users
} }
// If ReCaptcha is enabled, check the code. // If ReCaptcha is enabled, check the code.
if a.ReCaptcha != nil && len(a.ReCaptcha.Secret) > 0 { if a.ReCaptcha != nil && a.ReCaptcha.Secret != "" {
ok, err := a.ReCaptcha.Ok(cred.ReCaptcha) //nolint:shadow ok, err := a.ReCaptcha.Ok(cred.ReCaptcha)
if err != nil { if err != nil {
return nil, err return nil, err
@ -51,8 +55,18 @@ func (a JSONAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users
} }
} }
u, err := sto.Get(root, cred.Username) u, err := usr.Get(srv.Root, srv.FollowExternalSymlinks, cred.Username)
if err != nil || !users.CheckPwd(cred.Password, u.Password) {
hash := dummyHash
if err == nil {
hash = u.Password
}
if !users.CheckPwd(cred.Password, hash) {
return nil, os.ErrPermission
}
if err != nil {
return nil, os.ErrPermission return nil, os.ErrPermission
} }

View file

@ -14,8 +14,8 @@ const MethodNoAuth settings.AuthMethod = "noauth"
type NoAuth struct{} type NoAuth struct{}
// Auth uses authenticates user 1. // Auth uses authenticates user 1.
func (a NoAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) { func (a NoAuth) Auth(_ *http.Request, usr users.Store, _ *settings.Settings, srv *settings.Server) (*users.User, error) {
return sto.Get(root, uint(1)) return usr.Get(srv.Root, srv.FollowExternalSymlinks, uint(1))
} }
// LoginPage tells that no auth doesn't require a login page. // LoginPage tells that no auth doesn't require a login page.

View file

@ -1,10 +1,10 @@
package auth package auth
import ( import (
"errors"
"net/http" "net/http"
"os"
"github.com/filebrowser/filebrowser/v2/errors" fberrors "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
) )
@ -18,14 +18,48 @@ type ProxyAuth struct {
} }
// Auth authenticates the user via an HTTP header. // Auth authenticates the user via an HTTP header.
func (a ProxyAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) { func (a ProxyAuth) Auth(r *http.Request, usr users.Store, setting *settings.Settings, srv *settings.Server) (*users.User, error) {
username := r.Header.Get(a.Header) username := r.Header.Get(a.Header)
user, err := sto.Get(root, username) user, err := usr.Get(srv.Root, srv.FollowExternalSymlinks, username)
if err == errors.ErrNotExist { if errors.Is(err, fberrors.ErrNotExist) {
return nil, os.ErrPermission return a.createUser(usr, setting, srv, username)
}
return user, err
}
func (a ProxyAuth) createUser(usr users.Store, setting *settings.Settings, srv *settings.Server, username string) (*users.User, error) {
const randomPasswordLength = settings.DefaultMinimumPasswordLength + 10
pwd, err := users.RandomPwd(randomPasswordLength)
if err != nil {
return nil, err
} }
return user, err var hashedRandomPassword string
hashedRandomPassword, err = users.ValidateAndHashPwd(pwd, setting.MinimumPasswordLength)
if err != nil {
return nil, err
}
user := &users.User{
Username: username,
Password: hashedRandomPassword,
LockPassword: true,
}
setting.Defaults.Apply(user)
user.Perm.Admin = false
user.Perm.Execute = false
user.Commands = []string{}
var derivedScope bool
if derivedScope, err = setting.CreateUserHome(user, srv.Root, false); err != nil {
return nil, err
}
if err = usr.SaveProvisioned(user, derivedScope); err != nil {
return nil, err
}
return user, nil
} }
// LoginPage tells that proxy auth doesn't require a login page. // LoginPage tells that proxy auth doesn't require a login page.

142
auth/proxy_test.go Normal file
View file

@ -0,0 +1,142 @@
package auth
import (
"net/http"
"strings"
"testing"
fberrors "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users"
)
type mockUserStore struct {
users map[string]*users.User
}
func (m *mockUserStore) Get(_ string, _ bool, id interface{}) (*users.User, error) {
if v, ok := id.(string); ok {
if u, ok := m.users[v]; ok {
return u, nil
}
}
return nil, fberrors.ErrNotExist
}
func (m *mockUserStore) GetByScope(scope string) (*users.User, error) {
for _, u := range m.users {
if strings.EqualFold(u.Scope, scope) {
return u, nil
}
}
return nil, fberrors.ErrNotExist
}
func (m *mockUserStore) Gets(_ string, _ bool) ([]*users.User, error) { return nil, nil }
func (m *mockUserStore) Update(_ *users.User, _ ...string) error { return nil }
func (m *mockUserStore) Save(user *users.User) error {
m.users[user.Username] = user
return nil
}
func (m *mockUserStore) SaveProvisioned(user *users.User, derivedScope bool) error {
if derivedScope {
if _, err := m.GetByScope(user.Scope); err == nil {
return fberrors.ErrExist
}
}
return m.Save(user)
}
func (m *mockUserStore) Delete(_ interface{}) error { return nil }
func (m *mockUserStore) LastUpdate(_ uint) int64 { return 0 }
func TestProxyAuthCreateUserRestrictsDefaults(t *testing.T) {
t.Parallel()
store := &mockUserStore{users: make(map[string]*users.User)}
srv := &settings.Server{Root: t.TempDir()}
s := &settings.Settings{
Key: []byte("key"),
AuthMethod: MethodProxyAuth,
Defaults: settings.UserDefaults{
Perm: users.Permissions{
Admin: true,
Execute: true,
Create: true,
Rename: true,
Modify: true,
Delete: true,
Share: true,
Download: true,
},
Commands: []string{"git", "ls", "cat", "id"},
},
}
auth := ProxyAuth{Header: "X-Remote-User"}
req, _ := http.NewRequest(http.MethodGet, "/", http.NoBody)
req.Header.Set("X-Remote-User", "newproxyuser")
user, err := auth.Auth(req, store, s, srv)
if err != nil {
t.Fatalf("Auth() error: %v", err)
}
if user.Perm.Admin {
t.Error("auto-provisioned proxy user should not have Admin permission")
}
if user.Perm.Execute {
t.Error("auto-provisioned proxy user should not have Execute permission")
}
if len(user.Commands) != 0 {
t.Errorf("auto-provisioned proxy user should have empty Commands, got %v", user.Commands)
}
if !user.Perm.Create {
t.Error("auto-provisioned proxy user should retain Create permission from defaults")
}
}
// With CreateUserDir enabled, two distinct proxy-authenticated users must each
// receive their own home directory instead of both inheriting the server root.
func TestProxyAuthCreateUserDirIsolatesScope(t *testing.T) {
t.Parallel()
store := &mockUserStore{users: make(map[string]*users.User)}
srv := &settings.Server{Root: t.TempDir()}
s := &settings.Settings{
Key: []byte("key"),
AuthMethod: MethodProxyAuth,
CreateUserDir: true,
UserHomeBasePath: "/users",
Defaults: settings.UserDefaults{
Scope: ".",
Perm: users.Permissions{Create: true},
},
}
auth := ProxyAuth{Header: "X-Remote-User"}
provision := func(name string) *users.User {
req, _ := http.NewRequest(http.MethodGet, "/", http.NoBody)
req.Header.Set("X-Remote-User", name)
u, err := auth.Auth(req, store, s, srv)
if err != nil {
t.Fatalf("Auth(%q) error: %v", name, err)
}
return u
}
alice := provision("alice")
bob := provision("bob")
if alice.Scope == "/" || bob.Scope == "/" {
t.Fatalf("provisioned users inherited the server root: alice=%q bob=%q", alice.Scope, bob.Scope)
}
if alice.Scope == bob.Scope {
t.Fatalf("distinct users must get distinct scopes, both got %q", alice.Scope)
}
if alice.Scope != "/users/alice" {
t.Errorf("expected /users/alice, got %q", alice.Scope)
}
}

BIN
branding/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

1
branding/banner.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

BIN
branding/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

1
branding/icon.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="700" height="700" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"><defs><style>.prefix__fil1{fill:#fefefe}.prefix__fil6{fill:#006498}.prefix__fil5{fill:#bdeaff}</style></defs><g id="prefix__Layer_x0020_1"><path d="M80 0h540c44 0 80 36 80 80v540c0 44-36 80-80 80H80c-44 0-80-36-80-80V80C0 36 36 0 80 0z" fill="#455a64"/><path class="prefix__fil1" d="M350 71c154 0 279 125 279 279S504 629 350 629 71 504 71 350 196 71 350 71z"/><path d="M475 236l118 151c3 116-149 252-292 198l-76-99 114-156s138-95 136-94z" fill="#332c2b" fill-opacity=".149"/><path d="M231 211h208l38 24v246c0 5-3 8-8 8H231c-5 0-8-3-8-8V219c0-5 3-8 8-8z" fill="#2bbcff"/><path d="M231 211h208l38 24v2l-37-23H231c-4 0-7 3-7 7v263c-1-1-1-2-1-3V219c0-5 3-8 8-8z" fill="#53c6fc"/><path class="prefix__fil5" d="M305 212h113v98H305zM255 363h189c3 0 5 2 5 4v116H250V367c0-2 2-4 5-4z"/><path class="prefix__fil6" d="M250 470h199v13H250zM380 226h10c3 0 6 2 6 5v40c0 3-3 6-6 6h-10c-3 0-6-3-6-6v-40c0-3 3-5 6-5z"/><path class="prefix__fil1" d="M254 226c10 0 17 7 17 17 0 9-7 16-17 16-9 0-17-7-17-16 0-10 8-17 17-17z"/><path class="prefix__fil6" d="M267 448h165c2 0 3 1 3 3 0 1-1 3-3 3H267c-2 0-3-2-3-3 0-2 1-3 3-3zM267 415h165c2 0 3 1 3 3 0 1-1 2-3 2H267c-2 0-3-1-3-2 0-2 1-3 3-3zM267 381h165c2 0 3 2 3 3 0 2-1 3-3 3H267c-2 0-3-1-3-3 0-1 1-3 3-3z"/><path class="prefix__fil1" d="M236 472c3 0 5 2 5 5 0 2-2 4-5 4s-5-2-5-4c0-3 2-5 5-5zM463 472c3 0 5 2 5 5 0 2-2 4-5 4s-5-2-5-4c0-3 2-5 5-5z"/><path class="prefix__fil6" d="M305 212h-21v98h21z"/><path d="M477 479v2c0 5-3 8-8 8H231c-5 0-8-3-8-8v-2c0 4 3 8 8 8h238c5 0 8-4 8-8z" fill="#0ea5eb"/><path d="M350 70c155 0 280 125 280 280S505 630 350 630 70 505 70 350 195 70 350 70zm0 46c129 0 234 105 234 234S479 584 350 584 116 479 116 350s105-234 234-234z" fill="#2979ff"/></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
branding/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

1
branding/logo.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="560" height="560" version="1.1" id="prefix__svg44" clip-rule="evenodd" fill-rule="evenodd" image-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="geometricPrecision"><defs id="prefix__defs4"><style type="text/css" id="style2">.prefix__fil1{fill:#fefefe}.prefix__fil6{fill:#006498}.prefix__fil5{fill:#bdeaff}</style></defs><g id="prefix__g85" transform="translate(-70 -70)"><path class="prefix__fil1" d="M350 71c154 0 279 125 279 279S504 629 350 629 71 504 71 350 196 71 350 71z" id="prefix__path9" fill="#fefefe"/><path d="M475 236l118 151c3 116-149 252-292 198l-76-99 114-156s138-95 136-94z" id="prefix__path11" fill="#332c2b" fill-opacity=".149"/><path d="M231 211h208l38 24v246c0 5-3 8-8 8H231c-5 0-8-3-8-8V219c0-5 3-8 8-8z" id="prefix__path13" fill="#2bbcff"/><path d="M231 211h208l38 24v2l-37-23H231c-4 0-7 3-7 7v263c-1-1-1-2-1-3V219c0-5 3-8 8-8z" id="prefix__path15" fill="#53c6fc"/><path class="prefix__fil5" id="prefix__polygon17" fill="#bdeaff" d="M305 212h113v98H305z"/><path class="prefix__fil5" d="M255 363h189c3 0 5 2 5 4v116H250V367c0-2 2-4 5-4z" id="prefix__path19" fill="#bdeaff"/><path class="prefix__fil6" id="prefix__polygon21" fill="#006498" d="M250 470h199v13H250z"/><path class="prefix__fil6" d="M380 226h10c3 0 6 2 6 5v40c0 3-3 6-6 6h-10c-3 0-6-3-6-6v-40c0-3 3-5 6-5z" id="prefix__path23" fill="#006498"/><path class="prefix__fil1" d="M254 226c10 0 17 7 17 17 0 9-7 16-17 16-9 0-17-7-17-16 0-10 8-17 17-17z" id="prefix__path25" fill="#fefefe"/><path class="prefix__fil6" d="M267 448h165c2 0 3 1 3 3 0 1-1 3-3 3H267c-2 0-3-2-3-3 0-2 1-3 3-3z" id="prefix__path27" fill="#006498"/><path class="prefix__fil6" d="M267 415h165c2 0 3 1 3 3 0 1-1 2-3 2H267c-2 0-3-1-3-2 0-2 1-3 3-3z" id="prefix__path29" fill="#006498"/><path class="prefix__fil6" d="M267 381h165c2 0 3 2 3 3 0 2-1 3-3 3H267c-2 0-3-1-3-3 0-1 1-3 3-3z" id="prefix__path31" fill="#006498"/><path class="prefix__fil1" d="M236 472c3 0 5 2 5 5 0 2-2 4-5 4s-5-2-5-4c0-3 2-5 5-5z" id="prefix__path33" fill="#fefefe"/><path class="prefix__fil1" d="M463 472c3 0 5 2 5 5 0 2-2 4-5 4s-5-2-5-4c0-3 2-5 5-5z" id="prefix__path35" fill="#fefefe"/><path class="prefix__fil6" id="prefix__polygon37" fill="#006498" d="M305 212h-21v98h21z"/><path d="M477 479v2c0 5-3 8-8 8H231c-5 0-8-3-8-8v-2c0 4 3 8 8 8h238c5 0 8-4 8-8z" id="prefix__path39" fill="#0ea5eb"/><path d="M350 70c155 0 280 125 280 280S505 630 350 630 70 505 70 350 195 70 350 70zm0 46c129 0 234 105 234 234S479 584 350 584 116 479 116 350s105-234 234-234z" id="prefix__path41" fill="#2979ff"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -1,12 +1,6 @@
package cmd package cmd
import (
"log"
)
// Execute executes the commands. // Execute executes the commands.
func Execute() { func Execute() error {
if err := rootCmd.Execute(); err != nil { return rootCmd.Execute()
log.Fatal(err)
}
} }

61
cmd/cmd_test.go Normal file
View file

@ -0,0 +1,61 @@
package cmd
import (
"testing"
"github.com/samber/lo"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/settings"
)
// TestEnvCollisions ensures that there are no collisions in the produced environment
// variable names for all commands and their flags.
func TestEnvCollisions(t *testing.T) {
testEnvCollisions(t, rootCmd)
}
func testEnvCollisions(t *testing.T, cmd *cobra.Command) {
for _, cmd := range cmd.Commands() {
testEnvCollisions(t, cmd)
}
replacements := generateEnvKeyReplacements(cmd)
envVariables := []string{}
for i := range replacements {
if i%2 != 0 {
envVariables = append(envVariables, replacements[i])
}
}
duplicates := lo.FindDuplicates(envVariables)
if len(duplicates) > 0 {
t.Errorf("Found duplicate environment variable keys for command %q: %v", cmd.Name(), duplicates)
}
}
// TestGetSettingsFollowExternalSymlinks ensures that the followExternalSymlinks
// flag is persisted to the server config when set via "config set".
func TestGetSettingsFollowExternalSymlinks(t *testing.T) {
flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
addConfigFlags(flags)
if err := flags.Parse([]string{"--followExternalSymlinks"}); err != nil {
t.Fatal(err)
}
set := &settings.Settings{AuthMethod: auth.MethodJSONAuth}
ser := &settings.Server{}
if _, err := getSettings(flags, set, ser, &auth.JSONAuth{}, false); err != nil {
t.Fatal(err)
}
if !ser.FollowExternalSymlinks {
t.Error("expected FollowExternalSymlinks to be persisted as true")
}
}

View file

@ -14,14 +14,19 @@ var cmdsAddCmd = &cobra.Command{
Use: "add <event> <command>", Use: "add <event> <command>",
Short: "Add a command to run on a specific event", Short: "Add a command to run on a specific event",
Long: `Add a command to run on a specific event.`, Long: `Add a command to run on a specific event.`,
Args: cobra.MinimumNArgs(2), //nolint:mnd Args: cobra.MinimumNArgs(2),
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
s, err := d.store.Settings.Get() s, err := st.Settings.Get()
checkErr(err) if err != nil {
return err
}
command := strings.Join(args[1:], " ") command := strings.Join(args[1:], " ")
s.Commands[args[0]] = append(s.Commands[args[0]], command) s.Commands[args[0]] = append(s.Commands[args[0]], command)
err = d.store.Settings.Save(s) err = st.Settings.Save(s)
checkErr(err) if err != nil {
return err
}
printEvents(s.Commands) printEvents(s.Commands)
}, pythonConfig{}), return nil
}, storeOptions{}),
} }

View file

@ -14,10 +14,16 @@ var cmdsLsCmd = &cobra.Command{
Short: "List all commands for each event", Short: "List all commands for each event",
Long: `List all commands for each event.`, Long: `List all commands for each event.`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error {
s, err := d.store.Settings.Get() s, err := st.Settings.Get()
checkErr(err) if err != nil {
evt := mustGetString(cmd.Flags(), "event") return err
}
evt, err := cmd.Flags().GetString("event")
if err != nil {
return err
}
if evt == "" { if evt == "" {
printEvents(s.Commands) printEvents(s.Commands)
@ -27,5 +33,7 @@ var cmdsLsCmd = &cobra.Command{
show["after_"+evt] = s.Commands["after_"+evt] show["after_"+evt] = s.Commands["after_"+evt]
printEvents(show) printEvents(show)
} }
}, pythonConfig{}),
return nil
}, storeOptions{}),
} }

View file

@ -23,7 +23,7 @@ You can also specify an optional parameter (index_end) so
you can remove all commands from 'index' to 'index_end', you can remove all commands from 'index' to 'index_end',
including 'index_end'.`, including 'index_end'.`,
Args: func(cmd *cobra.Command, args []string) error { Args: func(cmd *cobra.Command, args []string) error {
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil { //nolint:mnd if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil {
return err return err
} }
@ -35,22 +35,31 @@ including 'index_end'.`,
return nil return nil
}, },
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
s, err := d.store.Settings.Get() s, err := st.Settings.Get()
checkErr(err) if err != nil {
return err
}
evt := args[0] evt := args[0]
i, err := strconv.Atoi(args[1]) i, err := strconv.Atoi(args[1])
checkErr(err) if err != nil {
return err
}
f := i f := i
if len(args) == 3 { //nolint:mnd if len(args) == 3 {
f, err = strconv.Atoi(args[2]) f, err = strconv.Atoi(args[2])
checkErr(err) if err != nil {
return err
}
} }
s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][f+1:]...) s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][f+1:]...)
err = d.store.Settings.Save(s) err = st.Settings.Save(s)
checkErr(err) if err != nil {
return err
}
printEvents(s.Commands) printEvents(s.Commands)
}, pythonConfig{}), return nil
}, storeOptions{}),
} }

View file

@ -2,7 +2,7 @@ package cmd
import ( import (
"encoding/json" "encoding/json"
nerrors "errors" "errors"
"fmt" "fmt"
"os" "os"
"strings" "strings"
@ -12,7 +12,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/filebrowser/filebrowser/v2/auth" "github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/errors" fberrors "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
) )
@ -30,24 +30,44 @@ var configCmd = &cobra.Command{
func addConfigFlags(flags *pflag.FlagSet) { func addConfigFlags(flags *pflag.FlagSet) {
addServerFlags(flags) addServerFlags(flags)
addUserFlags(flags) addUserFlags(flags)
flags.BoolP("signup", "s", false, "allow users to signup") flags.BoolP("signup", "s", false, "allow users to signup")
flags.Bool("hideLoginButton", false, "hide login button from public pages")
flags.Bool("createUserDir", false, "generate user's home directory automatically")
flags.Uint("minimumPasswordLength", settings.DefaultMinimumPasswordLength, "minimum password length for new users")
flags.String("shell", "", "shell command to which other commands should be appended") flags.String("shell", "", "shell command to which other commands should be appended")
// NB: these are string so they can be presented as octal in the help text
// as that's the conventional representation for modes in Unix.
flags.String("fileMode", fmt.Sprintf("%O", settings.DefaultFileMode), "mode bits that new files are created with")
flags.String("dirMode", fmt.Sprintf("%O", settings.DefaultDirMode), "mode bits that new directories are created with")
flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type") flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
flags.String("auth.header", "", "HTTP header for auth.method=proxy") flags.String("auth.header", "", "HTTP header for auth.method=proxy")
flags.String("auth.command", "", "command for auth.method=hook")
flags.String("auth.logoutPage", "", "url of custom logout page")
flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China") flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
flags.String("recaptcha.key", "", "ReCaptcha site key") flags.String("recaptcha.key", "", "ReCaptcha site key")
flags.String("recaptcha.secret", "", "ReCaptcha secret") flags.String("recaptcha.secret", "", "ReCaptcha secret")
flags.String("branding.name", "", "replace 'File Browser' by this name") flags.String("branding.name", "", "replace 'File Browser' by this name")
flags.String("branding.theme", "", "set the theme")
flags.String("branding.color", "", "set the theme color")
flags.String("branding.files", "", "path to directory with images and custom styles") flags.String("branding.files", "", "path to directory with images and custom styles")
flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links") flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph")
flags.Uint64("tus.chunkSize", settings.DefaultTusChunkSize, "the tus chunk size")
flags.Uint16("tus.retryCount", settings.DefaultTusRetryCount, "the tus retry count")
} }
//nolint:gocyclo func getAuthMethod(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, map[string]interface{}, error) {
func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, auth.Auther) { methodStr, err := flags.GetString("auth.method")
method := settings.AuthMethod(mustGetString(flags, "auth.method")) if err != nil {
return "", nil, err
}
method := settings.AuthMethod(methodStr)
var defaultAuther map[string]interface{} var defaultAuther map[string]interface{}
if len(defaults) > 0 { if len(defaults) > 0 {
@ -58,79 +78,143 @@ func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.
method = def.AuthMethod method = def.AuthMethod
case auth.Auther: case auth.Auther:
ms, err := json.Marshal(def) ms, err := json.Marshal(def)
checkErr(err) if err != nil {
return "", nil, err
}
err = json.Unmarshal(ms, &defaultAuther) err = json.Unmarshal(ms, &defaultAuther)
checkErr(err) if err != nil {
return "", nil, err
}
} }
} }
} }
} }
var auther auth.Auther return method, defaultAuther, nil
if method == auth.MethodProxyAuth {
header := mustGetString(flags, "auth.header")
if header == "" {
header = defaultAuther["header"].(string)
}
if header == "" {
checkErr(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
}
auther = &auth.ProxyAuth{Header: header}
}
if method == auth.MethodNoAuth {
auther = &auth.NoAuth{}
}
if method == auth.MethodJSONAuth {
jsonAuth := &auth.JSONAuth{}
host := mustGetString(flags, "recaptcha.host")
key := mustGetString(flags, "recaptcha.key")
secret := mustGetString(flags, "recaptcha.secret")
if key == "" {
if kmap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
key = kmap["key"].(string)
}
}
if secret == "" {
if smap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
secret = smap["secret"].(string)
}
}
if key != "" && secret != "" {
jsonAuth.ReCaptcha = &auth.ReCaptcha{
Host: host,
Key: key,
Secret: secret,
}
}
auther = jsonAuth
}
if auther == nil {
panic(errors.ErrInvalidAuthMethod)
}
return method, auther
} }
func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) { func getProxyAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) {
header, err := flags.GetString("auth.header")
if err != nil {
return nil, err
}
if header == "" && defaultAuther != nil {
header = defaultAuther["header"].(string)
}
if header == "" {
return nil, errors.New("you must set the flag 'auth.header' for method 'proxy'")
}
return &auth.ProxyAuth{Header: header}, nil
}
func getNoAuth() auth.Auther {
return &auth.NoAuth{}
}
func getJSONAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) {
jsonAuth := &auth.JSONAuth{}
host, err := flags.GetString("recaptcha.host")
if err != nil {
return nil, err
}
key, err := flags.GetString("recaptcha.key")
if err != nil {
return nil, err
}
secret, err := flags.GetString("recaptcha.secret")
if err != nil {
return nil, err
}
if key == "" {
if kmap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
key = kmap["key"].(string)
}
}
if secret == "" {
if smap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
secret = smap["secret"].(string)
}
}
if key != "" && secret != "" {
jsonAuth.ReCaptcha = &auth.ReCaptcha{
Host: host,
Key: key,
Secret: secret,
}
}
return jsonAuth, nil
}
func getHookAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) {
command, err := flags.GetString("auth.command")
if err != nil {
return nil, err
}
if command == "" {
command = defaultAuther["command"].(string)
}
if command == "" {
return nil, errors.New("you must set the flag 'auth.command' for method 'hook'")
}
return &auth.HookAuth{Command: command}, nil
}
func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, auth.Auther, error) {
method, defaultAuther, err := getAuthMethod(flags, defaults...)
if err != nil {
return "", nil, err
}
var auther auth.Auther
switch method {
case auth.MethodProxyAuth:
auther, err = getProxyAuth(flags, defaultAuther)
case auth.MethodNoAuth:
auther = getNoAuth()
case auth.MethodJSONAuth:
auther, err = getJSONAuth(flags, defaultAuther)
case auth.MethodHookAuth:
auther, err = getHookAuth(flags, defaultAuther)
default:
return "", nil, fberrors.ErrInvalidAuthMethod
}
if err != nil {
return "", nil, err
}
return method, auther, nil
}
func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) error {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup) fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
fmt.Fprintf(w, "Hide Login Button:\t%t\n", set.HideLoginButton)
fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir) fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
fmt.Fprintf(w, "Auth method:\t%s\n", set.AuthMethod) fmt.Fprintf(w, "Logout Page:\t%s\n", set.LogoutPage)
fmt.Fprintf(w, "Minimum Password Length:\t%d\n", set.MinimumPasswordLength)
fmt.Fprintf(w, "Auth Method:\t%s\n", set.AuthMethod)
fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " ")) fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
fmt.Fprintln(w, "\nBranding:") fmt.Fprintln(w, "\nBranding:")
fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name) fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name)
fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files) fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files)
fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal) fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal)
fmt.Fprintf(w, "\tDisable used disk percentage graph:\t%t\n", set.Branding.DisableUsedPercentage)
fmt.Fprintf(w, "\tColor:\t%s\n", set.Branding.Color)
fmt.Fprintf(w, "\tTheme:\t%s\n", set.Branding.Theme)
fmt.Fprintln(w, "\nServer:") fmt.Fprintln(w, "\nServer:")
fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log) fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port) fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)
@ -140,14 +224,34 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address) fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert) fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey) fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
fmt.Fprintf(w, "\tToken Expiration Time:\t%s\n", ser.TokenExpirationTime)
fmt.Fprintf(w, "\tExec Enabled:\t%t\n", ser.EnableExec)
fmt.Fprintf(w, "\tThumbnails Enabled:\t%t\n", ser.EnableThumbnails)
fmt.Fprintf(w, "\tResize Preview:\t%t\n", ser.ResizePreview)
fmt.Fprintf(w, "\tType Detection by Header:\t%t\n", ser.TypeDetectionByHeader)
fmt.Fprintf(w, "\tFollow External Symlinks:\t%t\n", ser.FollowExternalSymlinks)
fmt.Fprintln(w, "\nTUS:")
fmt.Fprintf(w, "\tChunk size:\t%d\n", set.Tus.ChunkSize)
fmt.Fprintf(w, "\tRetry count:\t%d\n", set.Tus.RetryCount)
fmt.Fprintln(w, "\nDefaults:") fmt.Fprintln(w, "\nDefaults:")
fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope) fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
fmt.Fprintf(w, "\tDateFormat:\t%t\n", set.Defaults.DateFormat)
fmt.Fprintf(w, "\tHideDotfiles:\t%t\n", set.Defaults.HideDotfiles)
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale) fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode) fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
fmt.Fprintf(w, "\tRedirect after Copy/Move:\t%t\n", set.Defaults.RedirectAfterCopyMove)
fmt.Fprintf(w, "\tFile Creation Mode:\t%O\n", set.FileMode)
fmt.Fprintf(w, "\tDirectory Creation Mode:\t%O\n", set.DirMode)
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " ")) fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
fmt.Fprintf(w, "\tAce editor syntax highlighting theme:\t%s\n", set.Defaults.AceEditorTheme)
fmt.Fprintf(w, "\tSorting:\n") fmt.Fprintf(w, "\tSorting:\n")
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By) fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc) fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)
fmt.Fprintf(w, "\tPermissions:\n") fmt.Fprintf(w, "\tPermissions:\n")
fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin) fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin)
fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute) fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute)
@ -157,9 +261,135 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete) fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete)
fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share) fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share)
fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download) fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download)
w.Flush() w.Flush()
b, err := json.MarshalIndent(auther, "", " ") b, err := json.MarshalIndent(auther, "", " ")
checkErr(err) if err != nil {
return err
}
fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b)) fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
return nil
}
func getSettings(flags *pflag.FlagSet, set *settings.Settings, ser *settings.Server, auther auth.Auther, all bool) (auth.Auther, error) {
errs := []error{}
hasAuth := false
visit := func(flag *pflag.Flag) {
var err error
switch flag.Name {
// Server flags from [addServerFlags]
case "address":
ser.Address, err = flags.GetString(flag.Name)
case "log":
ser.Log, err = flags.GetString(flag.Name)
case "port":
ser.Port, err = flags.GetString(flag.Name)
case "cert":
ser.TLSCert, err = flags.GetString(flag.Name)
case "key":
ser.TLSKey, err = flags.GetString(flag.Name)
case "root":
ser.Root, err = flags.GetString(flag.Name)
case "socket":
ser.Socket, err = flags.GetString(flag.Name)
case "baseURL":
ser.BaseURL, err = flags.GetString(flag.Name)
case "tokenExpirationTime":
ser.TokenExpirationTime, err = flags.GetString(flag.Name)
case "disableThumbnails":
ser.EnableThumbnails, err = flags.GetBool(flag.Name)
ser.EnableThumbnails = !ser.EnableThumbnails
case "disablePreviewResize":
ser.ResizePreview, err = flags.GetBool(flag.Name)
ser.ResizePreview = !ser.ResizePreview
case "disableExec":
ser.EnableExec, err = flags.GetBool(flag.Name)
ser.EnableExec = !ser.EnableExec
case "disableTypeDetectionByHeader":
ser.TypeDetectionByHeader, err = flags.GetBool(flag.Name)
ser.TypeDetectionByHeader = !ser.TypeDetectionByHeader
case "disableImageResolutionCalc":
ser.ImageResolutionCal, err = flags.GetBool(flag.Name)
ser.ImageResolutionCal = !ser.ImageResolutionCal
case "followExternalSymlinks":
ser.FollowExternalSymlinks, err = flags.GetBool(flag.Name)
// Settings flags from [addConfigFlags]
case "signup":
set.Signup, err = flags.GetBool(flag.Name)
case "hideLoginButton":
set.HideLoginButton, err = flags.GetBool(flag.Name)
case "createUserDir":
set.CreateUserDir, err = flags.GetBool(flag.Name)
case "minimumPasswordLength":
set.MinimumPasswordLength, err = flags.GetUint(flag.Name)
case "shell":
var shell string
shell, err = flags.GetString(flag.Name)
if err == nil {
set.Shell = convertCmdStrToCmdArray(shell)
}
case "fileMode":
set.FileMode, err = getAndParseFileMode(flags, flag.Name)
case "dirMode":
set.DirMode, err = getAndParseFileMode(flags, flag.Name)
case "auth.method":
hasAuth = true
case "auth.logoutPage":
set.LogoutPage, err = flags.GetString(flag.Name)
case "branding.name":
set.Branding.Name, err = flags.GetString(flag.Name)
case "branding.theme":
set.Branding.Theme, err = flags.GetString(flag.Name)
case "branding.color":
set.Branding.Color, err = flags.GetString(flag.Name)
case "branding.files":
set.Branding.Files, err = flags.GetString(flag.Name)
case "branding.disableExternal":
set.Branding.DisableExternal, err = flags.GetBool(flag.Name)
case "branding.disableUsedPercentage":
set.Branding.DisableUsedPercentage, err = flags.GetBool(flag.Name)
case "tus.chunkSize":
set.Tus.ChunkSize, err = flags.GetUint64(flag.Name)
case "tus.retryCount":
set.Tus.RetryCount, err = flags.GetUint16(flag.Name)
}
if err != nil {
errs = append(errs, err)
}
}
if all {
flags.VisitAll(visit)
} else {
flags.Visit(visit)
}
err := errors.Join(errs...)
if err != nil {
return nil, err
}
err = getUserDefaults(flags, &set.Defaults, all)
if err != nil {
return nil, err
}
if all {
set.AuthMethod, auther, err = getAuthentication(flags)
if err != nil {
return nil, err
}
} else {
set.AuthMethod, auther, err = getAuthentication(flags, hasAuth, set, auther)
if err != nil {
return nil, err
}
}
return auther, nil
} }

View file

@ -13,13 +13,19 @@ var configCatCmd = &cobra.Command{
Short: "Prints the configuration", Short: "Prints the configuration",
Long: `Prints the configuration.`, Long: `Prints the configuration.`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(_ *cobra.Command, _ []string, st *store) error {
set, err := d.store.Settings.Get() set, err := st.Settings.Get()
checkErr(err) if err != nil {
ser, err := d.store.Settings.GetServer() return err
checkErr(err) }
auther, err := d.store.Auth.Get(set.AuthMethod) ser, err := st.Settings.GetServer()
checkErr(err) if err != nil {
printSettings(ser, set, auther) return err
}, pythonConfig{}), }
auther, err := st.Auth.Get(set.AuthMethod)
if err != nil {
return err
}
return printSettings(ser, set, auther)
}, storeOptions{}),
} }

View file

@ -15,15 +15,21 @@ var configExportCmd = &cobra.Command{
json or yaml file. This exported configuration can be changed, json or yaml file. This exported configuration can be changed,
and imported again with 'config import' command.`, and imported again with 'config import' command.`,
Args: jsonYamlArg, Args: jsonYamlArg,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
settings, err := d.store.Settings.Get() settings, err := st.Settings.Get()
checkErr(err) if err != nil {
return err
}
server, err := d.store.Settings.GetServer() server, err := st.Settings.GetServer()
checkErr(err) if err != nil {
return err
}
auther, err := d.store.Auth.Get(settings.AuthMethod) auther, err := st.Auth.Get(settings.AuthMethod)
checkErr(err) if err != nil {
return err
}
data := &settingsFile{ data := &settingsFile{
Settings: settings, Settings: settings,
@ -32,6 +38,9 @@ and imported again with 'config import' command.`,
} }
err = marshal(args[0], data) err = marshal(args[0], data)
checkErr(err) if err != nil {
}, pythonConfig{}), return err
}
return nil
}, storeOptions{}),
} }

View file

@ -3,7 +3,6 @@ package cmd
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"path/filepath"
"reflect" "reflect"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -34,59 +33,88 @@ database.
The path must be for a json or yaml file.`, The path must be for a json or yaml file.`,
Args: jsonYamlArg, Args: jsonYamlArg,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
var key []byte var key []byte
if d.hadDB { var err error
settings, err := d.store.Settings.Get() if st.databaseExisted {
checkErr(err) settings, settingErr := st.Settings.Get()
if settingErr != nil {
return settingErr
}
key = settings.Key key = settings.Key
} else { } else {
key = generateKey() key = generateKey()
} }
file := settingsFile{} file := settingsFile{}
err := unmarshal(args[0], &file) err = unmarshal(args[0], &file)
checkErr(err) if err != nil {
return err
}
if file.Settings == nil || file.Server == nil {
return errors.New("invalid configuration file: 'settings' or 'server' fields are missing. Please ensure you are importing a file generated by the 'config export' command")
}
file.Settings.Key = key file.Settings.Key = key
err = d.store.Settings.Save(file.Settings) err = st.Settings.Save(file.Settings)
checkErr(err) if err != nil {
return err
err = d.store.Settings.SaveServer(file.Server)
checkErr(err)
var rawAuther interface{}
if filepath.Ext(args[0]) != ".json" { //nolint:goconst
rawAuther = cleanUpInterfaceMap(file.Auther.(map[interface{}]interface{}))
} else {
rawAuther = file.Auther
} }
err = st.Settings.SaveServer(file.Server)
if err != nil {
return err
}
var rawAuther = file.Auther
var auther auth.Auther var auther auth.Auther
var autherErr error
switch file.Settings.AuthMethod { switch file.Settings.AuthMethod {
case auth.MethodJSONAuth: case auth.MethodJSONAuth:
auther = getAuther(auth.JSONAuth{}, rawAuther).(*auth.JSONAuth) var a interface{}
a, autherErr = getAuther(auth.JSONAuth{}, rawAuther)
auther = a.(*auth.JSONAuth)
case auth.MethodNoAuth: case auth.MethodNoAuth:
auther = getAuther(auth.NoAuth{}, rawAuther).(*auth.NoAuth) var a interface{}
a, autherErr = getAuther(auth.NoAuth{}, rawAuther)
auther = a.(*auth.NoAuth)
case auth.MethodProxyAuth: case auth.MethodProxyAuth:
auther = getAuther(auth.ProxyAuth{}, rawAuther).(*auth.ProxyAuth) var a interface{}
a, autherErr = getAuther(auth.ProxyAuth{}, rawAuther)
auther = a.(*auth.ProxyAuth)
case auth.MethodHookAuth:
var a interface{}
a, autherErr = getAuther(&auth.HookAuth{}, rawAuther)
auther = a.(*auth.HookAuth)
default: default:
checkErr(errors.New("invalid auth method")) return errors.New("invalid auth method")
} }
err = d.store.Auth.Save(auther) if autherErr != nil {
checkErr(err) return autherErr
}
printSettings(file.Server, file.Settings, auther) err = st.Auth.Save(auther)
}, pythonConfig{allowNoDB: true}), if err != nil {
return err
}
return printSettings(file.Server, file.Settings, auther)
}, storeOptions{allowsNoDatabase: true}),
} }
func getAuther(sample auth.Auther, data interface{}) interface{} { func getAuther(sample auth.Auther, data interface{}) (interface{}, error) {
authType := reflect.TypeOf(sample) authType := reflect.TypeOf(sample)
auther := reflect.New(authType).Interface() auther := reflect.New(authType).Interface()
bytes, err := json.Marshal(data) bytes, err := json.Marshal(data)
checkErr(err) if err != nil {
return nil, err
}
err = json.Unmarshal(bytes, &auther) err = json.Unmarshal(bytes, &auther)
checkErr(err) if err != nil {
return auther return nil, err
}
return auther, nil
} }

View file

@ -2,7 +2,6 @@ package cmd
import ( import (
"fmt" "fmt"
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -23,48 +22,40 @@ this options can be changed in the future with the command
to the defaults when creating new users and you don't to the defaults when creating new users and you don't
override the options.`, override the options.`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error {
defaults := settings.UserDefaults{}
flags := cmd.Flags() flags := cmd.Flags()
getUserDefaults(flags, &defaults, true)
authMethod, auther := getAuthentication(flags)
s := &settings.Settings{ // Initialize config
Key: generateKey(), s := &settings.Settings{Key: generateKey()}
Signup: mustGetBool(flags, "signup"), ser := &settings.Server{}
Shell: strings.Split(strings.TrimSpace(mustGetString(flags, "shell")), " "),
AuthMethod: authMethod, // Fill config with options
Defaults: defaults, auther, err := getSettings(flags, s, ser, nil, true)
Branding: settings.Branding{ if err != nil {
Name: mustGetString(flags, "branding.name"), return err
DisableExternal: mustGetBool(flags, "branding.disableExternal"),
Files: mustGetString(flags, "branding.files"),
},
} }
ser := &settings.Server{ // Save updated config
Address: mustGetString(flags, "address"), err = st.Settings.Save(s)
Socket: mustGetString(flags, "socket"), if err != nil {
Root: mustGetString(flags, "root"), return err
BaseURL: mustGetString(flags, "baseurl"),
TLSKey: mustGetString(flags, "key"),
TLSCert: mustGetString(flags, "cert"),
Port: mustGetString(flags, "port"),
Log: mustGetString(flags, "log"),
} }
err := d.store.Settings.Save(s) err = st.Settings.SaveServer(ser)
checkErr(err) if err != nil {
err = d.store.Settings.SaveServer(ser) return err
checkErr(err) }
err = d.store.Auth.Save(auther)
checkErr(err) err = st.Auth.Save(auther)
if err != nil {
return err
}
fmt.Printf(` fmt.Printf(`
Congratulations! You've set up your database to use with File Browser. Congratulations! You've set up your database to use with File Browser.
Now add your first user via 'filebrowser users new' and then you just Now add your first user via 'filebrowser users add' and then you just
need to call the main command to boot up the server. need to call the main command to boot up the server.
`) `)
printSettings(ser, s, auther) return printSettings(ser, s, auther)
}, pythonConfig{noDB: true}), }, storeOptions{expectsNoDatabase: true}),
} }

View file

@ -1,10 +1,7 @@
package cmd package cmd
import ( import (
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag"
) )
func init() { func init() {
@ -18,63 +15,47 @@ var configSetCmd = &cobra.Command{
Long: `Updates the configuration. Set the flags for the options Long: `Updates the configuration. Set the flags for the options
you want to change. Other options will remain unchanged.`, you want to change. Other options will remain unchanged.`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error {
flags := cmd.Flags() flags := cmd.Flags()
set, err := d.store.Settings.Get()
checkErr(err)
ser, err := d.store.Settings.GetServer() // Read existing config
checkErr(err) set, err := st.Settings.Get()
if err != nil {
return err
}
hasAuth := false ser, err := st.Settings.GetServer()
flags.Visit(func(flag *pflag.Flag) { if err != nil {
switch flag.Name { return err
case "baseurl": }
ser.BaseURL = mustGetString(flags, flag.Name)
case "root":
ser.Root = mustGetString(flags, flag.Name)
case "socket":
ser.Socket = mustGetString(flags, flag.Name)
case "cert":
ser.TLSCert = mustGetString(flags, flag.Name)
case "key":
ser.TLSKey = mustGetString(flags, flag.Name)
case "address":
ser.Address = mustGetString(flags, flag.Name)
case "port":
ser.Port = mustGetString(flags, flag.Name)
case "log":
ser.Log = mustGetString(flags, flag.Name)
case "signup":
set.Signup = mustGetBool(flags, flag.Name)
case "auth.method":
hasAuth = true
case "shell":
set.Shell = strings.Split(strings.TrimSpace(mustGetString(flags, flag.Name)), " ")
case "branding.name":
set.Branding.Name = mustGetString(flags, flag.Name)
case "branding.disableExternal":
set.Branding.DisableExternal = mustGetBool(flags, flag.Name)
case "branding.files":
set.Branding.Files = mustGetString(flags, flag.Name)
}
})
getUserDefaults(flags, &set.Defaults, false) auther, err := st.Auth.Get(set.AuthMethod)
if err != nil {
return err
}
// read the defaults // Get updated config
auther, err := d.store.Auth.Get(set.AuthMethod) auther, err = getSettings(flags, set, ser, auther, false)
checkErr(err) if err != nil {
return err
}
// check if there are new flags for existing auth method // Save updated config
set.AuthMethod, auther = getAuthentication(flags, hasAuth, set, auther) err = st.Auth.Save(auther)
if err != nil {
return err
}
err = d.store.Auth.Save(auther) err = st.Settings.Save(set)
checkErr(err) if err != nil {
err = d.store.Settings.Save(set) return err
checkErr(err) }
err = d.store.Settings.SaveServer(ser)
checkErr(err) err = st.Settings.SaveServer(ser)
printSettings(ser, set, auther) if err != nil {
}, pythonConfig{}), return err
}
return printSettings(ser, set, auther)
}, storeOptions{}),
} }

View file

@ -3,137 +3,80 @@ package cmd
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"os" "os"
"path/filepath" "path"
"sort" "regexp"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/cobra/doc"
) )
func init() { func init() {
rootCmd.AddCommand(docsCmd) rootCmd.AddCommand(docsCmd)
docsCmd.Flags().StringP("path", "p", "./docs", "path to save the docs") docsCmd.Flags().String("out", "docs/cli", "directory to write the docs to")
}
func printToc(names []string) {
for i, name := range names {
name = strings.TrimSuffix(name, filepath.Ext(name))
name = strings.Replace(name, "-", " ", -1)
names[i] = name
}
sort.Strings(names)
toc := ""
for _, name := range names {
toc += "* [" + name + "](cli/" + strings.Replace(name, " ", "-", -1) + ".md)\n"
}
fmt.Println(toc)
} }
var docsCmd = &cobra.Command{ var docsCmd = &cobra.Command{
Use: "docs", Use: "docs",
Hidden: true, Hidden: true,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { RunE: func(cmd *cobra.Command, _ []string) error {
dir := mustGetString(cmd.Flags(), "path") outputDir, err := cmd.Flags().GetString("out")
generateDocs(rootCmd, dir) if err != nil {
names := []string{} return err
}
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { tempDir, err := os.MkdirTemp(os.TempDir(), "filebrowser-docs-")
if err != nil || info.IsDir() { if err != nil {
return err
}
defer os.RemoveAll(tempDir)
rootCmd.Root().DisableAutoGenTag = true
err = doc.GenMarkdownTreeCustom(cmd.Root(), tempDir, func(_ string) string {
return ""
}, func(s string) string {
return s
})
if err != nil {
return err
}
entries, err := os.ReadDir(tempDir)
if err != nil {
return err
}
headerRegex := regexp.MustCompile(`(?m)^(##)(.*)$`)
linkRegex := regexp.MustCompile(`\(filebrowser(.*)\.md\)`)
fmt.Println("Generated Documents:")
for _, entry := range entries {
srcPath := path.Join(tempDir, entry.Name())
dstPath := path.Join(outputDir, strings.ReplaceAll(entry.Name(), "_", "-"))
data, err := os.ReadFile(srcPath)
if err != nil {
return err return err
} }
if !strings.HasPrefix(info.Name(), "filebrowser") { data = headerRegex.ReplaceAll(data, []byte("#$2"))
return nil data = linkRegex.ReplaceAllFunc(data, func(b []byte) []byte {
return bytes.ReplaceAll(b, []byte("_"), []byte("-"))
})
data = bytes.ReplaceAll(data, []byte("## SEE ALSO"), []byte("## See Also"))
err = os.WriteFile(dstPath, data, 0666)
if err != nil {
return err
} }
names = append(names, info.Name()) fmt.Println("- " + dstPath)
return nil
})
checkErr(err)
printToc(names)
},
}
func generateDocs(cmd *cobra.Command, dir string) {
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
continue
} }
generateDocs(c, dir) return nil
} },
basename := strings.Replace(cmd.CommandPath(), " ", "-", -1) + ".md"
filename := filepath.Join(dir, basename)
f, err := os.Create(filename)
checkErr(err)
defer f.Close()
generateMarkdown(cmd, f)
}
func generateMarkdown(cmd *cobra.Command, w io.Writer) {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()
buf := new(bytes.Buffer)
name := cmd.CommandPath()
short := cmd.Short
long := cmd.Long
if long == "" {
long = short
}
buf.WriteString("---\ndescription: " + short + "\n---\n\n")
buf.WriteString("# " + name + "\n\n")
buf.WriteString("## Synopsis\n\n")
buf.WriteString(long + "\n\n")
if cmd.Runnable() {
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine()))
}
if len(cmd.Example) > 0 {
buf.WriteString("## Examples\n\n")
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example))
}
printOptions(buf, cmd)
_, err := buf.WriteTo(w)
checkErr(err)
}
func generateFlagsTable(fs *pflag.FlagSet, buf io.StringWriter) {
_, _ = buf.WriteString("| Name | Shorthand | Usage |\n")
_, _ = buf.WriteString("|------|-----------|-------|\n")
fs.VisitAll(func(f *pflag.Flag) {
_, _ = buf.WriteString("|" + f.Name + "|" + f.Shorthand + "|" + f.Usage + "|\n")
})
}
func printOptions(buf *bytes.Buffer, cmd *cobra.Command) {
flags := cmd.NonInheritedFlags()
flags.SetOutput(buf)
if flags.HasAvailableFlags() {
buf.WriteString("## Options\n\n")
generateFlagsTable(flags, buf)
buf.WriteString("\n")
}
parentFlags := cmd.InheritedFlags()
parentFlags.SetOutput(buf)
if parentFlags.HasAvailableFlags() {
buf.WriteString("### Inherited\n\n")
generateFlagsTable(parentFlags, buf)
buf.WriteString("\n")
}
} }

View file

@ -17,9 +17,12 @@ var hashCmd = &cobra.Command{
Short: "Hashes a password", Short: "Hashes a password",
Long: `Hashes a password using bcrypt algorithm.`, Long: `Hashes a password using bcrypt algorithm.`,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) { RunE: func(_ *cobra.Command, args []string) error {
pwd, err := users.HashPwd(args[0]) pwd, err := users.HashPwd(args[0])
checkErr(err) if err != nil {
return err
}
fmt.Println(pwd) fmt.Println(pwd)
return nil
}, },
} }

View file

@ -1,9 +1,12 @@
package cmd package cmd
import ( import (
"context"
"crypto/tls" "crypto/tls"
"errors" "errors"
"io/ioutil" "fmt"
"io"
"io/fs"
"log" "log"
"net" "net"
"net/http" "net/http"
@ -12,41 +15,88 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"syscall" "syscall"
"time"
homedir "github.com/mitchellh/go-homedir" "github.com/spf13/afero"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
v "github.com/spf13/viper" "github.com/spf13/viper"
lumberjack "gopkg.in/natefinch/lumberjack.v2" lumberjack "gopkg.in/natefinch/lumberjack.v2"
"github.com/filebrowser/filebrowser/v2/auth" "github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/diskcache"
"github.com/filebrowser/filebrowser/v2/frontend"
fbhttp "github.com/filebrowser/filebrowser/v2/http" fbhttp "github.com/filebrowser/filebrowser/v2/http"
"github.com/filebrowser/filebrowser/v2/img"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
) )
var ( var (
cfgFile string flagNamesMigrations = map[string]string{
"file-mode": "fileMode",
"dir-mode": "dirMode",
"hide-login-button": "hideLoginButton",
"create-user-dir": "createUserDir",
"minimum-password-length": "minimumPasswordLength",
"socket-perm": "socketPerm",
"disable-thumbnails": "disableThumbnails",
"disable-preview-resize": "disablePreviewResize",
"disable-exec": "disableExec",
"disable-type-detection-by-header": "disableTypeDetectionByHeader",
"img-processors": "imageProcessors",
"cache-dir": "cacheDir",
"redis-cache-url": "redisCacheUrl",
"token-expiration-time": "tokenExpirationTime",
"baseurl": "baseURL",
}
warnedFlags = map[string]bool{}
) )
// TODO(remove): remove after July 2026.
func migrateFlagNames(_ *pflag.FlagSet, name string) pflag.NormalizedName {
if newName, ok := flagNamesMigrations[name]; ok {
if !warnedFlags[name] {
warnedFlags[name] = true
log.Printf("DEPRECATION NOTICE: Flag --%s has been deprecated, use --%s instead\n", name, newName)
}
name = newName
}
return pflag.NormalizedName(name)
}
func init() { func init() {
cobra.OnInitialize(initConfig) rootCmd.SilenceUsage = true
rootCmd.SetGlobalNormalizationFunc(migrateFlagNames)
cobra.MousetrapHelpText = ""
rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n") rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n")
flags := rootCmd.Flags() // Flags available across the whole program
persistent := rootCmd.PersistentFlags() persistent := rootCmd.PersistentFlags()
persistent.StringP("config", "c", "", "config file path")
persistent.StringVarP(&cfgFile, "config", "c", "", "config file path")
persistent.StringP("database", "d", "./filebrowser.db", "database path") persistent.StringP("database", "d", "./filebrowser.db", "database path")
flags.Bool("noauth", false, "use the noauth auther when using quick setup")
flags.String("username", "admin", "username for the first user when using quick config")
flags.String("password", "", "hashed password for the first user when using quick config (default \"admin\")")
// Runtime flags for the root command
flags := rootCmd.Flags()
flags.Bool("noauth", false, "use the noauth auther when using quick setup")
flags.String("username", "admin", "username for the first user when using quick setup")
flags.String("password", "", "hashed password for the first user when using quick setup")
flags.Uint32("socketPerm", 0666, "unix socket file permissions")
flags.String("cacheDir", "", "file cache directory (disabled if empty)")
flags.String("redisCacheUrl", "", "redis cache URL (for multi-instance deployments), e.g. redis://user:pass@host:port")
flags.Int("imageProcessors", 4, "image processors count")
addServerFlags(flags) addServerFlags(flags)
} }
// addServerFlags adds server related flags to the given FlagSet. These flags are available
// in both the root command, config set and config init commands.
func addServerFlags(flags *pflag.FlagSet) { func addServerFlags(flags *pflag.FlagSet) {
flags.StringP("address", "a", "127.0.0.1", "address to listen on") flags.StringP("address", "a", "127.0.0.1", "address to listen on")
flags.StringP("log", "l", "stdout", "log output") flags.StringP("log", "l", "stdout", "log output")
@ -55,14 +105,21 @@ func addServerFlags(flags *pflag.FlagSet) {
flags.StringP("key", "k", "", "tls key") flags.StringP("key", "k", "", "tls key")
flags.StringP("root", "r", ".", "root to prepend to relative paths") flags.StringP("root", "r", ".", "root to prepend to relative paths")
flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)") flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)")
flags.StringP("baseurl", "b", "", "base url") flags.StringP("baseURL", "b", "", "base url")
flags.String("tokenExpirationTime", "2h", "user session timeout")
flags.Bool("disableThumbnails", false, "disable image thumbnails")
flags.Bool("disablePreviewResize", false, "disable resize of image previews")
flags.Bool("disableExec", true, "disables Command Runner feature")
flags.Bool("disableTypeDetectionByHeader", false, "disables type detection by reading file headers")
flags.Bool("disableImageResolutionCalc", false, "disables image resolution calculation by reading image files")
flags.Bool("followExternalSymlinks", false, "follow symlinks whose target is outside the user scope (unsafe)")
} }
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "filebrowser", Use: "filebrowser",
Short: "A stylish web-based file browser", Short: "A stylish web-based file browser",
Long: `File Browser CLI lets you create the database to use with File Browser, Long: `File Browser CLI lets you create the database to use with File Browser,
manage your users and all the configurations without acessing the manage your users and all the configurations without accessing the
web interface. web interface.
If you've never run File Browser, you'll need to have a database for If you've never run File Browser, you'll need to have a database for
@ -70,44 +127,80 @@ it. Don't worry: you don't need to setup a separate database server.
We're using Bolt DB which is a single file database and all managed We're using Bolt DB which is a single file database and all managed
by ourselves. by ourselves.
For this specific command, all the flags you have available (except For this command, all flags are available as environmental variables,
"config" for the configuration file), can be given either through except for "--config", which specifies the configuration file to use.
environment variables or configuration files. The environment variables are prefixed by "FB_" followed by the flag name in
UPPER_SNAKE_CASE. For example, the flag "--disablePreviewResize" is available
as FB_DISABLE_PREVIEW_RESIZE.
If you don't set "config", it will look for a configuration file called If "--config" is not specified, File Browser will look for a configuration
.filebrowser.{json, toml, yaml, yml} in the following directories: file named .filebrowser.{json, toml, yaml, yml} in the following directories:
- ./ - ./
- $HOME/ - $HOME/
- /etc/filebrowser/ - /etc/filebrowser/
**Note:** Only the options listed below can be set via the config file or
environment variables. Other configuration options live exclusively in the
database and so they must be set by the "config set" or "config
import" commands.
The precedence of the configuration values are as follows: The precedence of the configuration values are as follows:
- flags - Flags
- environment variables - Environment variables
- configuration file - Configuration file
- database values - Database values
- defaults - Defaults
The environment variables are prefixed by "FB_" followed by the option
name in caps. So to set "database" via an env variable, you should
set FB_DATABASE.
Also, if the database path doesn't exist, File Browser will enter into Also, if the database path doesn't exist, File Browser will enter into
the quick setup mode and a new database will be bootstraped and a new the quick setup mode and a new database will be bootstrapped and a new
user created with the credentials from options "username" and "password".`, user created with the credentials from options "username" and "password".`,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withViperAndStore(func(_ *cobra.Command, _ []string, v *viper.Viper, st *store) error {
log.Println(cfgFile) if !st.databaseExisted {
err := quickSetup(v, st.Storage)
if !d.hadDB { if err != nil {
quickSetup(cmd.Flags(), d) return err
}
} }
server := getRunParams(cmd.Flags(), d.store) // build img service
imgWorkersCount := v.GetInt("imageProcessors")
if imgWorkersCount < 1 {
return errors.New("image resize workers count could not be < 1")
}
imageService := img.New(imgWorkersCount)
var fileCache diskcache.Interface = diskcache.NewNoOp()
cacheDir := v.GetString("cacheDir")
if cacheDir != "" {
if err := os.MkdirAll(cacheDir, 0700); err != nil {
return fmt.Errorf("can't make directory %s: %w", cacheDir, err)
}
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
}
redisCacheURL := v.GetString("redisCacheUrl")
uploadCache, err := fbhttp.NewUploadCache(redisCacheURL)
if err != nil {
return fmt.Errorf("failed to initialize upload cache: %w", err)
}
server, err := getServerSettings(v, st.Storage)
if err != nil {
return err
}
setupLog(server.Log) setupLog(server.Log)
log.Println("NOTICE: File Browser is being wound down.")
log.Println("NOTICE: The project is archived on 2026-09-01, after which there will be no")
log.Println("NOTICE: further releases and no security fixes. Known unfixed issues are at")
log.Println("NOTICE: https://github.com/filebrowser/filebrowser/security/advisories")
root, err := filepath.Abs(server.Root) root, err := filepath.Abs(server.Root)
checkErr(err) if err != nil {
return err
}
server.Root = root server.Root = root
adr := server.Address + ":" + server.Port adr := server.Address + ":" + server.Port
@ -117,87 +210,162 @@ user created with the credentials from options "username" and "password".`,
switch { switch {
case server.Socket != "": case server.Socket != "":
listener, err = net.Listen("unix", server.Socket) listener, err = net.Listen("unix", server.Socket)
checkErr(err) if err != nil {
return err
}
socketPerm := v.GetUint32("socketPerm")
err = os.Chmod(server.Socket, os.FileMode(socketPerm))
if err != nil {
return err
}
case server.TLSKey != "" && server.TLSCert != "": case server.TLSKey != "" && server.TLSCert != "":
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:shadow cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey)
checkErr(err) if err != nil {
listener, err = tls.Listen("tcp", adr, &tls.Config{Certificates: []tls.Certificate{cer}}) //nolint:shadow return err
checkErr(err) }
listener, err = tls.Listen("tcp", adr, &tls.Config{
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{cer}},
)
if err != nil {
return err
}
default: default:
listener, err = net.Listen("tcp", adr) //nolint:shadow listener, err = net.Listen("tcp", adr)
checkErr(err) if err != nil {
return err
}
} }
sigc := make(chan os.Signal, 1) assetsFs, err := fs.Sub(frontend.Assets(), "dist")
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM) if err != nil {
go cleanupHandler(listener, sigc) panic(err)
}
handler, err := fbhttp.NewHandler(d.store, server) handler, err := fbhttp.NewHandler(imageService, fileCache, uploadCache, st.Storage, server, assetsFs)
checkErr(err) if err != nil {
return err
}
defer listener.Close() defer listener.Close()
log.Println("Listening on", listener.Addr().String()) log.Println("Listening on", listener.Addr().String())
if err := http.Serve(listener, handler); err != nil { srv := &http.Server{
log.Fatal(err) Handler: handler,
ReadHeaderTimeout: 60 * time.Second,
} }
}, pythonConfig{allowNoDB: true}),
go func() {
if err := srv.Serve(listener); !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("HTTP server error: %v", err)
}
log.Println("Stopped serving new connections.")
}()
sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
os.Interrupt,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT,
)
sig := <-sigc
log.Println("Got signal:", sig)
shutdownCtx, shutdownRelease := context.WithTimeout(context.Background(), 10*time.Second)
defer shutdownRelease()
if err := srv.Shutdown(shutdownCtx); err != nil {
log.Fatalf("HTTP shutdown error: %v", err)
}
log.Println("Graceful shutdown complete.")
return nil
}, storeOptions{allowsNoDatabase: true}),
} }
func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfacer func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, error) {
sig := <-c
log.Printf("Caught signal %s: shutting down.", sig)
listener.Close()
os.Exit(0)
}
//nolint:gocyclo
func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
server, err := st.Settings.GetServer() server, err := st.Settings.GetServer()
checkErr(err) if err != nil {
return nil, err
if val, set := getParamB(flags, "root"); set {
server.Root = val
}
if val, set := getParamB(flags, "baseurl"); set {
server.BaseURL = val
}
if val, set := getParamB(flags, "log"); set {
server.Log = val
} }
isSocketSet := false isSocketSet := false
isAddrSet := false isAddrSet := false
if val, set := getParamB(flags, "address"); set { if v.IsSet("address") {
server.Address = val server.Address = v.GetString("address")
isAddrSet = isAddrSet || set isAddrSet = true
} }
if val, set := getParamB(flags, "port"); set { if v.IsSet("log") {
server.Port = val server.Log = v.GetString("log")
isAddrSet = isAddrSet || set
} }
if val, set := getParamB(flags, "key"); set { if v.IsSet("port") {
server.TLSKey = val server.Port = v.GetString("port")
isAddrSet = isAddrSet || set isAddrSet = true
} }
if val, set := getParamB(flags, "cert"); set { if v.IsSet("cert") {
server.TLSCert = val server.TLSCert = v.GetString("cert")
isAddrSet = isAddrSet || set isAddrSet = true
} }
if val, set := getParamB(flags, "socket"); set { if v.IsSet("key") {
server.Socket = val server.TLSKey = v.GetString("key")
isSocketSet = isSocketSet || set isAddrSet = true
}
if v.IsSet("root") {
server.Root = v.GetString("root")
}
if v.IsSet("socket") {
server.Socket = v.GetString("socket")
isSocketSet = true
}
if v.IsSet("baseURL") {
server.BaseURL = v.GetString("baseURL")
// TODO(remove): remove after July 2026.
} else if v := os.Getenv("FB_BASEURL"); v != "" {
log.Println("DEPRECATION NOTICE: Environment variable FB_BASEURL has been deprecated, use FB_BASE_URL instead")
server.BaseURL = v
}
if v.IsSet("tokenExpirationTime") {
server.TokenExpirationTime = v.GetString("tokenExpirationTime")
}
if v.IsSet("disableThumbnails") {
server.EnableThumbnails = !v.GetBool("disableThumbnails")
}
if v.IsSet("disablePreviewResize") {
server.ResizePreview = !v.GetBool("disablePreviewResize")
}
if v.IsSet("disableTypeDetectionByHeader") {
server.TypeDetectionByHeader = !v.GetBool("disableTypeDetectionByHeader")
}
if v.IsSet("disableImageResolutionCalc") {
server.ImageResolutionCal = !v.GetBool("disableImageResolutionCalc")
}
if v.IsSet("disableExec") {
server.EnableExec = !v.GetBool("disableExec")
}
if v.IsSet("followExternalSymlinks") {
server.FollowExternalSymlinks = v.GetBool("followExternalSymlinks")
} }
if isAddrSet && isSocketSet { if isAddrSet && isSocketSet {
checkErr(errors.New("--socket flag cannot be used with --address, --port, --key nor --cert")) return nil, errors.New("--socket flag cannot be used with --address, --port, --key nor --cert")
} }
// Do not use saved Socket if address was manually set. // Do not use saved Socket if address was manually set.
@ -205,36 +373,33 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
server.Socket = "" server.Socket = ""
} }
return server if server.EnableExec {
} log.Println("WARNING: Command Runner feature enabled!")
log.Println("WARNING: This feature has known security vulnerabilities and should not")
// getParamB returns a parameter as a string and a boolean to tell if it is different from the default log.Println("WARNING: you fully understand the risks involved. For more information")
// log.Println("WARNING: read https://github.com/filebrowser/filebrowser/issues/5199")
// NOTE: we could simply bind the flags to viper and use IsSet.
// Although there is a bug on Viper that always returns true on IsSet
// if a flag is binded. Our alternative way is to manually check
// the flag and then the value from env/config/gotten by viper.
// https://github.com/spf13/viper/pull/331
func getParamB(flags *pflag.FlagSet, key string) (string, bool) {
value, _ := flags.GetString(key)
// If set on Flags, use it.
if flags.Changed(key) {
return value, true
} }
// If set through viper (env, config), return it. if server.FollowExternalSymlinks {
if v.IsSet(key) { log.Println("WARNING: Following external symlinks enabled!")
return v.GetString(key), true log.Println("WARNING: Symlinks pointing outside a user's scope will be followed,")
log.Println("WARNING: which can expose files outside that scope. Only enable this if")
log.Println("WARNING: you fully understand and trust the contents of every user scope.")
} }
// Otherwise use default value on flags. if set, err := st.Settings.Get(); err == nil && set.Signup {
return value, false scope := strings.TrimSpace(set.Defaults.Scope)
} scopeIsRoot := scope == "" || scope == "." || scope == "/"
func getParam(flags *pflag.FlagSet, key string) string { if !set.CreateUserDir && scopeIsRoot {
val, _ := getParamB(flags, key) log.Println("WARNING: Signup is enabled without createUserDir and the default scope is")
return val log.Println("WARNING: the server root, so every self-registered user can read, modify and")
log.Println("WARNING: delete all files File Browser serves, including other users' files.")
log.Println("WARNING: Enable createUserDir, or set a default scope other than the root.")
}
}
return server, nil
} }
func setupLog(logMethod string) { func setupLog(logMethod string) {
@ -244,7 +409,7 @@ func setupLog(logMethod string) {
case "stderr": case "stderr":
log.SetOutput(os.Stderr) log.SetOutput(os.Stderr)
case "": case "":
log.SetOutput(ioutil.Discard) log.SetOutput(io.Discard)
default: default:
log.SetOutput(&lumberjack.Logger{ log.SetOutput(&lumberjack.Logger{
Filename: logMethod, Filename: logMethod,
@ -255,14 +420,22 @@ func setupLog(logMethod string) {
} }
} }
func quickSetup(flags *pflag.FlagSet, d pythonData) { func quickSetup(v *viper.Viper, s *storage.Storage) error {
log.Println("Performing quick setup")
set := &settings.Settings{ set := &settings.Settings{
Key: generateKey(), Key: generateKey(),
Signup: false, Signup: false,
CreateUserDir: false, HideLoginButton: true,
CreateUserDir: false,
MinimumPasswordLength: settings.DefaultMinimumPasswordLength,
UserHomeBasePath: settings.DefaultUsersHomeBasePath,
Defaults: settings.UserDefaults{ Defaults: settings.UserDefaults{
Scope: ".", Scope: ".",
Locale: "en", Locale: "en",
SingleClick: false,
RedirectAfterCopyMove: true,
AceEditorTheme: v.GetString("defaults.aceEditorTheme"),
Perm: users.Permissions{ Perm: users.Permissions{
Admin: false, Admin: false,
Execute: true, Execute: true,
@ -274,40 +447,73 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
Download: true, Download: true,
}, },
}, },
AuthMethod: "",
Branding: settings.Branding{},
Tus: settings.Tus{
ChunkSize: settings.DefaultTusChunkSize,
RetryCount: settings.DefaultTusRetryCount,
},
Commands: nil,
Shell: nil,
Rules: nil,
} }
var err error var err error
if _, noauth := getParamB(flags, "noauth"); noauth { if v.GetBool("noauth") {
set.AuthMethod = auth.MethodNoAuth set.AuthMethod = auth.MethodNoAuth
err = d.store.Auth.Save(&auth.NoAuth{}) err = s.Auth.Save(&auth.NoAuth{})
} else { } else {
set.AuthMethod = auth.MethodJSONAuth set.AuthMethod = auth.MethodJSONAuth
err = d.store.Auth.Save(&auth.JSONAuth{}) err = s.Auth.Save(&auth.JSONAuth{})
}
if err != nil {
return err
} }
checkErr(err) err = s.Settings.Save(set)
err = d.store.Settings.Save(set) if err != nil {
checkErr(err) return err
}
ser := &settings.Server{ ser := &settings.Server{
BaseURL: getParam(flags, "baseurl"), BaseURL: v.GetString("baseURL"),
Port: getParam(flags, "port"), Port: v.GetString("port"),
Log: getParam(flags, "log"), Log: v.GetString("log"),
TLSKey: getParam(flags, "key"), TLSKey: v.GetString("key"),
TLSCert: getParam(flags, "cert"), TLSCert: v.GetString("cert"),
Address: getParam(flags, "address"), Address: v.GetString("address"),
Root: getParam(flags, "root"), Root: v.GetString("root"),
TokenExpirationTime: v.GetString("tokenExpirationTime"),
EnableThumbnails: !v.GetBool("disableThumbnails"),
ResizePreview: !v.GetBool("disablePreviewResize"),
EnableExec: !v.GetBool("disableExec"),
TypeDetectionByHeader: !v.GetBool("disableTypeDetectionByHeader"),
ImageResolutionCal: !v.GetBool("disableImageResolutionCalc"),
FollowExternalSymlinks: v.GetBool("followExternalSymlinks"),
} }
err = d.store.Settings.SaveServer(ser) err = s.Settings.SaveServer(ser)
checkErr(err) if err != nil {
return err
}
username := getParam(flags, "username") username := v.GetString("username")
password := getParam(flags, "password") password := v.GetString("password")
if password == "" { if password == "" {
password, err = users.HashPwd("admin") var pwd string
checkErr(err) pwd, err = users.RandomPwd(set.MinimumPasswordLength)
if err != nil {
return err
}
log.Printf("User '%s' initialized with randomly generated password: %s\n", username, pwd)
password, err = users.ValidateAndHashPwd(pwd, set.MinimumPasswordLength)
if err != nil {
return err
}
} else {
log.Printf("User '%s' initialize wth user-provided password\n", username)
} }
if username == "" || password == "" { if username == "" || password == "" {
@ -323,32 +529,5 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
set.Defaults.Apply(user) set.Defaults.Apply(user)
user.Perm.Admin = true user.Perm.Admin = true
err = d.store.Users.Save(user) return s.Users.Save(user)
checkErr(err)
}
func initConfig() {
if cfgFile == "" {
home, err := homedir.Dir()
checkErr(err)
v.AddConfigPath(".")
v.AddConfigPath(home)
v.AddConfigPath("/etc/filebrowser/")
v.SetConfigName(".filebrowser")
} else {
v.SetConfigFile(cfgFile)
}
v.SetEnvPrefix("FB")
v.AutomaticEnv()
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
if err := v.ReadInConfig(); err != nil {
if _, ok := err.(v.ConfigParseError); ok {
panic(err)
}
cfgFile = "No config file used"
} else {
cfgFile = "Using config file: " + v.ConfigFileUsed()
}
} }

View file

@ -40,27 +40,29 @@ including 'index_end'.`,
return nil return nil
}, },
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
i, err := strconv.Atoi(args[0]) i, err := strconv.Atoi(args[0])
checkErr(err) if err != nil {
return err
}
f := i f := i
if len(args) == 2 { //nolint:mnd if len(args) == 2 {
f, err = strconv.Atoi(args[1]) f, err = strconv.Atoi(args[1])
checkErr(err) if err != nil {
return err
}
} }
user := func(u *users.User) { user := func(u *users.User) error {
u.Rules = append(u.Rules[:i], u.Rules[f+1:]...) u.Rules = append(u.Rules[:i], u.Rules[f+1:]...)
err := d.store.Users.Save(u) return st.Users.Save(u)
checkErr(err)
} }
global := func(s *settings.Settings) { global := func(s *settings.Settings) error {
s.Rules = append(s.Rules[:i], s.Rules[f+1:]...) s.Rules = append(s.Rules[:i], s.Rules[f+1:]...)
err := d.store.Settings.Save(s) return st.Settings.Save(s)
checkErr(err)
} }
runRules(d.store, cmd, user, global) return runRules(st.Storage, cmd, user, global)
}, pythonConfig{}), }, storeOptions{}),
} }

View file

@ -29,41 +29,63 @@ rules.`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
} }
func runRules(st *storage.Storage, cmd *cobra.Command, usersFn func(*users.User), globalFn func(*settings.Settings)) { func runRules(st *storage.Storage, cmd *cobra.Command, usersFn func(*users.User) error, globalFn func(*settings.Settings) error) error {
id := getUserIdentifier(cmd.Flags()) id, err := getUserIdentifier(cmd.Flags())
if err != nil {
return err
}
if id != nil { if id != nil {
user, err := st.Users.Get("", id) var user *users.User
checkErr(err) user, err = st.Users.Get("", false, id)
if err != nil {
return err
}
if usersFn != nil { if usersFn != nil {
usersFn(user) err = usersFn(user)
if err != nil {
return err
}
} }
printRules(user.Rules, id) printRules(user.Rules, id)
return return nil
} }
s, err := st.Settings.Get() s, err := st.Settings.Get()
checkErr(err) if err != nil {
return err
}
if globalFn != nil { if globalFn != nil {
globalFn(s) err = globalFn(s)
if err != nil {
return err
}
} }
printRules(s.Rules, id) printRules(s.Rules, id)
return nil
} }
func getUserIdentifier(flags *pflag.FlagSet) interface{} { func getUserIdentifier(flags *pflag.FlagSet) (interface{}, error) {
id := mustGetUint(flags, "id") id, err := flags.GetUint("id")
username := mustGetString(flags, "username") if err != nil {
return nil, err
if id != 0 {
return id
} else if username != "" {
return username
} }
return nil username, err := flags.GetString("username")
if err != nil {
return nil, err
}
if id != 0 {
return id, nil
} else if username != "" {
return username, nil
}
return nil, nil
} }
func printRules(rulez []rules.Rule, id interface{}) { func printRules(rulez []rules.Rule, id interface{}) {

View file

@ -21,9 +21,19 @@ var rulesAddCmd = &cobra.Command{
Short: "Add a global rule or user rule", Short: "Add a global rule or user rule",
Long: `Add a global rule or user rule.`, Long: `Add a global rule or user rule.`,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
allow := mustGetBool(cmd.Flags(), "allow") flags := cmd.Flags()
regex := mustGetBool(cmd.Flags(), "regex")
allow, err := flags.GetBool("allow")
if err != nil {
return err
}
regex, err := flags.GetBool("regex")
if err != nil {
return err
}
exp := args[0] exp := args[0]
if regex { if regex {
@ -41,18 +51,16 @@ var rulesAddCmd = &cobra.Command{
rule.Path = exp rule.Path = exp
} }
user := func(u *users.User) { user := func(u *users.User) error {
u.Rules = append(u.Rules, rule) u.Rules = append(u.Rules, rule)
err := d.store.Users.Save(u) return st.Users.Save(u)
checkErr(err)
} }
global := func(s *settings.Settings) { global := func(s *settings.Settings) error {
s.Rules = append(s.Rules, rule) s.Rules = append(s.Rules, rule)
err := d.store.Settings.Save(s) return st.Settings.Save(s)
checkErr(err)
} }
runRules(d.store, cmd, user, global) return runRules(st.Storage, cmd, user, global)
}, pythonConfig{}), }, storeOptions{}),
} }

View file

@ -13,7 +13,7 @@ var rulesLsCommand = &cobra.Command{
Short: "List global rules or user specific rules", Short: "List global rules or user specific rules",
Long: `List global rules or user specific rules.`, Long: `List global rules or user specific rules.`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error {
runRules(d.store, cmd, nil, nil) return runRules(st.Storage, cmd, nil, nil)
}, pythonConfig{}), }, storeOptions{}),
} }

View file

@ -1,31 +0,0 @@
package cmd
import (
"github.com/spf13/cobra"
"github.com/filebrowser/filebrowser/v2/storage/bolt/importer"
)
func init() {
rootCmd.AddCommand(upgradeCmd)
upgradeCmd.Flags().String("old.database", "", "")
upgradeCmd.Flags().String("old.config", "", "")
_ = upgradeCmd.MarkFlagRequired("old.database")
}
var upgradeCmd = &cobra.Command{
Use: "upgrade",
Short: "Upgrades an old configuration",
Long: `Upgrades an old configuration. This command DOES NOT
import share links because they are incompatible with
this version.`,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
flags := cmd.Flags()
oldDB := mustGetString(flags, "old.database")
oldConf := mustGetString(flags, "old.config")
err := importer.Import(oldDB, oldConf, getParam(flags, "database"))
checkErr(err)
},
}

View file

@ -27,15 +27,17 @@ var usersCmd = &cobra.Command{
func printUsers(usrs []*users.User) { func printUsers(usrs []*users.User) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock") fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tRed. After C/M\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
for _, u := range usrs { for _, u := range usrs {
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n", fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
u.ID, u.ID,
u.Username, u.Username,
u.Scope, u.Scope,
u.Locale, u.Locale,
u.ViewMode, u.ViewMode,
u.SingleClick,
u.RedirectAfterCopyMove,
u.Perm.Admin, u.Perm.Admin,
u.Perm.Execute, u.Perm.Execute,
u.Perm.Create, u.Perm.Create,
@ -52,7 +54,7 @@ func printUsers(usrs []*users.User) {
} }
func parseUsernameOrID(arg string) (username string, id uint) { func parseUsernameOrID(arg string) (username string, id uint) {
id64, err := strconv.ParseUint(arg, 10, 0) id64, err := strconv.ParseUint(arg, 10, 64)
if err != nil { if err != nil {
return arg, 0 return arg, 0
} }
@ -75,50 +77,75 @@ func addUserFlags(flags *pflag.FlagSet) {
flags.String("scope", ".", "scope for users") flags.String("scope", ".", "scope for users")
flags.String("locale", "en", "locale for users") flags.String("locale", "en", "locale for users")
flags.String("viewMode", string(users.ListViewMode), "view mode for users") flags.String("viewMode", string(users.ListViewMode), "view mode for users")
flags.Bool("singleClick", false, "use single clicks only")
flags.Bool("redirectAfterCopyMove", false, "redirect to destination after copy/move")
flags.Bool("dateFormat", false, "use date format (true for absolute time, false for relative)")
flags.Bool("hideDotfiles", false, "hide dotfiles in file listings")
flags.String("aceEditorTheme", "", "ace editor's syntax highlighting theme for users")
} }
func getViewMode(flags *pflag.FlagSet) users.ViewMode { func getAndParseViewMode(flags *pflag.FlagSet) (users.ViewMode, error) {
viewMode := users.ViewMode(mustGetString(flags, "viewMode")) viewModeStr, err := flags.GetString("viewMode")
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode { if err != nil {
checkErr(errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(users.MosaicViewMode) + "\"")) return "", err
} }
return viewMode
viewMode := users.ViewMode(viewModeStr)
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode {
return "", errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(users.MosaicViewMode) + "\"")
}
return viewMode, nil
} }
//nolint:gocyclo func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all bool) error {
func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all bool) { errs := []error{}
visit := func(flag *pflag.Flag) { visit := func(flag *pflag.Flag) {
var err error
switch flag.Name { switch flag.Name {
case "scope": case "scope":
defaults.Scope = mustGetString(flags, flag.Name) defaults.Scope, err = flags.GetString(flag.Name)
case "locale": case "locale":
defaults.Locale = mustGetString(flags, flag.Name) defaults.Locale, err = flags.GetString(flag.Name)
case "viewMode": case "viewMode":
defaults.ViewMode = getViewMode(flags) defaults.ViewMode, err = getAndParseViewMode(flags)
case "singleClick":
defaults.SingleClick, err = flags.GetBool(flag.Name)
case "redirectAfterCopyMove":
defaults.RedirectAfterCopyMove, err = flags.GetBool(flag.Name)
case "aceEditorTheme":
defaults.AceEditorTheme, err = flags.GetString(flag.Name)
case "perm.admin": case "perm.admin":
defaults.Perm.Admin = mustGetBool(flags, flag.Name) defaults.Perm.Admin, err = flags.GetBool(flag.Name)
case "perm.execute": case "perm.execute":
defaults.Perm.Execute = mustGetBool(flags, flag.Name) defaults.Perm.Execute, err = flags.GetBool(flag.Name)
case "perm.create": case "perm.create":
defaults.Perm.Create = mustGetBool(flags, flag.Name) defaults.Perm.Create, err = flags.GetBool(flag.Name)
case "perm.rename": case "perm.rename":
defaults.Perm.Rename = mustGetBool(flags, flag.Name) defaults.Perm.Rename, err = flags.GetBool(flag.Name)
case "perm.modify": case "perm.modify":
defaults.Perm.Modify = mustGetBool(flags, flag.Name) defaults.Perm.Modify, err = flags.GetBool(flag.Name)
case "perm.delete": case "perm.delete":
defaults.Perm.Delete = mustGetBool(flags, flag.Name) defaults.Perm.Delete, err = flags.GetBool(flag.Name)
case "perm.share": case "perm.share":
defaults.Perm.Share = mustGetBool(flags, flag.Name) defaults.Perm.Share, err = flags.GetBool(flag.Name)
case "perm.download": case "perm.download":
defaults.Perm.Download = mustGetBool(flags, flag.Name) defaults.Perm.Download, err = flags.GetBool(flag.Name)
case "commands": case "commands":
commands, err := flags.GetStringSlice(flag.Name) defaults.Commands, err = flags.GetStringSlice(flag.Name)
checkErr(err)
defaults.Commands = commands
case "sorting.by": case "sorting.by":
defaults.Sorting.By = mustGetString(flags, flag.Name) defaults.Sorting.By, err = flags.GetString(flag.Name)
case "sorting.asc": case "sorting.asc":
defaults.Sorting.Asc = mustGetBool(flags, flag.Name) defaults.Sorting.Asc, err = flags.GetBool(flag.Name)
case "dateFormat":
defaults.DateFormat, err = flags.GetBool(flag.Name)
case "hideDotfiles":
defaults.HideDotfiles, err = flags.GetBool(flag.Name)
}
if err != nil {
errs = append(errs, err)
} }
} }
@ -127,4 +154,6 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
} else { } else {
flags.Visit(visit) flags.Visit(visit)
} }
return errors.Join(errs...)
} }

View file

@ -15,37 +15,68 @@ var usersAddCmd = &cobra.Command{
Use: "add <username> <password>", Use: "add <username> <password>",
Short: "Create a new user", Short: "Create a new user",
Long: `Create a new user and add it to the database.`, Long: `Create a new user and add it to the database.`,
Args: cobra.ExactArgs(2), //nolint:mnd Args: cobra.ExactArgs(2),
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
s, err := d.store.Settings.Get() flags := cmd.Flags()
checkErr(err) s, err := st.Settings.Get()
getUserDefaults(cmd.Flags(), &s.Defaults, false) if err != nil {
return err
}
err = getUserDefaults(flags, &s.Defaults, false)
if err != nil {
return err
}
password, err := users.HashPwd(args[1]) password, err := users.ValidateAndHashPwd(args[1], s.MinimumPasswordLength)
checkErr(err) if err != nil {
return err
}
user := &users.User{ user := &users.User{
Username: args[0], Username: args[0],
Password: password, Password: password,
LockPassword: mustGetBool(cmd.Flags(), "lockPassword"), }
user.LockPassword, err = flags.GetBool("lockPassword")
if err != nil {
return err
}
user.DateFormat, err = flags.GetBool("dateFormat")
if err != nil {
return err
}
user.HideDotfiles, err = flags.GetBool("hideDotfiles")
if err != nil {
return err
} }
s.Defaults.Apply(user) s.Defaults.Apply(user)
servSettings, err := d.store.Settings.GetServer() servSettings, err := st.Settings.GetServer()
checkErr(err) if err != nil {
return err
}
// since getUserDefaults() polluted s.Defaults.Scope // since getUserDefaults() polluted s.Defaults.Scope
// which makes the Scope not the one saved in the db // which makes the Scope not the one saved in the db
// we need the right s.Defaults.Scope here // we need the right s.Defaults.Scope here
s2, err := d.store.Settings.Get() s2, err := st.Settings.Get()
checkErr(err) if err != nil {
return err
}
userHome, err := s2.MakeUserDir(user.Username, user.Scope, servSettings.Root) userHome, err := s2.MakeUserDir(user.Username, user.Scope, servSettings.Root)
checkErr(err) if err != nil {
return err
}
user.Scope = userHome user.Scope = userHome
err = d.store.Users.Save(user) err = st.Users.Save(user)
checkErr(err) if err != nil {
return err
}
printUsers([]*users.User{user}) printUsers([]*users.User{user})
}, pythonConfig{}), return nil
}, storeOptions{}),
} }

View file

@ -14,11 +14,16 @@ var usersExportCmd = &cobra.Command{
Long: `Export all users to a json or yaml file. Please indicate the Long: `Export all users to a json or yaml file. Please indicate the
path to the file where you want to write the users.`, path to the file where you want to write the users.`,
Args: jsonYamlArg, Args: jsonYamlArg,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
list, err := d.store.Users.Gets("") list, err := st.Users.Gets("", false)
checkErr(err) if err != nil {
return err
}
err = marshal(args[0], list) err = marshal(args[0], list)
checkErr(err) if err != nil {
}, pythonConfig{}), return err
}
return nil
}, storeOptions{}),
} }

View file

@ -16,17 +16,17 @@ var usersFindCmd = &cobra.Command{
Short: "Find a user by username or id", Short: "Find a user by username or id",
Long: `Find a user by username or id. If no flag is set, all users will be printed.`, Long: `Find a user by username or id. If no flag is set, all users will be printed.`,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: findUsers, RunE: findUsers,
} }
var usersLsCmd = &cobra.Command{ var usersLsCmd = &cobra.Command{
Use: "ls", Use: "ls",
Short: "List all users.", Short: "List all users.",
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: findUsers, RunE: findUsers,
} }
var findUsers = python(func(cmd *cobra.Command, args []string, d pythonData) { var findUsers = withStore(func(_ *cobra.Command, args []string, st *store) error {
var ( var (
list []*users.User list []*users.User
user *users.User user *users.User
@ -36,16 +36,19 @@ var findUsers = python(func(cmd *cobra.Command, args []string, d pythonData) {
if len(args) == 1 { if len(args) == 1 {
username, id := parseUsernameOrID(args[0]) username, id := parseUsernameOrID(args[0])
if username != "" { if username != "" {
user, err = d.store.Users.Get("", username) user, err = st.Users.Get("", false, username)
} else { } else {
user, err = d.store.Users.Get("", id) user, err = st.Users.Get("", false, id)
} }
list = []*users.User{user} list = []*users.User{user}
} else { } else {
list, err = d.store.Users.Gets("") list, err = st.Users.Gets("", false)
} }
checkErr(err) if err != nil {
return err
}
printUsers(list) printUsers(list)
}, pythonConfig{}) return nil
}, storeOptions{})

View file

@ -25,50 +25,71 @@ file. You can use this command to import new users to your
installation. For that, just don't place their ID on the files installation. For that, just don't place their ID on the files
list or set it to 0.`, list or set it to 0.`,
Args: jsonYamlArg, Args: jsonYamlArg,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
flags := cmd.Flags()
fd, err := os.Open(args[0]) fd, err := os.Open(args[0])
checkErr(err) if err != nil {
return err
}
defer fd.Close() defer fd.Close()
list := []*users.User{} list := []*users.User{}
err = unmarshal(args[0], &list) err = unmarshal(args[0], &list)
checkErr(err) if err != nil {
return err
for _, user := range list {
err = user.Clean("")
checkErr(err)
} }
if mustGetBool(cmd.Flags(), "replace") { for _, user := range list {
oldUsers, err := d.store.Users.Gets("") err = user.Clean("", false)
checkErr(err) if err != nil {
return err
err = marshal("users.backup.json", list)
checkErr(err)
for _, user := range oldUsers {
err = d.store.Users.Delete(user.ID)
checkErr(err)
} }
} }
overwrite := mustGetBool(cmd.Flags(), "overwrite") replace, err := flags.GetBool("replace")
if err != nil {
return err
}
if replace {
oldUsers, userImportErr := st.Users.Gets("", false)
if userImportErr != nil {
return userImportErr
}
err = marshal("users.backup.json", list)
if err != nil {
return err
}
for _, user := range oldUsers {
err = st.Users.Delete(user.ID)
if err != nil {
return err
}
}
}
overwrite, err := flags.GetBool("overwrite")
if err != nil {
return err
}
for _, user := range list { for _, user := range list {
onDB, err := d.store.Users.Get("", user.ID) onDB, err := st.Users.Get("", false, user.ID)
// User exists in DB. // User exists in DB.
if err == nil { if err == nil {
if !overwrite { if !overwrite {
checkErr(errors.New("user " + strconv.Itoa(int(user.ID)) + " is already registred")) return errors.New("user " + strconv.Itoa(int(user.ID)) + " is already registered")
} }
// If the usernames mismatch, check if there is another one in the DB // If the usernames mismatch, check if there is another one in the DB
// with the new username. If there is, print an error and cancel the // with the new username. If there is, print an error and cancel the
// operation // operation
if user.Username != onDB.Username { if user.Username != onDB.Username {
if conflictuous, err := d.store.Users.Get("", user.Username); err == nil { //nolint:shadow if conflictuous, err := st.Users.Get("", false, user.Username); err == nil {
checkErr(usernameConflictError(user.Username, conflictuous.ID, user.ID)) return usernameConflictError(user.Username, conflictuous.ID, user.ID)
} }
} }
} else { } else {
@ -77,13 +98,16 @@ list or set it to 0.`,
user.ID = 0 user.ID = 0
} }
err = d.store.Users.Save(user) err = st.Users.Save(user)
checkErr(err) if err != nil {
return err
}
} }
}, pythonConfig{}), return nil
}, storeOptions{}),
} }
func usernameConflictError(username string, originalID, newID uint) error { func usernameConflictError(username string, originalID, newID uint) error {
return fmt.Errorf(`can't import user with ID %d and username "%s" because the username is already registred with the user %d`, return fmt.Errorf(`can't import user with ID %d and username "%s" because the username is already registered with the user %d`,
newID, username, originalID) newID, username, originalID)
} }

View file

@ -15,17 +15,20 @@ var usersRmCmd = &cobra.Command{
Short: "Delete a user by username or id", Short: "Delete a user by username or id",
Long: `Delete a user by username or id`, Long: `Delete a user by username or id`,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
username, id := parseUsernameOrID(args[0]) username, id := parseUsernameOrID(args[0])
var err error var err error
if username != "" { if username != "" {
err = d.store.Users.Delete(username) err = st.Users.Delete(username)
} else { } else {
err = d.store.Users.Delete(id) err = st.Users.Delete(id)
} }
checkErr(err) if err != nil {
return err
}
fmt.Println("user deleted successfully") fmt.Println("user deleted successfully")
}, pythonConfig{}), return nil
}, storeOptions{}),
} }

View file

@ -21,53 +21,91 @@ var usersUpdateCmd = &cobra.Command{
Long: `Updates an existing user. Set the flags for the Long: `Updates an existing user. Set the flags for the
options you want to change.`, options you want to change.`,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: python(func(cmd *cobra.Command, args []string, d pythonData) { RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
username, id := parseUsernameOrID(args[0])
flags := cmd.Flags() flags := cmd.Flags()
password := mustGetString(flags, "password") username, id := parseUsernameOrID(args[0])
newUsername := mustGetString(flags, "username") password, err := flags.GetString("password")
if err != nil {
return err
}
newUsername, err := flags.GetString("username")
if err != nil {
return err
}
s, err := st.Settings.Get()
if err != nil {
return err
}
var ( var (
err error
user *users.User user *users.User
) )
if id != 0 { if id != 0 {
user, err = d.store.Users.Get("", id) user, err = st.Users.Get("", false, id)
} else { } else {
user, err = d.store.Users.Get("", username) user, err = st.Users.Get("", false, username)
}
if err != nil {
return err
} }
checkErr(err)
defaults := settings.UserDefaults{ defaults := settings.UserDefaults{
Scope: user.Scope, Scope: user.Scope,
Locale: user.Locale, Locale: user.Locale,
ViewMode: user.ViewMode, ViewMode: user.ViewMode,
Perm: user.Perm, SingleClick: user.SingleClick,
Sorting: user.Sorting, RedirectAfterCopyMove: user.RedirectAfterCopyMove,
Commands: user.Commands, Perm: user.Perm,
Sorting: user.Sorting,
Commands: user.Commands,
} }
getUserDefaults(flags, &defaults, false)
err = getUserDefaults(flags, &defaults, false)
if err != nil {
return err
}
user.Scope = defaults.Scope user.Scope = defaults.Scope
user.Locale = defaults.Locale user.Locale = defaults.Locale
user.ViewMode = defaults.ViewMode user.ViewMode = defaults.ViewMode
user.SingleClick = defaults.SingleClick
user.RedirectAfterCopyMove = defaults.RedirectAfterCopyMove
user.Perm = defaults.Perm user.Perm = defaults.Perm
user.Commands = defaults.Commands user.Commands = defaults.Commands
user.Sorting = defaults.Sorting user.Sorting = defaults.Sorting
user.LockPassword = mustGetBool(flags, "lockPassword") user.LockPassword, err = flags.GetBool("lockPassword")
if err != nil {
return err
}
user.DateFormat, err = flags.GetBool("dateFormat")
if err != nil {
return err
}
user.HideDotfiles, err = flags.GetBool("hideDotfiles")
if err != nil {
return err
}
if newUsername != "" { if newUsername != "" {
user.Username = newUsername user.Username = newUsername
} }
if password != "" { if password != "" {
user.Password, err = users.HashPwd(password) user.Password, err = users.ValidateAndHashPwd(password, s.MinimumPasswordLength)
checkErr(err) if err != nil {
return err
}
} }
err = d.store.Users.Update(user) err = st.Users.Update(user)
checkErr(err) if err != nil {
return err
}
printUsers([]*users.User{user}) printUsers([]*users.User{user})
}, pythonConfig{}), return nil
}, storeOptions{}),
} }

View file

@ -3,64 +3,50 @@ package cmd
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "io/fs"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"strings"
"github.com/asdine/storm" "github.com/asdine/storm/v3"
homedir "github.com/mitchellh/go-homedir"
"github.com/samber/lo"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
yaml "gopkg.in/yaml.v2" "github.com/spf13/viper"
yaml "gopkg.in/yaml.v3"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/storage/bolt" "github.com/filebrowser/filebrowser/v2/storage/bolt"
) )
func checkErr(err error) { const databasePermissions = 0640
func getAndParseFileMode(flags *pflag.FlagSet, name string) (fs.FileMode, error) {
mode, err := flags.GetString(name)
if err != nil { if err != nil {
log.Fatal(err) return 0, err
} }
}
func mustGetString(flags *pflag.FlagSet, flag string) string { b, err := strconv.ParseUint(mode, 0, 32)
s, err := flags.GetString(flag) if err != nil {
checkErr(err) return 0, err
return s }
}
func mustGetBool(flags *pflag.FlagSet, flag string) bool { return fs.FileMode(b), nil
b, err := flags.GetBool(flag)
checkErr(err)
return b
}
func mustGetUint(flags *pflag.FlagSet, flag string) uint {
b, err := flags.GetUint(flag)
checkErr(err)
return b
} }
func generateKey() []byte { func generateKey() []byte {
k, err := settings.GenerateKey() k, err := settings.GenerateKey()
checkErr(err) if err != nil {
panic(err)
}
return k return k
} }
type cobraFunc func(cmd *cobra.Command, args []string)
type pythonFunc func(cmd *cobra.Command, args []string, data pythonData)
type pythonConfig struct {
noDB bool
allowNoDB bool
}
type pythonData struct {
hadDB bool
store *storage.Storage
}
func dbExists(path string) (bool, error) { func dbExists(path string) (bool, error) {
stat, err := os.Stat(path) stat, err := os.Stat(path)
if err == nil { if err == nil {
@ -71,7 +57,7 @@ func dbExists(path string) (bool, error) {
d := filepath.Dir(path) d := filepath.Dir(path)
_, err = os.Stat(d) _, err = os.Stat(d)
if os.IsNotExist(err) { if os.IsNotExist(err) {
if err := os.MkdirAll(d, 0700); err != nil { //nolint:shadow if err := os.MkdirAll(d, 0700); err != nil {
return false, err return false, err
} }
return false, nil return false, nil
@ -81,34 +67,143 @@ func dbExists(path string) (bool, error) {
return false, err return false, err
} }
func python(fn pythonFunc, cfg pythonConfig) cobraFunc { // Generate the replacements for all environment variables. This allows to
return func(cmd *cobra.Command, args []string) { // use FB_BRANDING_DISABLE_EXTERNAL environment variables, even when the
data := pythonData{hadDB: true} // option name is branding.disableExternal.
func generateEnvKeyReplacements(cmd *cobra.Command) []string {
replacements := []string{}
path := getParam(cmd.Flags(), "database") cmd.Flags().VisitAll(func(f *pflag.Flag) {
exists, err := dbExists(path) oldName := strings.ToUpper(f.Name)
newName := strings.ToUpper(lo.SnakeCase(f.Name))
replacements = append(replacements, oldName, newName)
})
return replacements
}
func initViper(cmd *cobra.Command) (*viper.Viper, error) {
v := viper.New()
// Get config file from flag
cfgFile, err := cmd.Flags().GetString("config")
if err != nil {
return nil, err
}
// Configuration file
if cfgFile == "" {
home, err := homedir.Dir()
if err != nil { if err != nil {
panic(err) return nil, err
} else if exists && cfg.noDB { }
log.Fatal(path + " already exists") v.AddConfigPath(".")
} else if !exists && !cfg.noDB && !cfg.allowNoDB { v.AddConfigPath(home)
log.Fatal(path + " does not exist. Please run 'filebrowser config init' first.") v.AddConfigPath("/etc/filebrowser/")
v.SetConfigName(".filebrowser")
} else {
v.SetConfigFile(cfgFile)
}
// Environment variables
v.SetEnvPrefix("FB")
v.AutomaticEnv()
v.SetEnvKeyReplacer(strings.NewReplacer(generateEnvKeyReplacements(cmd)...))
// Bind the flags
err = v.BindPFlags(cmd.Flags())
if err != nil {
return nil, err
}
// Read in configuration
if err := v.ReadInConfig(); err != nil {
if errors.As(err, &viper.ConfigParseError{}) {
return nil, err
} }
data.hadDB = exists log.Println("No config file used")
db, err := storm.Open(path) } else {
checkErr(err) log.Printf("Using config file: %s", v.ConfigFileUsed())
defer db.Close()
data.store, err = bolt.NewStorage(db)
checkErr(err)
fn(cmd, args, data)
} }
// Return Viper
return v, nil
}
type store struct {
*storage.Storage
databaseExisted bool
}
type storeOptions struct {
expectsNoDatabase bool
allowsNoDatabase bool
}
type cobraFunc func(cmd *cobra.Command, args []string) error
// withViperAndStore initializes Viper and the storage.Store and passes them to the callback function.
// This function should only be used by [withStore] and the root command. No other command should call
// this function directly.
func withViperAndStore(fn func(cmd *cobra.Command, args []string, v *viper.Viper, store *store) error, options storeOptions) cobraFunc {
return func(cmd *cobra.Command, args []string) error {
v, err := initViper(cmd)
if err != nil {
return err
}
path, err := filepath.Abs(v.GetString("database"))
if err != nil {
return err
}
exists, err := dbExists(path)
switch {
case err != nil:
return err
case exists && options.expectsNoDatabase:
log.Fatal(path + " already exists")
case !exists && !options.expectsNoDatabase && !options.allowsNoDatabase:
log.Fatal(path + " does not exist. Please run 'filebrowser config init' first.")
case !exists && !options.expectsNoDatabase:
log.Println("WARNING: filebrowser.db can't be found. Initialing in " + strings.TrimSuffix(path, "filebrowser.db"))
}
log.Println("Using database: " + path)
db, err := storm.Open(path, storm.BoltOptions(databasePermissions, nil))
if err != nil {
return err
}
defer db.Close()
storage, err := bolt.NewStorage(db)
if err != nil {
return err
}
store := &store{
Storage: storage,
databaseExisted: exists,
}
return fn(cmd, args, v, store)
}
}
func withStore(fn func(cmd *cobra.Command, args []string, store *store) error, options storeOptions) cobraFunc {
return withViperAndStore(func(cmd *cobra.Command, args []string, _ *viper.Viper, store *store) error {
return fn(cmd, args, store)
}, options)
} }
func marshal(filename string, data interface{}) error { func marshal(filename string, data interface{}) error {
fd, err := os.Create(filename) fd, err := os.Create(filename)
checkErr(err) if err != nil {
return err
}
defer fd.Close() defer fd.Close()
switch ext := filepath.Ext(filename); ext { switch ext := filepath.Ext(filename); ext {
@ -116,7 +211,7 @@ func marshal(filename string, data interface{}) error {
encoder := json.NewEncoder(fd) encoder := json.NewEncoder(fd)
encoder.SetIndent("", " ") encoder.SetIndent("", " ")
return encoder.Encode(data) return encoder.Encode(data)
case ".yml", ".yaml": //nolint:goconst case ".yml", ".yaml":
encoder := yaml.NewEncoder(fd) encoder := yaml.NewEncoder(fd)
return encoder.Encode(data) return encoder.Encode(data)
default: default:
@ -126,7 +221,9 @@ func marshal(filename string, data interface{}) error {
func unmarshal(filename string, data interface{}) error { func unmarshal(filename string, data interface{}) error {
fd, err := os.Open(filename) fd, err := os.Open(filename)
checkErr(err) if err != nil {
return err
}
defer fd.Close() defer fd.Close()
switch ext := filepath.Ext(filename); ext { switch ext := filepath.Ext(filename); ext {
@ -152,29 +249,14 @@ func jsonYamlArg(cmd *cobra.Command, args []string) error {
} }
} }
func cleanUpInterfaceMap(in map[interface{}]interface{}) map[string]interface{} { // convertCmdStrToCmdArray checks if cmd string is blank (whitespace included)
result := make(map[string]interface{}) // then returns empty string array, else returns the split word array of cmd.
for k, v := range in { // This is to ensure the result will never be []string{""}
result[fmt.Sprintf("%v", k)] = cleanUpMapValue(v) func convertCmdStrToCmdArray(cmd string) []string {
} var cmdArray []string
return result trimmedCmdStr := strings.TrimSpace(cmd)
} if trimmedCmdStr != "" {
cmdArray = strings.Split(trimmedCmdStr, " ")
func cleanUpInterfaceArray(in []interface{}) []interface{} {
result := make([]interface{}, len(in))
for i, v := range in {
result[i] = cleanUpMapValue(v)
}
return result
}
func cleanUpMapValue(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
return cleanUpInterfaceArray(v)
case map[interface{}]interface{}:
return cleanUpInterfaceMap(v)
default:
return v
} }
return cmdArray
} }

View file

@ -15,7 +15,7 @@ func init() {
var versionCmd = &cobra.Command{ var versionCmd = &cobra.Command{
Use: "version", Use: "version",
Short: "Print the version number", Short: "Print the version number",
Run: func(cmd *cobra.Command, args []string) { Run: func(_ *cobra.Command, _ []string) {
fmt.Println("File Browser v" + version.Version + "/" + version.CommitSHA) fmt.Println("File Browser v" + version.Version + "/" + version.CommitSHA)
}, },
} }

32
compose.yaml Normal file
View file

@ -0,0 +1,32 @@
services:
filebrowser:
container_name: filebrowser
image: filebrowser/filebrowser:latest
networks:
- filebrowser
ports:
- 8000:80
volumes:
- filebrowser:/flux/vault
environment:
- FB_REDIS_CACHE_URL=redis://default:filebrowser@redis:6379 # Use rediss:// for ssl
redis:
container_name: redis
image: redis:latest
networks:
- filebrowser
command:
- sh
- -c
- |
cat > /tmp/users.acl <<EOF
user default on >filebrowser ~* +@all
EOF
redis-server --aclfile /tmp/users.acl
networks:
filebrowser:
volumes:
filebrowser:

11
diskcache/cache.go Normal file
View file

@ -0,0 +1,11 @@
package diskcache
import (
"context"
)
type Interface interface {
Store(ctx context.Context, key string, value []byte) error
Load(ctx context.Context, key string) (value []byte, exist bool, err error)
Delete(ctx context.Context, key string) error
}

110
diskcache/file_cache.go Normal file
View file

@ -0,0 +1,110 @@
package diskcache
import (
"context"
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"sync"
"github.com/spf13/afero"
)
type FileCache struct {
fs afero.Fs
// granular locks
scopedLocks struct {
sync.Mutex
sync.Once
locks map[string]sync.Locker
}
}
func New(fs afero.Fs, root string) *FileCache {
return &FileCache{
fs: afero.NewBasePathFs(fs, root),
}
}
func (f *FileCache) Store(_ context.Context, key string, value []byte) error {
mu := f.getScopedLocks(key)
mu.Lock()
defer mu.Unlock()
fileName := f.getFileName(key)
if err := f.fs.MkdirAll(filepath.Dir(fileName), 0700); err != nil {
return err
}
if err := afero.WriteFile(f.fs, fileName, value, 0700); err != nil {
return err
}
return nil
}
func (f *FileCache) Load(_ context.Context, key string) (value []byte, exist bool, err error) {
r, ok, err := f.open(key)
if err != nil || !ok {
return nil, ok, err
}
defer r.Close()
value, err = io.ReadAll(r)
if err != nil {
return nil, false, err
}
return value, true, nil
}
func (f *FileCache) Delete(_ context.Context, key string) error {
mu := f.getScopedLocks(key)
mu.Lock()
defer mu.Unlock()
fileName := f.getFileName(key)
if err := f.fs.Remove(fileName); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
return nil
}
func (f *FileCache) open(key string) (afero.File, bool, error) {
fileName := f.getFileName(key)
file, err := f.fs.Open(fileName)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, false, nil
}
return nil, false, err
}
return file, true, nil
}
// getScopedLocks pull lock from the map if found or create a new one
func (f *FileCache) getScopedLocks(key string) (lock sync.Locker) {
f.scopedLocks.Do(func() { f.scopedLocks.locks = map[string]sync.Locker{} })
f.scopedLocks.Lock()
lock, ok := f.scopedLocks.locks[key]
if !ok {
lock = &sync.Mutex{}
f.scopedLocks.locks[key] = lock
}
f.scopedLocks.Unlock()
return lock
}
func (f *FileCache) getFileName(key string) string {
hasher := sha1.New()
_, _ = hasher.Write([]byte(key))
hash := hex.EncodeToString(hasher.Sum(nil))
return fmt.Sprintf("%s/%s/%s", hash[:1], hash[1:3], hash)
}

View file

@ -0,0 +1,55 @@
package diskcache
import (
"context"
"path/filepath"
"testing"
"github.com/spf13/afero"
"github.com/stretchr/testify/require"
)
func TestFileCache(t *testing.T) {
ctx := context.Background()
const (
key = "key"
value = "some text"
newValue = "new text"
cacheRoot = "/cache"
cachedFilePath = "a/62/a62f2225bf70bfaccbc7f1ef2a397836717377de"
)
fs := afero.NewMemMapFs()
cache := New(fs, "/cache")
// store new key
err := cache.Store(ctx, key, []byte(value))
require.NoError(t, err)
checkValue(ctx, t, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, value)
// update existing key
err = cache.Store(ctx, key, []byte(newValue))
require.NoError(t, err)
checkValue(ctx, t, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, newValue)
// delete key
err = cache.Delete(ctx, key)
require.NoError(t, err)
exists, err := afero.Exists(fs, filepath.Join(cacheRoot, cachedFilePath))
require.NoError(t, err)
require.False(t, exists)
}
func checkValue(ctx context.Context, t *testing.T, fs afero.Fs, fileFullPath string, cache *FileCache, key, wantValue string) {
t.Helper()
// check actual file content
b, err := afero.ReadFile(fs, fileFullPath)
require.NoError(t, err)
require.Equal(t, wantValue, string(b))
// check cache content
b, ok, err := cache.Load(ctx, key)
require.NoError(t, err)
require.True(t, ok)
require.Equal(t, wantValue, string(b))
}

24
diskcache/noop_cache.go Normal file
View file

@ -0,0 +1,24 @@
package diskcache
import (
"context"
)
type NoOp struct {
}
func NewNoOp() *NoOp {
return &NoOp{}
}
func (n *NoOp) Store(_ context.Context, _ string, _ []byte) error {
return nil
}
func (n *NoOp) Load(_ context.Context, _ string) (value []byte, exist bool, err error) {
return nil, false, nil
}
func (n *NoOp) Delete(_ context.Context, _ string) error {
return nil
}

View file

@ -0,0 +1,9 @@
#!/bin/sh
set -e
PORT=${FB_PORT:-$(cat /config/settings.json | sh /JSON.sh | grep '\["port"\]' | awk '{print $2}')}
ADDRESS=${FB_ADDRESS:-$(cat /config/settings.json | sh /JSON.sh | grep '\["address"\]' | awk '{print $2}' | sed 's/"//g')}
ADDRESS=${ADDRESS:-localhost}
wget -q --spider http://$ADDRESS:$PORT/health || exit 1

35
docker/alpine/init.sh Executable file
View file

@ -0,0 +1,35 @@
#!/bin/sh
set -e
# Ensure configuration exists
if [ ! -f "/config/settings.json" ]; then
cp -a /defaults/settings.json /config/settings.json
fi
# Extract config file path from arguments
config_file=""
next_is_config=0
for arg in "$@"; do
if [ "$next_is_config" -eq 1 ]; then
config_file="$arg"
break
fi
case "$arg" in
-c|--config)
next_is_config=1
;;
-c=*|--config=*)
config_file="${arg#*=}"
break
;;
esac
done
# If no config argument is provided, set the default and add it to the args
if [ -z "$config_file" ]; then
config_file="/config/settings.json"
set -- --config=/config/settings.json "$@"
fi
exec filebrowser "$@"

View file

@ -3,6 +3,6 @@
"baseURL": "", "baseURL": "",
"address": "", "address": "",
"log": "stdout", "log": "stdout",
"database": "/database.db", "database": "/database/filebrowser.db",
"root": "/srv" "root": "/srv"
} }

9
docker/common/healthcheck.sh Executable file
View file

@ -0,0 +1,9 @@
#!/bin/sh
set -e
PORT=${FB_PORT:-$(jq -r .port /config/settings.json)}
ADDRESS=${FB_ADDRESS:-$(jq -r .address /config/settings.json)}
ADDRESS=${ADDRESS:-localhost}
wget -q --spider http://$ADDRESS:$PORT/health || exit 1

View file

@ -0,0 +1,12 @@
#!/usr/bin/with-contenv bash
# Ensure configuration exists
if [ ! -f "/config/settings.json" ]; then
cp -a /defaults/settings.json /config/settings.json
fi
# permissions
chown abc:abc \
/config/settings.json \
/database \
/srv

View file

@ -0,0 +1,3 @@
#!/usr/bin/with-contenv bash
exec s6-setuidgid abc filebrowser -c /config/settings.json;

49
docs/README.md Normal file
View file

@ -0,0 +1,49 @@
<p align="center">
<img src="../branding/banner.png" width="550"/>
</p>
> [!WARNING]
>
> **File Browser is archived on 2026-09-01.** There will be no further releases and no security fixes. Existing releases and Docker images stay online. For the known unaddressed security issues and hardening guidance, read the [README](../README.md#security).
File Browser provides a file managing interface within a specified directory and it can be used to upload, delete, preview and edit your files. It is a **create-your-own-cloud**-kind of software where you can just install it on your server, direct it to a path and access your files through a nice web interface.
![Preview](static/example.gif)
## Contents
- [Installation](installation.md)
- [Customization](customization.md)
- [Authentication](authentication.md)
- [Command Execution](command-execution.md)
- [Deployment](deployment.md)
- [Troubleshooting](troubleshooting.md)
- [Command Line Usage](cli/filebrowser.md)
Project-level documents live in the repository root: [README](../README.md), [Building File Browser](../CONTRIBUTING.md), [Security Policy](../SECURITY.md), [Code of Conduct](../CODE-OF-CONDUCT.md), [Changelog](../CHANGELOG.md) and [License](../LICENSE).
## Features
- **Easy Login System**
![Login screen](static/1.jpg)
- **Sleek Interface**
![File listing](static/2.jpg)
- **User Management**
![User management](static/3.jpg)
- **File Editing**
![File editor](static/4.jpg)
- **Custom Commands**
![Command runner](static/5.jpg)
- **Customization**
![Customization settings](static/6.jpg)

167
docs/authentication.md Normal file
View file

@ -0,0 +1,167 @@
# Authentication
There are three possible authentication methods. Each one of them has its own capabilities and specification. Adding another authentication method is described in [Building File Browser](../CONTRIBUTING.md#authentication-provider).
## JSON Auth (default)
We call it JSON Authentication but it is just the default authentication method and the one that is provided by default if you don't make any changes. It is set by default, but if you've made changes before you can revert to using JSON auth:
```sh
filebrowser config set --auth.method=json
```
This method can also be extended with **reCAPTCHA** verification during login:
```sh
filebrowser config set --auth.method=json \
--recaptcha.key site-key \
--recaptcha.secret private-key
```
By default, we use [Google's reCAPTCHA](https://developers.google.com/recaptcha/docs/display) service. If you live in China, or want to use other provider, you can change the host with the following command:
```sh
filebrowser config set --recaptcha.host https://recaptcha.net
```
Where `https://recaptcha.net` is any provider you want.
## Proxy Header
If you have a reverse proxy you want to use to login your users, you do it via our `proxy` authentication method. To configure this method, your proxy must send an HTTP header containing the username of the logged in user:
```sh
filebrowser config set --auth.method=proxy --auth.header=X-My-Header
```
Where `X-My-Header` is the HTTP header provided by your proxy with the username.
> [!WARNING]
>
> File Browser will blindly trust the provided header. If the proxy can be bypassed, an attacker could simply attach the header and get admin access. Please ensure that File Browser is not accessible from untrusted networks, and that the proxy is correctly configured to strip/overwrite the header from client requests.
## Hook Authentication
The Hook Authentication method in FileBrowser allows developers to delegate user authentication to an external script or program. Instead of validating credentials internally, FileBrowser sends the username and password to a custom command defined by the administrator. This command receives the credentials through environment variables and returns keyvalue pairs indicating whether the user should be authenticated, blocked, or passed through.
The hooks output controls user permissions, scope, locale, and other attributes, making it a powerful and extensible authentication mechanism.
> [!WARNING]
>
> The submitted username and password are attacker-controlled and are handed to your hook command as the `USERNAME` and `PASSWORD` environment variables. File Browser runs the command directly, without a shell, so the values themselves are inert. However, your script must treat them as untrusted: always quote them (`"$USERNAME"`, `"$PASSWORD"`) and never pass them unquoted to a shell, `eval`, `bash -c`, command substitution, or backticks. A hook script that shell-evaluates these values turns any login request into remote code execution.
For example, the following code delegates filebrowser authentication to a PowerShell script on Windows. You can configure any command (for example, a script in Python, Node.js, etc.).
```sh
filebrowser config set --auth.method=hook --auth.command="powershell.exe -File C:\route\to\your\script\auth.ps1"
```
This is the code for the auth.ps1 script
```sh
param()
# Get FileBrowser credentials from environment variables
$username = $env:USERNAME
$password = $env:PASSWORD
# Users dictionary (for testing purposes only)
$users = @{
"admin" = "kideW48v7-SdE*"
"test" = "2sDd3-etrytñK"
}
# Check if the user exists in the dictionary and verify the password
if ($users.ContainsKey($username) -and $users[$username] -eq $password) {
# Successful authentication
Write-Output "hook.action=auth" # Hook action (in this case, "auth", is required for successful authentication)
Write-Output "user.perm.admin=true" # Set admin role (all permissions)
#You can also define specific permissions like this:
Write-Output "user.perm.execute=true"
Write-Output "user.perm.create=true"
Write-Output "user.perm.rename=true"
Write-Output "user.perm.modify=true"
Write-Output "user.perm.delete=true"
Write-Output "user.perm.share=true"
Write-Output "user.perm.download=true"
Write-Output "user.locale=es" # Set language
Write-Output "user.viewMode=list" # Set view mode
Write-Output "user.scope=/" # Set FileBrowser scope
Write-Output "user.singleClick=true" # Set single click user configuration
Write-Output "user.hideDotfiles=false" # Set hide dot files user configuration
#Set other configuration
} else {
# Block authentication
Write-Output "hook.action=block"
}
```
### Hook Output Format
A hook authentication script must output a series of keyvalue pairs, one per line, using the format:
```
key=value
```
FileBrowser reads these lines and applies the corresponding authentication action and user configuration.
#### Required Fields
The hook must output one of the following actions:
| Key | Description |
|--------|------------ |
| hook.action=auth | Authenticates the user. FileBrowser will create or update the user if needed. |
| hook.action=block | Rejects authentication. The login attempt fails. |
| hook.action=pass | Delegates authentication to FileBrowsers internal password validation. |
For most custom authentication flows, auth or block are used.
Example of a successful authentication:
```sh
hook.action=auth
```
#### Optional User Fields
When `hook.action=auth` is returned, the hook may also define additional user attributes. These fields override FileBrowser defaults and allow full customization of the authenticated user.
1. Permissions
```
user.perm.admin=true
user.perm.execute=true
user.perm.create=true
user.perm.rename=true
user.perm.modify=true
user.perm.delete=true
user.perm.share=true
user.perm.download=true
```
> Setting user.perm.admin=true automatically enables all permissions.
2. User Interface and Behavior
```
user.locale=es
user.viewMode=list
user.singleClick=true
user.hideDotfiles=false
```
3. User Scope
```
user.scope=/
```
## No Authentication
We also provide a no authentication mechanism for users that want to use File Browser privately such in a home network. By setting this authentication method, the user with **id 1** will be used as the default users. Creating more users won't have any effect.
```sh
filebrowser config set --auth.method=noauth
```

View file

@ -0,0 +1,29 @@
# filebrowser cmds add
Add a command to run on a specific event
## Synopsis
Add a command to run on a specific event.
```
filebrowser cmds add <event> <command> [flags]
```
## Options
```
-h, --help help for add
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser cmds](filebrowser-cmds.md) - Command runner management utility

View file

@ -0,0 +1,30 @@
# filebrowser cmds ls
List all commands for each event
## Synopsis
List all commands for each event.
```
filebrowser cmds ls [flags]
```
## Options
```
-e, --event string event name, without 'before' or 'after'
-h, --help help for ls
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser cmds](filebrowser-cmds.md) - Command runner management utility

View file

@ -0,0 +1,37 @@
# filebrowser cmds rm
Removes a command from an event hooker
## Synopsis
Removes a command from an event hooker. The provided index
is the same that's printed when you run 'cmds ls'. Note
that after each removal/addition, the index of the
commands change. So be careful when removing them after each
other.
You can also specify an optional parameter (index_end) so
you can remove all commands from 'index' to 'index_end',
including 'index_end'.
```
filebrowser cmds rm <event> <index> [index_end] [flags]
```
## Options
```
-h, --help help for rm
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser cmds](filebrowser-cmds.md) - Command runner management utility

View file

@ -0,0 +1,28 @@
# filebrowser cmds
Command runner management utility
## Synopsis
Command runner management utility.
## Options
```
-h, --help help for cmds
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser](filebrowser.md) - A stylish web-based file browser
* [filebrowser cmds add](filebrowser-cmds-add.md) - Add a command to run on a specific event
* [filebrowser cmds ls](filebrowser-cmds-ls.md) - List all commands for each event
* [filebrowser cmds rm](filebrowser-cmds-rm.md) - Removes a command from an event hooker

View file

@ -0,0 +1,50 @@
# filebrowser completion bash
Generate the autocompletion script for bash
## Synopsis
Generate the autocompletion script for the bash shell.
This script depends on the 'bash-completion' package.
If it is not installed already, you can install it via your OS's package manager.
To load completions in your current shell session:
source <(filebrowser completion bash)
To load completions for every new session, execute once:
### Linux:
filebrowser completion bash > /etc/bash_completion.d/filebrowser
### macOS:
filebrowser completion bash > $(brew --prefix)/etc/bash_completion.d/filebrowser
You will need to start a new shell for this setup to take effect.
```
filebrowser completion bash
```
## Options
```
-h, --help help for bash
--no-descriptions disable completion descriptions
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell

View file

@ -0,0 +1,41 @@
# filebrowser completion fish
Generate the autocompletion script for fish
## Synopsis
Generate the autocompletion script for the fish shell.
To load completions in your current shell session:
filebrowser completion fish | source
To load completions for every new session, execute once:
filebrowser completion fish > ~/.config/fish/completions/filebrowser.fish
You will need to start a new shell for this setup to take effect.
```
filebrowser completion fish [flags]
```
## Options
```
-h, --help help for fish
--no-descriptions disable completion descriptions
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell

View file

@ -0,0 +1,38 @@
# filebrowser completion powershell
Generate the autocompletion script for powershell
## Synopsis
Generate the autocompletion script for powershell.
To load completions in your current shell session:
filebrowser completion powershell | Out-String | Invoke-Expression
To load completions for every new session, add the output of the above command
to your powershell profile.
```
filebrowser completion powershell [flags]
```
## Options
```
-h, --help help for powershell
--no-descriptions disable completion descriptions
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell

View file

@ -0,0 +1,52 @@
# filebrowser completion zsh
Generate the autocompletion script for zsh
## Synopsis
Generate the autocompletion script for the zsh shell.
If shell completion is not already enabled in your environment you will need
to enable it. You can execute the following once:
echo "autoload -U compinit; compinit" >> ~/.zshrc
To load completions in your current shell session:
source <(filebrowser completion zsh)
To load completions for every new session, execute once:
### Linux:
filebrowser completion zsh > "${fpath[1]}/_filebrowser"
### macOS:
filebrowser completion zsh > $(brew --prefix)/share/zsh/site-functions/_filebrowser
You will need to start a new shell for this setup to take effect.
```
filebrowser completion zsh [flags]
```
## Options
```
-h, --help help for zsh
--no-descriptions disable completion descriptions
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell

View file

@ -0,0 +1,31 @@
# filebrowser completion
Generate the autocompletion script for the specified shell
## Synopsis
Generate the autocompletion script for filebrowser for the specified shell.
See each sub-command's help for details on how to use the generated script.
## Options
```
-h, --help help for completion
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser](filebrowser.md) - A stylish web-based file browser
* [filebrowser completion bash](filebrowser-completion-bash.md) - Generate the autocompletion script for bash
* [filebrowser completion fish](filebrowser-completion-fish.md) - Generate the autocompletion script for fish
* [filebrowser completion powershell](filebrowser-completion-powershell.md) - Generate the autocompletion script for powershell
* [filebrowser completion zsh](filebrowser-completion-zsh.md) - Generate the autocompletion script for zsh

View file

@ -0,0 +1,29 @@
# filebrowser config cat
Prints the configuration
## Synopsis
Prints the configuration.
```
filebrowser config cat [flags]
```
## Options
```
-h, --help help for cat
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser config](filebrowser-config.md) - Configuration management utility

View file

@ -0,0 +1,31 @@
# filebrowser config export
Export the configuration to a file
## Synopsis
Export the configuration to a file. The path must be for a
json or yaml file. This exported configuration can be changed,
and imported again with 'config import' command.
```
filebrowser config export <path> [flags]
```
## Options
```
-h, --help help for export
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser config](filebrowser-config.md) - Configuration management utility

View file

@ -0,0 +1,36 @@
# filebrowser config import
Import a configuration file
## Synopsis
Import a configuration file. This will replace all the existing
configuration. Can be used with or without unexisting databases.
If used with a nonexisting database, a key will be generated
automatically. Otherwise the key will be kept the same as in the
database.
The path must be for a json or yaml file.
```
filebrowser config import <path> [flags]
```
## Options
```
-h, --help help for import
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser config](filebrowser-config.md) - Configuration management utility

View file

@ -0,0 +1,90 @@
# filebrowser config init
Initialize a new database
## Synopsis
Initialize a new database to use with File Browser. All of
this options can be changed in the future with the command
'filebrowser config set'. The user related flags apply
to the defaults when creating new users and you don't
override the options.
```
filebrowser config init [flags]
```
## Options
```
--aceEditorTheme string ace editor's syntax highlighting theme for users
-a, --address string address to listen on (default "127.0.0.1")
--auth.command string command for auth.method=hook
--auth.header string HTTP header for auth.method=proxy
--auth.logoutPage string url of custom logout page
--auth.method string authentication type (default "json")
-b, --baseURL string base url
--branding.color string set the theme color
--branding.disableExternal disable external links such as GitHub links
--branding.disableUsedPercentage disable used disk percentage graph
--branding.files string path to directory with images and custom styles
--branding.name string replace 'File Browser' by this name
--branding.theme string set the theme
-t, --cert string tls certificate
--commands strings a list of the commands a user can execute
--createUserDir generate user's home directory automatically
--dateFormat use date format (true for absolute time, false for relative)
--dirMode string mode bits that new directories are created with (default "0o750")
--disableExec disables Command Runner feature (default true)
--disableImageResolutionCalc disables image resolution calculation by reading image files
--disablePreviewResize disable resize of image previews
--disableThumbnails disable image thumbnails
--disableTypeDetectionByHeader disables type detection by reading file headers
--fileMode string mode bits that new files are created with (default "0o640")
--followExternalSymlinks follow symlinks whose target is outside the user scope (unsafe)
-h, --help help for init
--hideDotfiles hide dotfiles in file listings
--hideLoginButton hide login button from public pages
-k, --key string tls key
--locale string locale for users (default "en")
--lockPassword lock password
-l, --log string log output (default "stdout")
--minimumPasswordLength uint minimum password length for new users (default 12)
--perm.admin admin perm for users
--perm.create create perm for users (default true)
--perm.delete delete perm for users (default true)
--perm.download download perm for users (default true)
--perm.execute execute perm for users (default true)
--perm.modify modify perm for users (default true)
--perm.rename rename perm for users (default true)
--perm.share share perm for users (default true)
-p, --port string port to listen on (default "8080")
--recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
--recaptcha.key string ReCaptcha site key
--recaptcha.secret string ReCaptcha secret
--redirectAfterCopyMove redirect to destination after copy/move
-r, --root string root to prepend to relative paths (default ".")
--scope string scope for users (default ".")
--shell string shell command to which other commands should be appended
-s, --signup allow users to signup
--singleClick use single clicks only
--socket string socket to listen to (cannot be used with address, port, cert nor key flags)
--sorting.asc sorting by ascending order
--sorting.by string sorting mode (name, size or modified) (default "name")
--tokenExpirationTime string user session timeout (default "2h")
--tus.chunkSize uint the tus chunk size (default 10485760)
--tus.retryCount uint16 the tus retry count (default 5)
--viewMode string view mode for users (default "list")
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser config](filebrowser-config.md) - Configuration management utility

View file

@ -0,0 +1,87 @@
# filebrowser config set
Updates the configuration
## Synopsis
Updates the configuration. Set the flags for the options
you want to change. Other options will remain unchanged.
```
filebrowser config set [flags]
```
## Options
```
--aceEditorTheme string ace editor's syntax highlighting theme for users
-a, --address string address to listen on (default "127.0.0.1")
--auth.command string command for auth.method=hook
--auth.header string HTTP header for auth.method=proxy
--auth.logoutPage string url of custom logout page
--auth.method string authentication type (default "json")
-b, --baseURL string base url
--branding.color string set the theme color
--branding.disableExternal disable external links such as GitHub links
--branding.disableUsedPercentage disable used disk percentage graph
--branding.files string path to directory with images and custom styles
--branding.name string replace 'File Browser' by this name
--branding.theme string set the theme
-t, --cert string tls certificate
--commands strings a list of the commands a user can execute
--createUserDir generate user's home directory automatically
--dateFormat use date format (true for absolute time, false for relative)
--dirMode string mode bits that new directories are created with (default "0o750")
--disableExec disables Command Runner feature (default true)
--disableImageResolutionCalc disables image resolution calculation by reading image files
--disablePreviewResize disable resize of image previews
--disableThumbnails disable image thumbnails
--disableTypeDetectionByHeader disables type detection by reading file headers
--fileMode string mode bits that new files are created with (default "0o640")
--followExternalSymlinks follow symlinks whose target is outside the user scope (unsafe)
-h, --help help for set
--hideDotfiles hide dotfiles in file listings
--hideLoginButton hide login button from public pages
-k, --key string tls key
--locale string locale for users (default "en")
--lockPassword lock password
-l, --log string log output (default "stdout")
--minimumPasswordLength uint minimum password length for new users (default 12)
--perm.admin admin perm for users
--perm.create create perm for users (default true)
--perm.delete delete perm for users (default true)
--perm.download download perm for users (default true)
--perm.execute execute perm for users (default true)
--perm.modify modify perm for users (default true)
--perm.rename rename perm for users (default true)
--perm.share share perm for users (default true)
-p, --port string port to listen on (default "8080")
--recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
--recaptcha.key string ReCaptcha site key
--recaptcha.secret string ReCaptcha secret
--redirectAfterCopyMove redirect to destination after copy/move
-r, --root string root to prepend to relative paths (default ".")
--scope string scope for users (default ".")
--shell string shell command to which other commands should be appended
-s, --signup allow users to signup
--singleClick use single clicks only
--socket string socket to listen to (cannot be used with address, port, cert nor key flags)
--sorting.asc sorting by ascending order
--sorting.by string sorting mode (name, size or modified) (default "name")
--tokenExpirationTime string user session timeout (default "2h")
--tus.chunkSize uint the tus chunk size (default 10485760)
--tus.retryCount uint16 the tus retry count (default 5)
--viewMode string view mode for users (default "list")
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser config](filebrowser-config.md) - Configuration management utility

View file

@ -0,0 +1,30 @@
# filebrowser config
Configuration management utility
## Synopsis
Configuration management utility.
## Options
```
-h, --help help for config
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser](filebrowser.md) - A stylish web-based file browser
* [filebrowser config cat](filebrowser-config-cat.md) - Prints the configuration
* [filebrowser config export](filebrowser-config-export.md) - Export the configuration to a file
* [filebrowser config import](filebrowser-config-import.md) - Import a configuration file
* [filebrowser config init](filebrowser-config-init.md) - Initialize a new database
* [filebrowser config set](filebrowser-config-set.md) - Updates the configuration

View file

@ -0,0 +1,29 @@
# filebrowser hash
Hashes a password
## Synopsis
Hashes a password using bcrypt algorithm.
```
filebrowser hash <password> [flags]
```
## Options
```
-h, --help help for hash
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser](filebrowser.md) - A stylish web-based file browser

View file

@ -0,0 +1,33 @@
# filebrowser rules add
Add a global rule or user rule
## Synopsis
Add a global rule or user rule.
```
filebrowser rules add <path|expression> [flags]
```
## Options
```
-a, --allow indicates this is an allow rule
-h, --help help for add
-r, --regex indicates this is a regex rule
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
-i, --id uint id of user to which the rules apply
-u, --username string username of user to which the rules apply
```
## See Also
* [filebrowser rules](filebrowser-rules.md) - Rules management utility

View file

@ -0,0 +1,31 @@
# filebrowser rules ls
List global rules or user specific rules
## Synopsis
List global rules or user specific rules.
```
filebrowser rules ls [flags]
```
## Options
```
-h, --help help for ls
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
-i, --id uint id of user to which the rules apply
-u, --username string username of user to which the rules apply
```
## See Also
* [filebrowser rules](filebrowser-rules.md) - Rules management utility

View file

@ -0,0 +1,40 @@
# filebrowser rules rm
Remove a global rule or user rule
## Synopsis
Remove a global rule or user rule. The provided index
is the same that's printed when you run 'rules ls'. Note
that after each removal/addition, the index of the
commands change. So be careful when removing them after each
other.
You can also specify an optional parameter (index_end) so
you can remove all commands from 'index' to 'index_end',
including 'index_end'.
```
filebrowser rules rm <index> [index_end] [flags]
```
## Options
```
-h, --help help for rm
--index uint index of rule to remove
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
-i, --id uint id of user to which the rules apply
-u, --username string username of user to which the rules apply
```
## See Also
* [filebrowser rules](filebrowser-rules.md) - Rules management utility

View file

@ -0,0 +1,34 @@
# filebrowser rules
Rules management utility
## Synopsis
On each subcommand you'll have available at least two flags:
"username" and "id". You must either set only one of them
or none. If you set one of them, the command will apply to
an user, otherwise it will be applied to the global set or
rules.
## Options
```
-h, --help help for rules
-i, --id uint id of user to which the rules apply
-u, --username string username of user to which the rules apply
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser](filebrowser.md) - A stylish web-based file browser
* [filebrowser rules add](filebrowser-rules-add.md) - Add a global rule or user rule
* [filebrowser rules ls](filebrowser-rules-ls.md) - List global rules or user specific rules
* [filebrowser rules rm](filebrowser-rules-rm.md) - Remove a global rule or user rule

View file

@ -0,0 +1,49 @@
# filebrowser users add
Create a new user
## Synopsis
Create a new user and add it to the database.
```
filebrowser users add <username> <password> [flags]
```
## Options
```
--aceEditorTheme string ace editor's syntax highlighting theme for users
--commands strings a list of the commands a user can execute
--dateFormat use date format (true for absolute time, false for relative)
-h, --help help for add
--hideDotfiles hide dotfiles in file listings
--locale string locale for users (default "en")
--lockPassword lock password
--perm.admin admin perm for users
--perm.create create perm for users (default true)
--perm.delete delete perm for users (default true)
--perm.download download perm for users (default true)
--perm.execute execute perm for users (default true)
--perm.modify modify perm for users (default true)
--perm.rename rename perm for users (default true)
--perm.share share perm for users (default true)
--redirectAfterCopyMove redirect to destination after copy/move
--scope string scope for users (default ".")
--singleClick use single clicks only
--sorting.asc sorting by ascending order
--sorting.by string sorting mode (name, size or modified) (default "name")
--viewMode string view mode for users (default "list")
```
## Options inherited from parent commands
```
-c, --config string config file path
-d, --database string database path (default "./filebrowser.db")
```
## See Also
* [filebrowser users](filebrowser-users.md) - Users management utility

Some files were not shown because too many files have changed in this diff Show more