-Coquelicot
-==========
+About “Coquelicot”
+==================
-Coquelicot is a "one-click" file sharing web application with specific
-thoughts on protecting users privacy.
+Coquelicot is a "one-click" file sharing web application with a specific
+focus on protecting users' privacy.
-Basic principle: users can upload a file to the server, it return they
-get a unique URL which can be shared to others in order to download the
-file.
+Basic principle: users can upload a file to the server, in return they
+get a unique URL which can be shared with others in order to download
+the file.
-Coquelicot aims to protect, to some extents, users and system
-administrators from disclosure of the files exchanged from passive
-and not so active attackers.
+Coquelicot aims to protect, to some extent, users and system
+administrators from disclosure of the files exchanged from passive and
+not so active attackers.
Features
--------
- * Uploading a file is protected by a common password
+ * Support for different authentication methods
- In order to prevent random Internet users to eat bandwidth and disk
- space, uploading a file to share is protected by a common password.
+ In order to prevent random Internet users to eat bandwidth and
+ disk space, Coquelicot limits upload to authenticated users.
+ It currently ships with two authentication mechanisms:
+
+ - "simplepass": users will need to provide a global, pre-shared,
+ password;
+ - "imap": users will need to provide a login and a password,
+ those credentials will be used to authenticate against an existing
+ IMAP server.
+
+ It is possible to integrate more authentication mechanisms by
+ implementing a single method, some Javascript, and a template partial
+ to render the common fields. For more information have a look at the
+ notes below.
* Mandatory expiration
When uploading, a time limit has to be specified. The file will be
unavailable once this limit has been reached.
+ During a configurable period of time, trying to download the file
+ will return a page saying "too late" instead of "not found".
+
+ * Support for one-time download
+
+ An user might want to allow exactly _one_ download of a file, to more
+ closely replace an email attachment. The file will be removed after
+ the first complete download and concurrent downloads are prevented.
+
* Upload progress bar
If the web server tracks upload progress, users having javascript
* Files are stored encrypted on the server
- Upon upload, files are written to the disk using symmetric
+ While being uploaded, files are written to the disk using symmetric
encryption. The encryption key is _not_ stored directly by
Coquelicot. It is either generated randomly and given as part of the
download URL, or specified by the uploader.
When a file has expired, it is removed from the server. In order
to make it harder to retrieve its content through filesystem
- analysis, it is filled with zeroes first.
+ analysis, it is filled with zeros first.
-Setup
------
+Installation
+------------
-Coquelicot is written in Ruby using the Sinatra web framework.
+Coquelicot is written in Ruby using the Sinatra web framework. Due to
+reasons detailed below, it needs to be run with the Rainbows! web
+server. The later should probably be made accessible through a reverse
+proxy.
-On Debian, one can fulfill its dependencies by issueing:
+### Initial setup
- apt-get install libsinatra-ruby1.8 libopenssl-ruby1.8 \
- libhaml-ruby1.8 liblockfile-ruby
+Coquelicot uses Bundler to manage its dependency. To install Bundler on
+Debian, please issue:
-Then you need to figure out the best way to host a Rack application
-depending on your setup. *evil grin*
+ # apt-get install rubygems
+ $ gem install bundler
-Test suite
-----------
+Once Bundler is available, please issue:
-Coquelicot test suite is written using RSpec.
+ $ bundle install --deployment --binstubs
-On Debian, you will need those extra packages:
+Then, to start Coquelicot use:
- apt-get install librspec-ruby1.8 libhpricot-ruby1.8
+ $ bin/rackup config.ru
-You will also need the unpackaged gems "timecop" and "rack-test".
+Coquelicot is intended to be run on a fully encrypted system and
+accessible only through HTTPS. To configure Apache as a reverse proxy,
+you will need to add the following directives:
-Then, running the test suite is just a matter of typing:
+ ProxyPass / http://127.0.0.1:9292/
+ SetEnv proxy-sendchunks 1
+ RequestHeader set X-Forwarded-SSL "on"
- spec test_coquelicot.rb
+You can also run Coquelicot with mod_passenger, Mongrel, Thin or any
+Rack compatible webserver.
-Future
-------
+### Configuration
+
+By default Coquelicot is configured to authenticate with the
+"simplepass" mechanism and some other reasonable defaults.
+
+It is possible to overwrite these settings from a configuration file
+named `settings.yml` that will be used if it is present in the `conf`
+directory of the application.
+
+All available settings with their default values are documented in
+`conf/settings-default.yml`.
+
+Further settings example:
+
+ * `conf/settings-simplepass.yml`: shows how to change the default
+ password for the "simplepass" mechanism.
+
+ * `conf/settings-imap.yml`: necessary configuration for the "imap"
+ authentication mechanism.
+
+You can copy one of these examples to `conf/settings.yml` and adjust
+them according to your environment.
+
+### Garbage collection
+
+To cleanup files automatically when they expired, coquelicot comes with
+a cleanup script, that does the garbage collection for you. The easiest
+way is to add `ext/coquelicot_gc.rb` as a cron job that runs every 5
+minutes (or so).
+
+### Migrate from Jyraphe
+
+[Jyraphe] is another free software web file sharing application.
+Coquelicot provides a migration script to import Jyraphe 0.5
+repositories in `tools/migrate_jyraphe.rb`.
+
+[Jyraphe]: http://home.gna.org/jyraphe/
+
+Test, development and extensions
+--------------------------------
+
+Coquelicot is written in Ruby and should be quite easy to improve for
+anyone a little bit familiar with the Sinatra web framework. It is
+mostly written using Behaviour Driven Development, making the test suite
+a fine net to hack in confidence. So please go ahead!
+
+### Setup a work environment
+
+As Coquelicot uses Bundle, the first step to work on Coquelicot
+is installing the proper dependencies by issuing:
+
+ bundle install
+
+### Basic operations
+
+Coquelicot test suite is written using RSpec. Running the test suite is
+just a matter of typing:
+
+ bundle exec rspec
+
+Running a test server can be done with:
+
+ bundle exec rackup config-development.ru
- * Integrate other authentication systems for uploads
+To update the translation source files, use:
- A common password is a pretty limited authentication scheme.
- One could like to also configure no password or integrate with
- webmails or other authentication system.
+ bundle exec rake updatepo
- * One-time download
+This will update `po/coquelicot.pot` and merge the new strings in the various
+`po/*/coquelicot.po` files.
- An user might want to allow exactly _one_ download of a file,
- to more closely replace an email attachment.
+### Authentication mechanisms
+
+The authentication part of Coquelicot has been made modular. Adding a
+new authentication mechanism should be fairly straightforward.
+
+New authentication mechanism needs to provide the following 3 files,
+with the following responsabilities:
+
+ * `lib/coquelicot/auth/<METHOD>.rb`:
+
+ A class implementing the actual authentication. This class must
+ implement an `authenticate` method. It will receive the form fields
+ as usual (params). This method should either return true if upload
+ should be allowed.
+
+ * `public/javascripts/coquelicot.auth.<METHOD>.js:`
+
+ This file should define 'authentication' as an object with the
+ following methods:
+
+ - `getData()`: returns an object of all the necessary data
+ to authenticate on the app side. Keys should have the same name
+ as the input fields used to authenticate without Javascript.
+ - `focus()`: set the focus on the first authentication form field.
+ - (optional) `handleSuccess()`: arbitrary action upon successful
+ authentication. This is called after the livebox is closed.
+ - (optional) `handleReject()`: arbitrary action when access
+ get rejected. One can reset authentication fields after a failed
+ authentication.
+ - (optional) `handleFailure()`: arbitrary action when there was
+ a problem in the authentication procedure.
+
+ * `views/auth/<METHOD>.haml`:
+
+ Render the necessary form fields that will be used for
+ authentication.
+
+ The authentication method can be set in the application settings
+ including mandatory options for this method.
+
+Future
+------
* More flexible expiration
It might be interesting to also offer a calendar for specifying
an exact date after which the file will be unavailable.
- * Upper-bound expiration time
-
- Malicious users could specify an arbitrary number of minutes before
- the file is expired. This should be limited by an upper-bound.
-
* Hide file size (padding)
There is currently a real close mapping from original file size to
Storage details
---------------
-Files are stored in the directory specified by the 'depot_path'
-setting.
+Files are stored in the directory specified by the 'depot_path' setting.
+One file in Coquelicot is actually stored in two files: one for metadata and
+one for the file content.
+
+### Metadata file
The format is the following:
---
- Coquelicot: "1.0"
+ Coquelicot: "2.0"
Salt: <8 bytes stored as Base64>
Expire-at: <expiration time in seconds since epoch>
---
- <encrypted data>
+ <encrypted metadata>
Encryption is done using OpenSSL. Cipher is AES-256-CBC with key and IV
-created using the pbkdf2_hmac_sha1() implementation of PKCS5. The later
-is fead using the former 'Salt' and the given passphrase.
+created using the `pbkdf2_hmac_sha1()` implementation of PKCS5. The later
+is fed using the former *Salt* and the given passphrase, using 2000
+iterations.
-Once decrypted, content has the following format:
+Once decrypted, the metadata have the following format:
---
+ Created-at: <upload time in seconds since epoch>
Filename: "<original file name>"
Content-Type: "<MIME type>"
- Length: <file length is bytes>
- ---
- <original bytes forming the file content>
+ Length: <content length is bytes>
+ One-time-only: <true|false>
Headers must be parseable using the YAML standard.
+### Content file
+
+The content file contains the stored file in encrypted form. Encryption is done
+with the same algorithm and keys as the encrypted metadata (see above).
+
+The file name of the content file is the same as the one for metada, with an
+added suffix of '.content'. For example, if the metadata file name is
+`mqeb4pfcru2ymq3e6se7`, the associated content file will be
+`mqeb4pfcru2ymq3e6se7.content`.
+
+### Expired files
+
+Both the content file and the metadata file are truncated to zero length when
+they are "expired".
+
+### URL mapping
+
In order to map download URLs to file name, a simple text file ".links"
is used. It contains a line for each file in the form:
- <URL name> <file name>
+ <URL name> <metadata file name>
+
+### Changes history
+
+ version 2.0
+ : Current version described above.
+
+ version 1.0
+ : File content is in the same file as the metadata. Content is put in the
+ after the metadata and an extra "--- \n".
Authors
-------
-Coquelicot © 2010 potager.org <jardiniers@potager.org>
+ Coquelicot © 2010-2012 potager.org <jardiniers@potager.org>
+ © 2011 mh / immerda.ch <mh+coquelicot@immerda.ch>
+
+Coquelicot is distributed under the [GNU Affero General Public License]
+version 3 or (at your option) any later version.
+
+Background image (`public/images/background.jpg`) derived from:
+[“coquelicot”] © 2008 Jean-Louis Zimmermann
+Licensed under [Creative Commons Attributions 2.0 Generic]
-Coquelicot is distributed under the GNU Affero General Public License
-version 3. See LICENSE for details.
+[“coquelicot”]: https://secure.flickr.com/photos/jeanlouis_zimmermann/2478019744/
+[GNU Affero General Public License]: http://www.gnu.org/licenses/agpl.txt
+[Creative Commons Attributions 2.0 Generic]: https://creativecommons.org/licenses/by/2.0/deed