---
title: "File Reception"
weight: 20
slug: file-reception
aliases:
- /docs/no18-file-reception.html
---
{{< toc >}}

## Preface

Rport allows users to copy files from their local machines to one or many remote clients through the rport server.
The most common use case is the distribution of software or configuration files.

As an alternative, users can write a script to download needed files from the Internet, but usually, we don't want the
client machine downloading it directly because a virus scan must happen at a central place first.

A recommended solution would be to download the file in some workstation, do the necessary virus scans and checksum
checks and then upload the file to the rport server. The latter will distribute it among the clients through the secure SSH connection:

{{< mermaid class="text-center">}}
flowchart TD
    1[http client: browser, rportcli, curl, you]-->|file upload via HTTPS|2[RPort Server]
    2[RPort Server]-->|sftp/ssh file transfer|3[rport clients]
    2[RPort Server]-->|sftp/ssh file transfer|4[rport clients]
    2[RPort Server]-->|sftp/ssh file transfer|5[rport clients]
{{< /mermaid >}}

## Data flow

- The RPort administrator uploads a file to the RPort server by using [UPLOAD API](https://apidoc.openrport.io/master/#tag/Upload).
  With the file, he provides all required information: target file path on client, list of client IDs or group IDs,
  desired file mode, owner/group etc.
- The RPort server copies the file to a temporary folder `[server] {data_dir}/filepush/xxx`, where `[server] data_dir`
  is a configuration option and xxx is a random unique file name generated by the Rport server.
- The RPort server sends to the provided clients a lightweight JSON request via the established and secured SSH
  connections. The request contains a temporary file location on the server as well as all other details
  (target path, checksum, desired file mode and owner etc) needed for the file operations on the client.
- The RPort client(s) opens an SFTP session on top of the existing SSH connection and downloads the file to a temporary
  location `[client] {data_dir}/filepush/xxx`, where `[client] {data_dir}` is the client configuration option and xxx
  is a unique file name generated by the Rport server.
- If the SFTP session succeeds, the client checks the md5 hash of the actual file against the provided checksum,
  chowns and chmods the file (for Unix only) if needed and finally moves it to the target location.
- If the file already exists, and force and sync flags are false, rport client will do nothing.
- If force flag is true, the existing file will be removed and replaced by the provided one
- If sync flag is true, the rport client will compare md5 hash of the existing file with the new one, and will overwrite
  it if they don't match. Additionally, it will apply chmod/chown operations if needed.
- Successes or failures of file operations will be sent to the server via the established SSH connection.
- The server will track the successes or failures on the clients and will report them to all websocket listeners.
- Finally, it will remove the temporary file.

## Upload API

You can use [UPLOAD API](https://apidoc.openrport.io/master/#tag/Upload) to upload a file to a Rport server.

JSON API is not well suited for uploading files, so you need to use the
[multipart form data format](https://en.wikipedia.org/wiki/MIME#Multipart_messages).

The file itself is marked with the required `upload` key.

Additionally, users should provide the following information as additional key/value parts of the multipart request:

`client_id`
: _(string optional)_
  ID of a client who should receive the file. You can repeat `client` part to send a file to multiple clients.

`group_id`
: _(string optional)_
  Client group ID where server should place the uploaded file. You can repeat group IDs to indicate multiple client groups.

`dest`
: _(string required)_
  Absolute path with the file name, showing the desired location of the uploaded file on the client(s).

`force`
: _(bool, optional, default false)_
  By default, ff the target file exists, Rport client will skip the upload request. By providing force flag you require
  rport to overwrite the target file no matter if it exists or not.

`sync`
: _(bool, optional, default false)_
 The sync flag is taken into account only if the target file already exists. The Rport client will do the following:

- if the md5 of the provided file doesn't match the md5 hash of the existing file, it will be overwritten by the new file
- if file mode parameter is provided (see below), the file mode of the target file will be changed to this value (for Unix only)
- if either user or group parameters is provided (see below) and the existing file has a different owner or group,
 Rport client will apply a `chown` operation to it to change owner and group attributes (for Unix only)
- if a destination file doesn't exist, the file will be copied to the destination as mentioned before

`mode`
: _(string, optional, default empty, for Unix only)_
  Indicates the desired file mode of the target file. If no target file exists, rport client will create a temp file
  with the provided mode. If no mode is provided, the default value will be 0764. When rport moves the temp file to the
  destination with its mode. If target file already exists and the sync flag is true, rport client will explicitly change
  mode of the target file to the provided value.

`user/group`
: _(string, optional, default empty, for Unix only)_
  Indicates the desired file owner and group of the target file. If nothing is given, the current Rport client user and
  its default group will be used.
  If no target file exists, rport will create a temp file with the current user and his default group. Then it will do
  the chown operation on the temp file. Then rport client will move the temporary file to the target path along with its
  owner and group attributes.

If target file exists and sync flag is true, rport client will explicitly call chown operation on the target file.

Please note, that on Unix the rport client runs with unprivileged rights. Changing the ownership of a file and moving a
file to folders with restricted write access requires sudo rights. The user must create sudo rules for that. This allows
a fine-grained control over which folders are accessible for the rport client. Example:

```text
# /etc/sudoers.d/rport-filereception
# The following rule allows the rport client to change the ownership of any file retrieved from the rport server
rport ALL=NOPASSWD: /usr/bin/chown * /var/lib/rport/filepush/*_rport_filepush

# The following rules allows the rport client to move copied files to any folder
rport ALL=NOPASSWD: /usr/bin/mv /var/lib/rport/filepush/*_rport_filepush *
```

## Example for a file upload via curl with all parameters provided

```shell
curl -XPOST \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1...snip...snap' \ 
-F 'upload=@/home/myuser/some-file.txt' \
-F 'client_id=89C4AB76-D90A-555C-85BF-9F8770A3036F' \
-F 'client_id=b4f795ef-718f-4f69-8f6f-b304b38a904f' \
-F 'dest=/Users/hero/Projects/rport/dist/data/client/some-file.txt' \
-F 'force=true' \
-F 'sync=true' \
-F 'mode=0744' \
-F 'user=hero' \ 
-F 'group=staff' \ 
http://localhost:3000/api/v1/files
```

## Tracking upload results

Sending a file to the rport server is performed as a synchronous atomic operation. It means if the transfer has failed,
the whole operation will be rejected. Similarly, if the server cannot perform some file operations e.g. because of
insufficient permissions, the whole file will be discarded.

However, distribution of a large file among multiple clients might take a while so there is no reason for the user to
wait for it. Therefore, the Rport server will respond with success information once the upload operation completes.
This doesn't mean, that the distribution to the given clients was successful too.

If you want to track upload process in real time, you can use a websocket API
[our testing API for Websockets](https://apidoc.openrport.io/master/#operation/WsUploadsGet) similar to commands websocket API.

You can also use our sandbox interface to play with the upload websocket API.
First, enable testing endpoints by setting `enable_ws_test_endpoints` flag to true in the `[server]` section of the
configuration file:

```text
[server]
...
  enable_ws_test_endpoints = true
```

Restart Rport server and go to: `{YOUR_RPORT_ADDRESS}/api/v1/test/uploads/ui`

Put an access token in the corresponding field.

Click Open to start websocket connection.

The websocket API will give you information about all uploads happening after you open a ws connection.

Here is an example payload you're usually getting through the ws upload API:

```json
{
  "client_id": "89C4AB76-D90A-555C-85BF-9F8770A3036F",
  "uuid": "482ae29e-d372-4d21-8cb4-58d75482b7e1",
  "filepath": "/target/file.txt",
  "size": 17118,
  "message": "file successfully copied to destination",
  "status": "success"
}
```

This message says that the client `89C4AB76-D90A-555C-85BF-9F8770A3036F` downloaded the 17118 bytes of a file and placed
it to the destination path `/target/file.txt`. The `uuid` parameter indicates a unique request id, that you also received
once file was uploaded to the server.

Similarly, errors or warnings will be reported in the same format, e.g.:

```json
{
  "client_id": "89C4AB76-D90A-555C-85BF-9F8770A3036F",
  "uuid": "2ea7863b-94ae-4a91-87de-a85bc105ad4e",
  "filepath": "",
  "size": 0,
  "message": "rename /data/filepush/2ea7863b-94ae-4a91-87de-a85bc105ad4e_rport_filepush /etc/lala.txt: permission denied",
  "status": "error"
}
```

This message tells about the failure of a rename/move operation because of permission denied error.

The websocket API will deliver upload results at real time but only those which happened after the websocket connection
was opened as rport server doesn't store upload results for this use case. If you need this information, use audit logs for that.

Uploads for all clients and all requests will be delivered to the same websocket. Server won't close the ws connection
like it happens with the commands websockets.

## File reception restrictions

By default, Rport client can place files anywhere in the file system where the rport OS user is allowed to write files.

That means, that running rport as sudo user, will give write access to the whole filesystem on the client (for Unix only).

However, by default rport won't allow uploading files to the following folders
`['/bin', '/sbin', '/boot', '/usr/bin', '/usr/sbin', '/dev', '/lib*', '/run']` for Unix and
`['C:\Windows\', 'C:\ProgramData']` for Windows

The denied folders list are defined as a list of [glob patterns](https://en.wikipedia.org/wiki/Glob_(programming))
in the `[file-reception] protected` configuration section of an rport client.

The restriction is applied for both target directory or target file path. Here is the list of examples to demonstrate this:

- `/bin` rejects the target paths like `/bin/yourfile.txt`, `/bin/somefile.csv` but not `/etc/bin/yourfile.txt`
- `C:\Windows\*.exe` rejects the target paths like `C:\Windows\myfancy_program.exe`, `C:\Windows
otepad.exe` but not `C:\Windows\myfancy_program.txt` or `C:\Windows
otepad.md`

## File size limit

you can limit the size of uploaded files in bytes by setting `max_filepush_size` parameter in `[server]` section of rport
server configuration. By default, this limit is 10485760 bytes (ca 10,5 MB).

## Disabling file reception on the client

The file reception is enabled on the client by default. If you want to disable it, set `[file-reception] enabled` flag
to false in the client config.
