Actions
40 actions, callable from the panel, the command palette and the API as
POST /api/v1/a/<id>. Internal actions used between modules are not listed.
| Action | What it does | Risk | Preview |
|---|---|---|---|
files.list | List a folder (read) | low | No dry run |
files.stat | Stat a file or folder (read) | low | No dry run |
files.read | Read part of a file (read) | low | No dry run |
files.write | Save a file | low | No dry run |
files.mkdir | Create a folder | low | No dry run |
files.move | Move or rename | low | No dry run |
files.copy | Copy a file or folder | low | No dry run |
files.delete | Delete to trash | medium | No dry run |
files.trash.list | List the trash (read) | low | No dry run |
files.trash.restore | Restore from trash | medium | No dry run |
files.trash.empty | Empty the trash | medium | No dry run |
files.chmod | Change permissions | medium | No dry run |
files.archive.create | Create an archive | low | No dry run |
files.archive.extract | Extract an archive | medium | No dry run |
files.search | Search by name or content (read) | low | No dry run |
files.usage.scan | Disk usage of a folder (read) | low | No dry run |
files.upload.chunk | Upload a chunk | low | No dry run |
files.upload.finish | Finish an upload | low | No dry run |
files.upload.abort | Cancel an upload | low | No dry run |
files.ssh.get | SSH access of an account (read) | low | No dry run |
files.ssh.set | Set SSH mode | high | |
files.ssh.status | Effective sshd settings for an account (read) | low | No dry run |
files.sshkey.add | Add an SSH public key | medium | No dry run |
files.sshkey.generate | Generate an ed25519 key pair | medium | No dry run |
files.sshkey.remove | Remove an SSH key | medium | No dry run |
files.ssh.reconcile | Re-apply SSH access and drop expired keys | medium | No dry run |
files.sshd.apply | Apply the sshd hardening profile | critical | |
files.share.create | Create a share link | medium | |
files.share.list | List share links (read) | low | No dry run |
files.share.revoke | Stop sharing | low | |
files.access.list | List FTP and WebDAV users (read) | low | No dry run |
files.access.create | Create an FTP or WebDAV user | medium | |
files.access.update | Change an FTP or WebDAV user | medium | |
files.access.delete | Delete an FTP or WebDAV user | medium | |
files.server.get | File transfer settings of a server (read) | low | No dry run |
files.server.set | Change file transfer settings | high | |
files.firewall.requirements | Ports the file transfer services need (read) | low | No dry run |
files.version.list | List versions of a file (read) | low | No dry run |
files.version.restore | Restore a version of a file | medium | |
files.sshd.get | SSH server settings last applied (read) | low | No dry run |
Permissions and limits
Permissions
files.viewBrowse and read filesfiles.writeCreate and change filesfiles.deleteDelete files and manage the trashfiles.permissionsChange file permissionsfiles.ssh.manageManage SSH access and keysfiles.server.manageManage sshd on serversfiles.shareShare files and folders with a linkfiles.access.manageManage FTP and WebDAV users
Plan limits
files.ssh_keysSSH keys
Engineering notes
Generated from modules/files/docs.md at build e0cdf300. These are the notes the engineers keep
next to the code: precise, technical, and honest about what is not done yet.
Security model (read this first)
- Every file op runs in a helper process that is the account's Unix user (
internal/agent/files_helper.go: the agent re-executes itself withSysProcAttr.Credential{uid,gid,groups}; the helper refuses to run as root and sets no_new_privs). The kernel enforces ordinary permissions; files are createdaccount:account. - Paths are virtual (
/= home) and resolved with openat2(RESOLVE_BENEATH|NO_MAGICLINKS) against a dirfd of the home (files_root.go). Absolute symlinks,..escapes and /proc links are refused by the kernel, race-free. Without openat2 (old kernel/seccomp) a component-wiseO_NOFOLLOWwalk is used, which refuses every symlink. Mutations use parent dirfd + validated leaf with*at()calls; writes are temp + rename and replace (never follow) a symlink at the target. - Sub-users (
actor.Kind == "subuser") are confined: only scopedfoldergrants count (an unscoped role permission is ignored) and the helper refuses every symlink, so a link inside a granted folder cannot reach the rest of the home. Trash and usage ops need a grant on/. - Archives: names validated (no
.., absolute, backslash, NUL), links/devices never extracted, entries created with NOFOLLOW walks, limits (4 GiB, 200k files, ratio 200) enforced on bytes actually written, rollback on failure. .ssh,.rc-trash,.rc-uploadsare panel-managed: not writable through the API; internals are not listed.- SSH keys are not read from
~/.ssh(user-writable). sshd is pointed at root-owned/etc/ssh/rc-keys/%u, rendered from typed key objects (restrictions: from CIDRs,git/sftpforced command, expiry;restrictalways on, so no port forwarding). Modes via groups:rc-ssh-off(AuthorizedKeysFile none),rc-sftp(chroot/srv/rc-chroot/<u>bind-mounting the home viarc-chroot@<u>.service, internal-sftp, no TTY),rc-shell. Snippet/etc/ssh/sshd_config.d/50-respirecloud.conf, hardening10-respirecloud-hardening.conf; every change issshd -tvalidated and reverted on failure.
Actions
files.list/stat/read/write/mkdir/move/copy/delete/trash.*/chmod/archive.create/archive.extract/search/usage.scan,
files.upload.chunk/finish/abort (resumable, 256 KiB chunks), files.ssh.get/set/status, files.sshkey.add/generate/remove,
files.ssh.reconcile (drops expired keys), files.sshd.apply (admin, dry-run diff).
Admins/resellers pass account_id; owners and sub-users act on their own account.
Verified (lab w2-05, Ubuntu 24.04 container, 2026-10-09)
See docs/tasks/w2/w2-05-files-terminal.handover.md.
Sharing, versions, FTP(S) and WebDAV (w11-22)
- Share links (
files.share.create/list/revoke, public page/s/<token>): 256-bit token shown once (only its SHA-256 is stored), optional expiry, bcrypt password (5 wrong tries per link and address in 15 min, then 429), download limit and counter, revocation that also stops a running download (the link is re-checked at every 256 KiB chunk). Files are served asapplication/octet-stream+Content-Disposition: attachment+nosniff+ sandboxing CSP from the panel origin, never from a site; every read isopenat2 RESOLVE_BENEATH|NO_SYMLINKSas the account user, so a shared file that becomes a symlink fails (410 page). Folder shares list the folder and stream a zip (symlinks and special files skipped, 20,000 files at most). The list shows who created each link. Not built: drop-box (upload) mode. - Versions (
files.version.list/restore): a save throughfiles.writeor an overwriting upload keeps the replaced content in<home>/.rc-versions/(counts against the quota; hidden from the file manager; symlinks never followed). Retention: count (default 10), age (30 days), size cap (25 MB; a bigger file is saved without a version and the response carriesversion_note). Restore keeps the current content as a new version first. Settings:files.server.set. - FTP(S) (
files.server.setftp_*,files.access.*): ProFTPD (Debianproftpd-core+proftpd-mod-crypto; RHEL EPELproftpd) as its own unitrc-ftpd.servicewith a panel-owned config; off until an administrator enables it. Explicit TLS is required (TLSRequired on) unless staff allow plain FTP (a warning is shown). Virtual users in/etc/proftpd/rc-ftp.passwd(SHA-512 crypt made by the agent, root-only; never the account's password) with the account's uid/gid and one folder as the chroot (DefaultRoot ~), optional read-only (<Limit WRITE>), allowed addresses, expiry. Passive ports: a range of at most 100 (default 40000-40049) published throughfiles.firewall.requirementsand opened bysecurity.firewall.files.AllowOverwrite on(a re-upload replaces the file; the replaced content is NOT versioned over FTP: ProFTPD runs hooks inside the user's chroot where no panel binary exists, so versions come from the file manager and WebDAV only). Brute force:mod_banMaxLoginAttemptsonly (4 connections that each use their 4 password tries within 10 min = the ADDRESS is banned for 1 h) andClientConnectRate(60 connections in a minute = the address is banned 10 min; it stops one-try-per-connection scripts). NoLoginRaterule: a ban on successful logins punishes normal clients, and a ban keyed on a user name lets anyone lock that user out (w11-41). Without a certificate path a self-signed certificate is created (fingerprint shown). - WebDAV at
/dav/on the panel's own TLS, served by the panel withgolang.org/x/net/webdavoverfiles.dav.op: chosen over nginx (its dav module has no PROPFIND anddav-extis not packaged on both families) and Apache (a second web server). Basic auth with the access user's own password (bcrypt), 8 failures in 15 min per name and address lock it, confined to the user's folder with symlinks refused, read-only enforced server side. - SSH server screen (admin, File transfer > SSH server): review (dry-run diff) then apply
files.sshd.apply; the last applied values are remembered (files.sshd.get).files.sshkey.add/files.ssh.setanswer "SSH is not set up on this server yet" when openssh-server is missing. - Previews: images (as an inert
<img>), text and code (first 64 KB as plain text; HTML and SVG are shown as source). - Upkeep:
files.maintenanceruns hourly (expired SSH keys, finished shares removed after 30 days, old versions pruned).
Not done / next
PDF preview in the panel (its CSP has no frame/object source); share drop-box mode; FTP certificate from the ssl module; a
per-user activity/bytes log and "kill session" for FTP; remote storage; bubblewrap cage (exec path is cageArgv in pty.go);
per-account SSH on/off gated by package; password SSH + TOTP; sshd port change and the second-connection login test; session
list/kill for SSH.