2428 Commits
Author SHA1 Message Date
Nicola Murino 62ae9ba395 set version to 2.7.6
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
v2.7.6
2026-09-18 21:12:40 +02:00
Nicola Murino 2f6ec588bc update deps
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-18 14:51:32 +02:00
Nicola Murino 4814c2ea6c pkgs: restore the cap_net_bind_service file capability
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-14 10:31:54 +02:00
Nicola Murino bb4252c2b0 pkgs: restore the env.d ownership fixup in the rpm postinstall
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-08 10:27:54 +02:00
Nicola Murino ec49c84aea transferchecks: fix flaky tests
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-07 21:19:14 +02:00
Nicola Murino 6e3af25ca1 update deps
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-07 21:11:06 +02:00
Nicola Murino 946b105285 packaging: harden data directory permissions on install
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-07 21:09:18 +02:00
Nicola Murino 98f7e467ab dataprovider: refuse self-service writes made from a stale snapshot
A user or admin changing its own password, profile or two-factor
settings wrote the whole account back and could overwrite a concurrent
administrator change. Self-service updates are now conditional on the
stored updated_at matching the value read, and every update stores a
strictly increasing updated_at.

Thanks to Thomas Toth for the report.

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-07 21:07:59 +02:00
Nicola Murino b3994a9b2c httpd: check the login conditions on every request
HTTP builds a connection per request, so checkHTTPClientUser is where a
request is authorized, the way the credential check is for SFTP and FTP:
it evaluates the login conditions of the account together with the
denied protocols, the login method and the source address.

An account that is disabled, that reaches its expiration date or that
falls outside its access time restrictions is refused on the next
request. The check is redundant on the paths that already run it before
the call, and costs nothing: the account is in memory.

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-07 19:57:07 +02:00
Nicola Murino 227f004620 httpd: check the account state when a public share is served
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-09-07 19:57:00 +02:00
Nicola Murino c8b5ddc5e0 update deps
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-31 21:19:07 +02:00
Nicola Murino 913337f987 httpd: improvements to the static files handling
The wrapper also always closes the files it opens

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-31 21:15:42 +02:00
Nicola Murino 097d86fbfd fix test case with memory provider
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-27 19:05:31 +02:00
Nicola Murino 929c531492 webdav: return the correct ETag after upload, or no ETag if unavailable
Fixes #2282

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-27 15:34:24 +02:00
Nicola Murino db77535ed2 reject a different username from the pre-login hook and auth plugins
Answering with another account has never been a supported configuration for
these two integrations. Mapping several login names onto a single account is a
feature of the external authentication hook

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-27 11:07:55 +02:00
Nicola Murino 4ed2f22257 normalize permission keys and file pattern paths like every other virtual path
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-26 23:31:47 +02:00
Nicola Murino 18d715f44c rename: remove SetPathPermissions
useless on rename, permissions are preserved

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-26 14:43:10 +02:00
Nicola Murino 1505f92f2d sftpd: bound the SCP protocol record length
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-26 11:54:35 +02:00
Nicola Murino 31173b3f67 check transfers: use compare and swap
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-25 10:02:39 +02:00
Nicola Murino b5fb419d76 transferschecker: wait for async transfer registration in tests
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-25 09:53:12 +02:00
Nicola Murino 7fb4c9b2ed shares: fix a directory share widened to the whole user filesystem
Downloading a public share limited to a single directory as a zip archive
rewrote share.Paths[0] to "/" so the entry names came out relative to that
directory. The value it overwrote is the policy every later public request is
authorized against: the browsable listing resolves the requested path under
Paths[0] and the upload handler derives its destination prefix from it.

The rewrite stays confined to the copy the handler holds only if the data
provider returns a share that owns its paths. The memory provider did not:
getACopy assigned the Paths slice by header, so the copy kept pointing at the
array stored in the provider map and the rewrite reached the stored share.
From that moment the link served the whole filesystem of the share owner. Any
recipient, with no account and nothing beyond the share URL, could list and
download every file the owner can reach, and a read-write share also accepted
uploads at the owner's root. The archive returned to the recipient who
triggered the change was still limited to the shared directory, so the
response revealed nothing. The SQL and bolt providers rebuild the slice while
decoding the stored row and were not affected.

The list of files to archive is now local to the handler, so the share is no
longer written to, and getACopy clones the paths, so a copy never shares state
with the provider.

The regression test downloads a share limited to one directory twice and
checks the archive, the stored paths, the browsable listing and a file outside
the share in between, with whichever data provider the test suite runs with.

Thanks to Yutaka Sasaki (@SAYUTIM) for the report.

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-25 09:33:33 +02:00
Nicola Murino f5bd5cada6 update deps
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 22:18:27 +02:00
Nicola Murino 7003eea3f5 fix a race in test cases
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 21:42:53 +02:00
Nicola Murino 1657c6d0d7 serve: guard the state the servers publish while they initialize
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 21:35:27 +02:00
Nicola Murino e8018318d2 switch to Go 1.26
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 15:18:29 +02:00
Nicola Murino 1f7f4ed36e replace golangci-lint with staticcheck, errcheck and unparam
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 15:11:34 +02:00
Nicola Murino ca6d187c92 complete the backport of 5f7a25ebeb
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 11:47:24 +02:00
Nicola Murino 668214452b dataprovider: refresh the cached admin state on shared databases
An instance that starts with an empty admins table caches that state until
restart, so it keeps serving the setup page after another instance completes
the initial configuration. Instances backed by a shared SQL provider now
re-check the database, rate limited to one query per second and only until
the first admin is found

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 11:26:36 +02:00
Nicola Murino c06725a531 WebClient: build the multi-download form via the DOM
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 11:25:30 +02:00
Nicola Murino 69cec5d9bd WebClient: add a render function to the dir browser meta field
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-24 11:25:26 +02:00
Nicola Murino cb0b486f33 fix test cases on Windows
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:53:29 +02:00
Nicola Murino 69cd41ea77 suppress lint warnings
we should consider to remove the gocyclo linter

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:37:06 +02:00
Nicola Murino 54552c2f03 service: warn at startup when running with an effective uid of 0
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:34:26 +02:00
Nicola Murino d801952543 httpd: do not end a streamed listing on a batch with nothing to render
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:34:21 +02:00
Nicola Murino 18964ccacd vfs: skip the listing entries that do not address an entry inside
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:34:16 +02:00
Nicola Murino 87ff5c6969 templates: bound the two factor requests with their timeout
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:34:12 +02:00
Nicola Murino a558122273 sftpd: align SCP name parsing with OpenSSH
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:34:08 +02:00
Nicola Murino b7434f8f87 common: do not apply the user transfer limits to the event actions
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:34:04 +02:00
Nicola Murino 1ab0129013 sftpd: bound the SCP download recursion
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:34:01 +02:00
Nicola Murino 9575747aa3 sftpd: read the directory entries through the shared listing on SCP download
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:56 +02:00
Nicola Murino c1705dc82c sftpd: clean the path before the SCP download checks
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:52 +02:00
Nicola Murino 0f9e9bf39e sftpd: report the SCP download errors once
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:49 +02:00
Nicola Murino 31060cb401 common: check the target write permission and quota on the server-side copy
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:45 +02:00
Nicola Murino f0e660bef2 common: report a hidden path as missing consistently
this is a best effort and outside the security boundaries

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:41 +02:00
Nicola Murino 64586620a2 common: match the entries when a rename changes the filter scope
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:37 +02:00
Nicola Murino 14ed7f6d03 common: apply the name filter wherever a directory is created
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:33 +02:00
Nicola Murino a69ceedf42 common: authorize a directory copy before it creates anything
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:29 +02:00
Nicola Murino dc8886bc07 common: evaluate the name filter on the source of copy, rename and symlink
The file pattern filter matches names, and the operations that read an item
evaluate it on the item itself. Three did not agree with that: a copy
evaluated it on the target only, a rename mapped every refusal to a
permission error and so discarded the deny policy configured on the filter,
and symlink creation honored the hide policy alone, letting the default one
through.

They now all evaluate the source and report the configured policy through
GetErrorForDeniedFile, as stat, download and delete already do, so the same
filter gives the same answer whichever operation reaches a name. The target
keeps reporting a permission error: it is a path being written, not an item
being read. isRenamePermitted returns an error and is renamed accordingly;
the recursive walk still reports a permission error, because the entries it
walks are the contents of the directory being renamed and a hidden one among
them must not make that directory look missing.

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:25 +02:00
Nicola Murino 0547fd5aec sftpd: refuse to hash a path that ends with a slash
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:21 +02:00
Nicola Murino f9f9813246 httpd: refuse an authorization request without a browser identifier
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2026-08-12 23:33:17 +02:00