The Application
The Django Application
Business logic and models
Basic code is laid out swiftly, with a directed, acyclic graph (DAG) of model dependencies as laid out here:
+-----------+ +--------------+ +------------+ +----------+ | Shareable | | DownloadCode | | Activation | | Download | |-----------|<-|--------------|<-|------------|<-|----------| | file | | intent | | email | | datetime | +-----------+ +--------------+ +------------+ +----------+
As you can interpret from this graph, we upload some original file (which we call a Shareable), then create a DownloadCode which points to such a Shareable and stores some intent. We can share such DownloadCodes with whomever we please - obtainers of the code can then state their email address by activating a code and will retrieve the final download link through mail.
As laid out before, the core "logic" of the app is hashing combinations of arbitrary objects. Hashing itself is a basic cryptographic function, so all we need to care about is what we want to hash, how we do it and where we will store those hashes.
After quick consideration we will agree that hashing the file's contents brings vast advantages over hashing for example hashing file names and we will quickly feel gratitude towards the ease at which Python allows concatenating arbitrary arrays of bytes (which can of course also represent strings).
If you care about the actual inner workings, have a look at utils.py and models.py.
URLs and views
The core application will only serve two or three views, depending on how you count. The first one shows a form and asks for an email address (the activation view) and - if successfully transmitted - lets the user know that the final download link will be sent through email. The other view simply parses a download link and serves the Shareable (with its original filename).
For completeness' sake we'll add a static view that serves a simple, informative note for the root of the application ('/').
CSRF and Testing
Django - being a framework to build classic Web 2.0 applications, where the default use-case is for people to log in, and only then be allowed to send POST requests - is built upon all that is necessary to prevent malicious interference with user's traffic. Since our application differs from that scenario, we have to omit CSRF checks for the public-facing, POST request parsing view.
As we go along writing functionality, stumble upon unexpected behavior and find first bugs, we write test cases for all that seems eligible for (unit-)testing, inside its own tests.py file.
As soon as we get basic functionality working we craft a simple end-to-end test, so we can ensure further development does not regress functionality.