4 Coquelicot is a "one-click" file sharing web application with a specific
5 focus on protecting users' privacy.
7 Basic principle: users can upload a file to the server, in return they
8 get a unique URL which can be shared with others in order to download
11 Coquelicot aims to protect, to some extent, users and system
12 administrators from disclosure of the files exchanged from passive and
13 not so active attackers.
18 * Support for different authentication methods
20 In order to prevent random Internet users to eat bandwidth and
21 disk space, Coquelicot limits upload to authenticated users.
22 It currently ships with two authentication mechanisms:
24 - "simplepass": users will need to provide a global, pre-shared,
26 - "imap": users will need to provide a login and a password,
27 those credentials will be used to authenticate against an existing
30 It is possible to integrate more authentication mechanisms by
31 implementing a single method, some Javascript, and a template partial
32 to render the common fields. For more information have a look at the
35 * Mandatory expiration
37 When uploading, a time limit has to be specified. The file will be
38 unavailable once this limit has been reached.
40 During a configurable period of time, trying to download the file
41 will return a page saying "too late" instead of "not found".
43 * Support for one-time download
45 An user might want to allow exactly _one_ download of a file, to more
46 closely replace an email attachment. The file will be removed after
47 the first complete download and concurrent downloads are prevented.
51 If the web server tracks upload progress, users having javascript
52 enabled will see a nice progress bar during the file upload.
56 The application works fine without javascript or CSS.
58 * Download URL are hand-writing compatible
60 URLs generated to download files uses the Base32 character set. This
61 set is specifically designed to overcome misread of 'l', '1', '0' and
62 'O' characters. Coquelicot will automatically convert case and
63 ambiguous characters to facilitate URL exchanges through
66 * Files are stored encrypted on the server
68 While being uploaded, files are written to the disk using symmetric
69 encryption. The encryption key is _not_ stored directly by
70 Coquelicot. It is either generated randomly and given as part of the
71 download URL, or specified by the uploader.
73 * Download can be protected by a password
75 When uploading, a password can be specified which will be used as
76 the encryption key. In order to download the file, the password
77 must be entered through in a POST'ed form, preventing the password
78 from appearing in the server logs.
80 * Files are stored with a random name
82 To prevent disclosure of the shared file name, it is stored encrypted
83 together with the file content. On the server, this encrypted file is
84 stored with a random name.
86 * Download URLs do not reflect stored file names
88 The random names given in download URLs do not map directly to file
89 names on the server. This prevent server logs from giving a direct
90 mapping to the shared files.
92 * File content is zero'ed before removal
94 When a file has expired, it is removed from the server. In order
95 to make it harder to retrieve its content through filesystem
96 analysis, it is filled with zeros first.
101 Coquelicot is written in Ruby using the Sinatra web framework. Due to
102 reasons detailed below, it needs to be run with the Rainbows! web
103 server. The later should probably be made accessible through a reverse
108 Coquelicot uses Bundler to manage its dependency. To install Bundler on
109 Debian, please issue:
111 # apt-get install rubygems
112 $ gem install bundler
114 Once Bundler is available, please issue:
116 $ bundle install --deployment --binstubs
118 Then, to start Coquelicot use:
120 $ bin/rainbows -c rainbows.conf -E none config.ru
122 Coquelicot is intended to be run on a fully encrypted system and
123 accessible only through HTTPS. To configure Apache as a reverse proxy,
124 you will need to add the following directives:
126 ProxyPass / http://127.0.0.1:51161/
127 SetEnv proxy-sendchunks 1
128 RequestHeader set X-Forwarded-SSL "on"
130 You can also run Coquelicot with mod_passenger, Mongrel, Thin or any
131 Rack compatible webserver, but please read below about buffered input.
135 By default Coquelicot is configured to authenticate with the
136 "simplepass" mechanism and some other reasonable defaults.
138 It is possible to overwrite these settings from a configuration file
139 named `settings.yml` that will be used if it is present in the `conf`
140 directory of the application.
142 All available settings with their default values are documented in
143 `conf/settings-default.yml`.
145 Further settings example:
147 * `conf/settings-simplepass.yml`: shows how to change the default
148 password for the "simplepass" mechanism.
150 * `conf/settings-imap.yml`: necessary configuration for the "imap"
151 authentication mechanism.
153 You can copy one of these examples to `conf/settings.yml` and adjust
154 them according to your environment.
156 ### Garbage collection
158 To cleanup files automatically when they expired, coquelicot comes with
159 a cleanup script, that does the garbage collection for you. The easiest
160 way is to add `ext/coquelicot_gc.rb` as a cron job that runs every 5
163 ### Migrate from Jyraphe
165 [Jyraphe] is another free software web file sharing application.
166 Coquelicot provides a migration script to import Jyraphe 0.5
167 repositories in `tools/migrate_jyraphe.rb`.
169 [Jyraphe]: http://home.gna.org/jyraphe/
171 Test, development and extensions
172 --------------------------------
174 Coquelicot is written in Ruby and should be quite easy to improve for
175 anyone a little bit familiar with the Sinatra web framework. It is
176 mostly written using Behaviour Driven Development, making the test suite
177 a fine net to hack in confidence. So please go ahead!
179 ### Setup a work environment
181 As Coquelicot uses Bundle, the first step to work on Coquelicot
182 is installing the proper dependencies by issuing:
188 Coquelicot test suite is written using RSpec. Running the test suite is
189 just a matter of typing:
193 Running a test server can be done with:
195 bundle exec rackup config-development.ru
197 To update the translation source files, use:
199 bundle exec rake updatepo
201 This will update `po/coquelicot.pot` and merge the new strings in the various
202 `po/*/coquelicot.po` files.
204 ### Authentication mechanisms
206 The authentication part of Coquelicot has been made modular. Adding a
207 new authentication mechanism should be fairly straightforward.
209 New authentication mechanism needs to provide the following 3 files,
210 with the following responsabilities:
212 * `lib/coquelicot/auth/<METHOD>.rb`:
214 A class implementing the actual authentication. This class must
215 implement an `authenticate` method. It will receive the form fields
216 as usual (params). This method should either return true if upload
219 * `public/javascripts/coquelicot.auth.<METHOD>.js:`
221 This file should define 'authentication' as an object with the
224 - `getData()`: returns an object of all the necessary data
225 to authenticate on the app side. Keys should have the same name
226 as the input fields used to authenticate without Javascript.
227 - `focus()`: set the focus on the first authentication form field.
228 - (optional) `handleSuccess()`: arbitrary action upon successful
229 authentication. This is called after the livebox is closed.
230 - (optional) `handleReject()`: arbitrary action when access
231 get rejected. One can reset authentication fields after a failed
233 - (optional) `handleFailure()`: arbitrary action when there was
234 a problem in the authentication procedure.
236 * `views/auth/<METHOD>.haml`:
238 Render the necessary form fields that will be used for
241 The authentication method can be set in the application settings
242 including mandatory options for this method.
244 ### Watch for buffered inputs!
246 Coquelicot is written in Ruby using Sinatra. Sinatra is based on the
247 Rack webserver interface. Rack specification mandates that applications
248 must be able to seek and rewind freely in the request content.
250 Request data are always received as a stream through the network. So in
251 order to comply with the specification, webservers implementing Rack will
252 either buffer the input in memory (Webrick) or in a temporary file
253 (Thin, Passenger or Mongrel).
255 On top of that, when parsing `multipart/form-data` POST content,
256 `Rack::Request` (used by Sinatra) will create a new temporary file for
257 each files in the POST request.
259 For the specific needs of Coquelicot, those behaviours will prevent
260 users from uploading large files (if `/tmp` is in memory) or will be a
261 breach of privacy, as a clear text version will be written to disk.
263 To overcome these limitations, Coquelicot first uses a specific feature
264 of the Rainbows! webserver of streaming its input directly to
265 applications, and second bypass `Rack::Request` to directly handle
266 POST content. Usage of any other Rack webserver is strongly discouraged
267 and should be restricted to development and testing.
269 ### Implementation details
271 Common application code lies in `Coquelicot::Application`. Except for
272 one specific (and important) type of requests, namely `POST /update`.
273 These requests are handled directly at bare Rack level by
274 `Coquelicot::Rack::Upload`.
276 This allows to work directly with POST data as the browser is sending
277 them, so we can directly stream the uploaded file to our encrypted
280 The POST data must be in a very specific order, as we need to handle
281 authentication, and various options prior to start recording the file
282 content. Thanks to the W3C, the [HTML specification] states that parts
283 of the POST data must be delivered in the same order the controls
284 appears in the `<form/>` container.
286 `Coquelicot::Rack::Multipart` expose a simple DSL to parse the fields as
287 they are delivered. The later is used by `Coquelicot::Rack::Upload` to
288 perform its logic pretty nicely.
290 [HTML specification]: http://www.w3.org/TR/html4/interact/forms.html
295 * More flexible expiration
297 It might be interesting to also offer a calendar for specifying
298 an exact date after which the file will be unavailable.
300 * Hide file size (padding)
302 There is currently a real close mapping from original file size to
303 stored file size. Original file size will also be recorded in server
304 logs. Padding could be used to improve this situation.
308 Most Ruby stuff is installed using Gem, so Coquelicot should be one.
312 A Debian package would be nice to spread Coquelicot setups.
317 Files are stored in the directory specified by the 'depot_path' setting.
318 One file in Coquelicot is actually stored in two files: one for metadata and
319 one for the file content.
323 The format is the following:
327 Salt: <8 bytes stored as Base64>
328 Expire-at: <expiration time in seconds since epoch>
332 Encryption is done using OpenSSL. Cipher is AES-256-CBC with key and IV
333 created using the `pbkdf2_hmac_sha1()` implementation of PKCS5. The later
334 is fed using the former *Salt* and the given passphrase, using 2000
337 Once decrypted, the metadata have the following format:
340 Created-at: <upload time in seconds since epoch>
341 Filename: "<original file name>"
342 Content-Type: "<MIME type>"
343 Length: <content length is bytes>
344 One-time-only: <true|false>
346 Headers must be parseable using the YAML standard.
350 The content file contains the stored file in encrypted form. Encryption is done
351 with the same algorithm and keys as the encrypted metadata (see above).
353 The file name of the content file is the same as the one for metada, with an
354 added suffix of '.content'. For example, if the metadata file name is
355 `mqeb4pfcru2ymq3e6se7`, the associated content file will be
356 `mqeb4pfcru2ymq3e6se7.content`.
360 Both the content file and the metadata file are truncated to zero length when
365 In order to map download URLs to file name, a simple text file ".links"
366 is used. It contains a line for each file in the form:
368 <URL name> <metadata file name>
373 : Current version described above.
376 : File content is in the same file as the metadata. Content is put in the
377 after the metadata and an extra "--- \n".
382 Coquelicot © 2010-2012 potager.org <jardiniers@potager.org>
383 © 2011 mh / immerda.ch <mh+coquelicot@immerda.ch>
385 Coquelicot is distributed under the [GNU Affero General Public License]
386 version 3 or (at your option) any later version.
388 Background image (`public/images/background.jpg`) derived from:
389 [“coquelicot”] © 2008 Jean-Louis Zimmermann
390 Licensed under [Creative Commons Attributions 2.0 Generic]
392 [“coquelicot”]: https://secure.flickr.com/photos/jeanlouis_zimmermann/2478019744/
393 [GNU Affero General Public License]: http://www.gnu.org/licenses/agpl.txt
394 [Creative Commons Attributions 2.0 Generic]: https://creativecommons.org/licenses/by/2.0/deed