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>
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>
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>
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>
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>
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>