2023-03-29 19:07:48 +02:00
[](https://github.com/tlinden/ephemerup/actions)
[](https://github.com/tlinden/ephemerup/blob/master/LICENSE)
[](https://goreportcard.com/report/github.com/tlinden/ephemerup)
2023-03-21 19:41:24 +01:00
# ephemerup
2023-03-19 17:09:13 +01:00
Simple standalone file upload server with expiration and commandline client.
## Introduction
2023-03-21 19:41:24 +01:00
**ephemerup** is a simple standalone file server where every uploaded
2023-03-19 17:09:13 +01:00
file expires sooner or later. The server provides a RESTful API and
can be used easily with the commandline client `upctl` .
The idea is to provide a way to quickly exchange files between parties
when no other way is available and the files themselfes are not
important enough to keep them around. Think of this szenario: you're
working for the network departement and there's a problem with your
routing. Tech support asks you to create a network trace and send it
to them. But you can't because the trace file is too large and
2023-03-21 19:41:24 +01:00
sensitive to be sent by email. This is where **ephemerup ** comes to
2023-03-19 17:09:13 +01:00
the rescue.
You upload the file, send the download url to the other party and -
assuming you've utilized the defaults - when they download it, it is
being deleted immediately from the server. But you can also set an
expire time, say 5 days or something like that.
2023-03-21 19:41:24 +01:00
The download urls generated by **ephemerup ** consist of a unique
2023-03-19 17:09:13 +01:00
onetime hash, so they are somewhat confident. However, if you're
uploading really sensitive data, you better encrypt it.
2023-03-21 19:41:24 +01:00
**ephemerup** also supports something we call an API Context. There
2023-03-19 17:09:13 +01:00
can be many such API contexts. Each of these has an associated token,
which has to be used by legitimate clients to authenticate and
authorize. A user can only manage uploads within that context. Think
"tenant" if you will.
## Demo

2023-03-17 19:38:53 +01:00
2023-03-19 12:33:15 +01:00
## Features
- RESTful API
- Authentication and Authorization through bearer api token
- multiple tenants supported (tenant == api context)
- Each upload gets its own unique id
- download uri is public, no api required, it is intended for end users
- uploads may consist of one or multiple files
- zipped automatically
- uploads expire, either as soon as it gets downloaded or when a timer runs out
- the command line client uses the api
- configuration using HCL language
- docker container build available
- the server supports config by config file, environment variables or flags
- restrictive defaults
2023-03-19 17:09:13 +01:00
## Installation
Since the software is currently being developed, there are no binary
releases available yet. You'll need a go build environment. Just run
`make` to build everything.
There's a `Dockerfile` available for the server so you can build and run it using docker:
```
make buildimage
2023-03-21 19:41:24 +01:00
docker-compose run ephemerup
2023-03-19 17:09:13 +01:00
```
Then use the client to test it.
2023-03-17 19:38:53 +01:00
## Server Usage
```
2023-03-21 19:41:24 +01:00
ephemerupd -h
2023-03-17 19:38:53 +01:00
--apikeys strings Api key[s] to allow access
-a, --apiprefix string API endpoint path (default "/api")
2023-03-21 19:41:24 +01:00
-n, --appname string App name to say hi as (default "ephemerupd v0.0.1")
2023-03-17 19:38:53 +01:00
-b, --bodylimit int Max allowed upload size in bytes (default 10250000000)
-c, --config string custom config file
-D, --dbfile string Bold database file to use (default "/tmp/uploads.db")
-d, --debug Enable debugging
2023-03-19 12:33:15 +01:00
--frontpage string Content or filename to be displayed on / in case someone visits (default "welcome to upload api, use /api enpoint!")
2023-03-17 19:38:53 +01:00
-4, --ipv4 Only listen on ipv4
-6, --ipv6 Only listen on ipv6
-l, --listen string listen to custom ip:port (use [ip]:port for ipv6) (default ":8080")
-p, --prefork Prefork server threads
-s, --storagedir string storage directory for uploaded files (default "/tmp")
--super string The API Context which has permissions on all contexts
-u, --url string HTTP endpoint w/o path
-v, --version Print program version
```
2023-03-21 19:41:24 +01:00
All flags can be set using environment variables, prefix the flag with `EPHEMERUPD_` and uppercase it, eg:
2023-03-19 12:33:15 +01:00
```
2023-03-21 19:41:24 +01:00
EPHEMERUPD_LISTEN=:8080
2023-03-19 12:33:15 +01:00
```
In addition it is possible to set api contexts using env vars (otherwise only possible using the config file):
```
2023-03-21 19:41:24 +01:00
EPHEMERUPD_CONTEXT_SUPPORT="support:tymag-fycyh-gymof-dysuf-doseb-puxyx"
EPHEMERUPD_CONTEXT_FOOBAR="foobar:U3VuIE1hciAxOSAxMjoyNTo1NyBQTSBDRVQgMjAyMwo"
2023-03-19 12:33:15 +01:00
```
Configuration can also be done using a config file (searched in the following locations):
2023-03-21 19:41:24 +01:00
- `/etc/ephemerupd.hcl`
- `/usr/local/etc/ephemerupd.hcl`
- `~/.config/ephemerupd/ephemerupd.hcl`
- `~/.ephemerupd`
- `$(pwd)/ephemerupd.hcl`
2023-03-19 12:33:15 +01:00
Or using the flag `-c` . Sample config file:
```
listen = ":8080"
bodylimit = 10000
apicontext = [
{
context = "root"
key = "0fddbff5d8010f81cd28a7d77f3e38981b13d6164c2fd6e1c3f60a4287630c37",
},
{
context = "foo",
key = "970b391f22f515d96b3e9b86a2c62c627968828e47b356994d2e583188b4190a"
}
]
#url = "https://sokrates.daemon.de"
# this is the root context with all permissions
super = "root"
```
2023-03-19 17:09:13 +01:00
### Server endpoint
The server serves the API under the following endpoint:
2023-03-19 17:11:32 +01:00
`http://SERVERNAME[:PORT]/api/v1` where SERVERNAME[:PORT] is the
2023-03-19 17:09:13 +01:00
argument to the `-l` commandline argument or the config option
2023-03-21 19:41:24 +01:00
`listen` or the environment variable `EPHEMERUPD_LISTEN` .
2023-03-19 17:09:13 +01:00
By default the server listens on any interface ip4 and ipv6 on TCP
port 8080. You can specify a server name or an ipaddress and a
port. The server can be configured to run on ipv6 (or ipv4) only using
the `-4` respective the `-6` commandline flags.
It does not support TLS at the moment. Use a nginx reverse proxy in
front of it.
2023-03-21 19:41:24 +01:00
### Server REST API
Every endpoint returns a JSON object. Each returned object contains the data requested plus:
- success: true or false
- code: HTTP Response Code
- message: error message, if success==false
#### Endpoints
| HTTP Method | Endpoint | Parameters | Input | Returns | Description |
|-------------|-----------------------|---------------------|----------------------------|---------------------------------------|-----------------------------------------------|
| GET | /v1/uploads | apicontext,q,expire | | List of upload objects | list upload objects |
| POST | /v1/uploads | | multipart-formdata file[s] | List of 1 upload object if successful | upload a file and create a new upload object |
| GET | /v1/uploads/{id} | | | List of 1 upload object if successful | list one specific upload object matching {id} |
| DELETE | /v1/uploads/{id} | | | Noting | delete an upload object identified by {id} |
| PUT | /v1/uploads/{id} | | JSON upload object | List of 1 upload object if successful | modify an upload object identified by {id} |
| GET | /v1/uploads/{id}/file | | | File download | Download the file associated with the object |
| GET | /v1/forms | apicontext,q,expire | | List of form objects | list form objects |
| POST | /v1/forms | | JSON form object | List of 1 form object if successful | create a new form object |
| GET | /v1/forms/{id} | | | List of 1 form object if successful | list one specific form object matching {id} |
| DELETE | /v1/forms/{id} | | | Noting | delete an form object identified by {id} |
| PUT | /v1/forms/{id} | | JSON form object | List of 1 form object if successful | modify an form object identified by {id} |
#### Consumer URLs
The following endpoints are no API urls, but accessed directly by consumers using their browser or `wget` etc:
| URL | Description |
|-------------------------|---------------------------------------------------------|
| / | Display a short welcome message, can be customized |
| /download/{id}[/{file}] | Download link returned after an upload has been created |
| /form/{id} | Upload form for consumer |
#### API Objects
Response:
| Field | Data Type | Description |
|---------|-----------|---------------------------------------|
| success | bool | if true the request was successful |
| code | int | HTTP response code |
| message | string | error message, if any |
| uploads | array | list of upload objects (may be empty) |
| forms | array | list of form objects (may be empty) |
Upload:
| Field | Data Type | Description |
|----------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| id | string | unique identifier for the object |
| expire | string | when the upload has to expire, either "asap" or a Duration using numbers and the letters d,h,m,s (days,hours,minutes,seconds), e.g. 2d4h30m |
| file | string | filename after uploading, this is what a consumer gets when downloading it |
| members | array of strings | list of the original filenames |
| created | timestamp | time of object creation |
| context | string | the API context the upload has been created under |
| url | string | the download URL |
Form:
| Field | Data Type | Description |
|-------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------|
| id | string | unique identifier for the object |
| expire | string | when the form has to expire, either "asap" or a Duration using numbers and the letters d,h,m,s (days,hours,minutes,seconds), e.g. 2d4h30m |
| description | string | arbitrary description, shown on the form page |
| context | string | the API context the form has been created under and the uploaded files will be created on |
| notify | string | email address of the form creator, who gets an email once the consumer has uploaded files using the form |
| created | timestamp | time of object creation |
| url | string | the form URL |
Note: if the expire field for a form is not set or set to "asap" only
1 upload object can be created from it. However, if a duration has
been specified, the form can be used multiple times and thus creates
multiple upload objects.
2023-03-17 19:38:53 +01:00
## Client Usage
```
upctl
Error: No command specified!
Usage:
upctl [options] [flags]
upctl [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
delete Delete an upload
describe Describe an upload.
download Download a file.
help Help about any command
list List uploads
upload Upload files
Flags:
-a, --apikey string Api key to use
-c, --config string custom config file
-d, --debug Enable debugging
-p, --endpoint string upload api endpoint url (default "http://localhost:8080/api/v1")
-h, --help help for upctl
-r, --retries int How often shall we retry to access our endpoint (default 3)
-v, --version Print program version
Use "upctl [command] --help" for more information about a command.
```
2023-03-19 12:33:15 +01:00
The client must be configured using a config file. The following locations are searched for it:
- `$(pwd)/upctl.hcl`
- `~/.config/upctl/upctl.hcl`
Sample config file for a client:
```
endpoint = "http://localhost:8080/api/v1"
apikey = "970b391f22f515d96b3e9b86a2c62c627968828e47b356994d2e583188b4190a"
```
2023-03-21 19:41:24 +01:00
The `endpoint` is the **ephemerup ** server running somewhere and the
2023-03-19 17:09:13 +01:00
`apikey` is the token you got from the server operator..
2023-03-17 19:38:53 +01:00
2023-02-17 13:22:29 +01:00
## TODO
- also serve a html upload page
2023-03-13 18:48:38 +01:00
- add metrics (as in https://github.com/ansrivas/fiberprometheus)
2023-03-09 20:24:20 +01:00
- do not manually generate output urls, use fiber.GetRoute()
2023-03-13 18:48:38 +01:00
- upd: https://docs.gofiber.io/guide/error-handling/ to always use json output
- upctl: get rid of HandleResponse(), used only once anyway
2023-03-17 19:38:53 +01:00
- add form so that public users can upload
2023-03-20 14:34:39 +01:00
- use Writer for output.go so we can unit test the stuff in there
2023-03-29 19:04:01 +02:00
- add (default by time!) sorting to list outputs, and add sort flag
2023-03-19 12:33:15 +01:00
2023-02-28 19:05:09 +01:00
2023-03-07 20:06:13 +01:00
## BUGS
### upctl HTTP 413 weird behavior
- with -d reports correctly the 413, w/o it, it reports the timeout before.
2023-02-28 19:05:09 +01:00
## curl commands
### upload
```
curl -X POST localhost:8080/api/putfile -F "upload[]=@xxx " -F "upload[]=@yyy " -H "Content-Type: multipart/form-data"
```
### download
```
curl -O http://localhost:8080/api/v1/file/388f41f4-3f0d-41e1-a022-9132c0e9e16f/2023-02-28-18-33-xxx
```
### delete
```
curl -X DELETE http://localhost:8080/api/v1/file/388f41f4-3f0d-41e1-a022-9132c0e9e16f/
curl -X DELETE http://localhost:8080/api/v1/file/?id=388f41f4-3f0d-41e1-a022-9132c0e9e16f/
curl -X DELETE -H "Accept: application/json" -d '{"id":"$id"}' http://localhost:8080/api/v1/file/
```