"flahspaper" is pronounced "flashpaper". It's flashpaper with Haskell inside.
This blatant ripoff of homage
to go-flashpaper, a
service for one-time links, is an exercise in writing a real-world
program in Haskell. It has diverged from Ryan's excellent one-file
aesthetic, as I wanted to use stack
to generate scaffolding and set
up tests.
I quote: "It is a web service that allows you to upload text snippets or files and generates one time use links to share these things with other people. As soon as the sharing link is accessed, the data is deleted from the web service's memory and the link expires. This means that old links are useless, even if shared somewhere insecure. This can be used to share sensitive data with friends or colleagues." Flahspaper, like go-flashpaper, "has a maximum data retention period of 24 hours."
I commend you to go-flashpaper's excellent README for considerations on running this anywhere other than locally. There are several such considerations.
Locally:
- Install
Haskell Stack
and run
stack setup
- Clone this repo and enter the directory:
git clone https://github.com/bensteinberg/flahspaper.git ; cd flahspaper
stack build
- Get a TLS certificate. Put
certificate.pem
andkey.pem
in the application's directory. stack exec flahspaper
- Visit your service at https://localhost:8443/
Test with stack test
or stack test --coverage
.
Writing this program has been strangely like doing Haskell exercises in a class or book, in that getting things to work is precisely a matter of following the types.
This project contains a number of features commonly needed by
real-world programs, for many of which there are various possible
solutions. For the web server, I
chose WAI
and Warp. I'm generating
randomness
with Crypto.Random.DRBG,
though I'm making a new seed every time, which may not be optimal or
idiomatic. In order to remove old secrets, we need concurrency,
using forkIO
from Control.Concurrent (in base) and a TVar
from
Control.Concurrent.STM. To
know when a secret is old, we need time,
from Data.Time's
getCurrentTime
and diffUTCTime
. I
use
Text.InterpolatedString.Perl6 instead
of
Text.RawString.QQ for
quasiquoting in order to get string interpolation. For testing the
running application, I'm using wreq
as a web
client,
Text.HTML.TagSoup for
HTML parsing,
and System.IO.Temp
for temporary files.
(This State of the Haskell ecosystem does a nice job of showing the variety of approaches.)
If swap is turned off, secrets should only be kept in RAM. Presumably that's safe, as anyone who can see your memory already owns you. The question is, does writing a TVar actually overwrite the data in memory? What kind of garbage collection does Haskell do? TODO: investigate, perform the experiment.
Although this program no longer uses constants like go-flashpaper does (in order to make testing easier), it does pass the values around in an options object, so TODO: make a context/environment, maybe with ReaderT. Maybe also add the random Gen to the context?