Overview
Based on the Storj problem:
Terminal 1:
$ ./relay :9021
Terminal 2:
$ ./send localhost:9021 test/olivia.jpg
little-earth-music
Terminal 3:
$ ./receive localhost:9021 little-earth-music test2/
$ diff test/olivia.jpg test2/olivia.jpg
I thought this was a really interesting challenge so I hacked a version together after reading about it on Reddit.
Given that they plan to replace the now-public challenge, it doesn't seem like I'm spoiling anything.
That said, Storj, please reach out if you'd rather this not be on GitHub.
Design
An HTTP server at the relay host:
POST /file
to get a new secret
PUT /file/{secret}
to stream the file to a receiver (paused to start)
GET /file/{secret}
to download an offered file
The recommended filename is suggested via HTTP headers.
Read the docs on go.dev.
Considerations
A solution could be built with just TCP, rather than on top of HTTP.
However, that solution would need to invent some sort of protocol for indicating "sending," "receiving,"
"ready to receive," "proposed filename," and so forth. HTTP provides well-understood mechanisms for this.
In production, it would be straightforward to enable TLS to protect the privacy and data integrity of transfers.
relay.Handler
doesn't care whether it's hosted by an HTTP server with or without TLS; for simplicity, it's without for now.
To make secret codes easier to share via voice,
they're generated by randomly selecting three words in sequence from a dictionary of the most-common
800-or-so English words (eg, little-earth-music
). This provides a search space of a little over half-a-billion
strings, which seems reasonable for this situation.
To provide additional security, the relay server could either implement, or be placed behind,
a rate-limiting service to prevent brute-force attacks over the network.
The server enforces a 10-minute timeout on transfer offers.
It would have been nice to have just two discrete requests: POST /file and GET /file.
However, the complexity of multiplexing the connection wasn't worth the aesthetic benefit.
Local development
Testing
$ go test ./...
$ go test -race ./...
Building
$ make
$ cd dist