aboutsummaryrefslogtreecommitdiff
path: root/README
blob: 0d2c189e9253426912c600b9b70fc162f6162463 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
Fshare is a simple Python-based HTTP server for personal ad-hoc file sharing. You upload files in the form of HTTP PUT
or POST requests and it returns a URL through which the file contents can be retrieved.

Fshare has two modes of operation: private (the default) and public. In the private mode, the generated URLs are
a HMAC computed from server's private key (which it generates on the first run) and the file contents. They should thus
be unguessable as long as the server's key remains secret, and so can be used for sharing confidential information -
only someone in possession of the URL can access the data.

In the public mode (activated by the -P switch), the generated URLs are short and easy to remember - and therefore also
easy to guess. This mode is useful for sharing non-sensitive data.

Fshare works only with plain HTTP and does no limiting or authentication - anyone can upload data as they wish. In a
typical setup it should be deployed behind a gateway such as Nginx, that will handle TLS, authentication, request size
limits, etc.

Fshare should be run as an executable Python script. It takes two mandatory arguments - the state dir and the data dir.
The state dir contains server runtime data (such as the abovementioned private key), the data dir will contain the
actual uploaded files.

The data from a PUT/POST request is stored exactly as it was received. E.g. using curl one can upload files with
 $ curl --data-binary '@<filename>' https://<server location>/pic.jpg
The server will reply with a URL like
 https://<server location>/081c5e45316f0c65e945edc4622a8173451d4a808648f5e310ced8a7e079ffdf/pic.jpg
in the private mode or
 https://<server location>/f2.jpg
in the public mode. The data can be retrieved with a HTTP GET request for this URL.

In GET requests, fshare only looks at the basename (i.e. stripping the extension, if any) of the first path component of
the request location. You can thus add/change the extenion, add further arbitrary path components, or otherwise modify
it as you wish. As long as the first component is unchanged, the same data will be returned.

In PUT/POST requests, the request location is appended to the generated URL (in the public mode, only the extension of
the last path component is used). As per the previous paragraph, this is done for convenience only and may be changed at
will. Requests with an empty location will work as well, then the returned URL will be just the HMAC in the private mode
and have no extension in the public mode.

Fshare is distributed under the GNU AGPL licence.

Example Nginx config
--------------------
upstream fshare_py {
    # host/port of the fshare.py process
    server [::1]:5400;
}

server {
    # network config
    listen [::]:443 ssl;
    server_name fshare.example.com;

    # server's TLS cert+key
    ssl_certificate     <path_to_cert>;
    ssl_certificate_key <path_to_key>;

    # source authentication with TLS client certificates
    ssl_client_certificate <path_to_client_CA>;
    ssl_verify_client optional;

    # define parameters for communicating with upstream
    # enable chunked transfers
    proxy_http_version        1.1;
    proxy_buffering           off;
    proxy_request_buffering   off;
    # finish the upload even if the client does not bother waiting for our
    # response
    proxy_ignore_client_abort on;

    # only these methods are allowed
    if ($request_method !~ ^(GET|POST|PUT|DELETE)$) {
        return 405; # Method Not Allowed
    }

    # privileged operation requested
    if ($request_method ~ ^(POST|PUT|DELETE)$) {
        set $priv_op "R";
    }

    # privileged operations are forbidden unless client cert has validated
    # successfully
    if ($ssl_client_verify != "SUCCESS") {
        set $priv_op "${priv_op}F";
    }

    if ($priv_op = "RF") {
        return 401; # unauthorized
    }

    location / {
        proxy_pass http://fshare_py;
        proxy_set_header Host $host;
    }
}