== link:index.html[Index] -> link:modules.html[Modules] -> link:modules_handlers.html[Handlers] Handler: Hidden Downloads ------------------------- The **Hidden Downloads** handler implements secure download mechanisms. This module allows to handle temporal URLs to serve hidden files. [[parameters]] Parameters ~~~~~~~~~~ [cols="20%,10%,70%",options="header"] |================================================================== |Parameters |Type |Description |`secret` |String |Required. Share secret between the handler and the script. |`timeout` |number |Optional. How long - in seconds - the URL will be valid. |================================================================== [[technical]] Technical Description ~~~~~~~~~~~~~~~~~~~~~ The idea behind this handler is plain and simple. It will only serve a file if the URL has been generated by a dynamic execution script that you've previously written. If the script allows the user to access the file, it will generate a special encoded URL that Cherokee will handle through the **Hidden Downloads** module. If the URL is invalid, is modified, or expires, Cherokee will not serve the file. The encoding scheme is quite straightforward. It is basically the result of MD5-hash of: a shared secret string between Cherokee and the script, the relative path to the requested file (relative to the rule document root), and the current time: '/' HEX (MD5 (Secret + URL + HEX(time))) '/' HEX(time) '/' URL Here you have a reference implementation in Python: --------------------------------- def secure_download (prefix, url, secret): import time, hashlib t = '%08x' % (time.time()) return "/%s/%s" % (hashlib.md5(secret + url + t).hexdigest(), t + url) --------------------------------- The same function written in PHP would be: --------------------------------- function secure_download ($prefix, $url, $secret) { $time = sprintf('%08x', time()); return "$prefix/".md5($secret.$url.$time)."/$time$url"; } --------------------------------- It is important to notice that the URLs are only valid for a period of time. If an URL expires, the server will return an error instead of the file contents. By default URLs last 60 seconds. NOTE: Please note that both sample implementations count on having an URL that starts with `/`. [[examples]] Examples ~~~~~~~~ Lets imagine you have a few ISO files that you want to distribute among a certain group of people. First, and most importantly, the ISO files ought to be outside of the WWW directory root; otherwise, anybody would be able to download them. Let's imagine those ISO files are located under: `/mnt/isos/`, and the server document root is located in `/var/www/`. Now it is time to configure the `/downloads` web directory, so it is handled by **Hidden Downloads**. We set a shared secret string (`Abracadabra`), and the document root where the real ISO files are located (`/mnt/isos`): .Configuration for directory /downloads [cols="50%,50%"] |================================================================== |Handler | `Hidden Downloads` |Document Root| /mnt/isos |Secret | Abracadabra |================================================================== .Hidden downloads configuration image::media/images/admin_handler_secdownload.png[Hidden Downloads configuration] To summarize, its a four step process: - Configure a Directory rule. Let's say: /downloads - Set the rule to use "Hidden Downloads" handler - Set the Document Root directory (this is important!) - Set the Secret string Next step is to write the logic that will decide what is the user given access to. For instance, check out this Pyton example: --------------------------------- import time try: from hashlib import md5 except ImportError: from md5 import md5 SECRET = "Abracadabra" DIR = "downloads" def secure_download (url, secret): t = "%08x"%(time.time()) return '/'+ DIR +'/'+ md5(secret + url + t).hexdigest() +'/'+ t + url # Example request file = "test.txt" host = "localhost" hidden_url = secure_download('/%s'%(file), SECRET) print "/%(DIR)s/%(file)s -> http://%(host)s%(hidden_url)s" %(locals()) --------------------------------- According to this example, if a user tries to access `/bar/foo/example.iso` and access is granted, working URL such as this would be provided: /downloads/ac003ebbb88c4fc9a75687223c72c6da/49b40a43/bar/foo/example.iso Since the `/downloads` web directory is configured with this "Hidden Downloads" handler, it will check the URL to ensure that it is valid and has not expired. Then, if everything was right, it would send the `/mnt/isos/bar/foo/example.iso` file to the client.