rephrase README section about the "download password" feature
[coquelicot.git] / README
diff --git a/README b/README
index 8647479..6ebb748 100644 (file)
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
-Coquelicot
-==========
+About “Coquelicot”
+==================
 
-Coquelicot is a "one-click" file sharing web application with a specific
+[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, in return they
@@ -12,6 +12,8 @@ Coquelicot aims to protect, to some extent, users and system
 administrators from disclosure of the files exchanged from passive and
 not so active attackers.
 
+[Coquelicot]: https://coquelicot.potager.org/
+
 Features
 --------
 
@@ -48,8 +50,8 @@ Features
 
  * Upload progress bar
 
-   If the web server tracks upload progress, users having javascript
-   enabled will see a nice progress bar during the file upload.
+   Users having javascript enabled will see a nice progress bar during
+   the file upload.
 
  * Downgrade nicely
 
@@ -72,10 +74,10 @@ Features
 
  * Download can be protected by a password
 
-   When uploading, a password can be specified which will be used as
-   the encryption key. In order to download the file, the password
-   must be entered through in a POST'ed form, preventing the password
-   from appearing in the server logs.
+   When uploading, a password can be specified which will then be used
+   to encrypt the file. For subsequent downloads, the password
+   must be entered through in a POST'ed form. This prevents the password
+   from appearing in most server logs.
 
  * Files are stored with a random name
 
@@ -95,25 +97,43 @@ Features
    to make it harder to retrieve its content through filesystem
    analysis, it is filled with zeros first.
 
-Setup
------
+Installation
+------------
+
+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.
+
+### Initial setup
+
+Coquelicot uses Bundler to manage its dependency. To install Bundler on
+Debian, please issue:
+
+    # apt-get install rubygems
+    $ gem install bundler
+
+Once Bundler is available, please issue:
 
-Coquelicot is written in Ruby using the Sinatra web framework.
+    $ bundle install --deployment --binstubs
 
-On Debian, one can fulfill its dependencies by issuing:
+Then, to start Coquelicot use:
 
-    apt-get install libsinatra-ruby1.8 libopenssl-ruby1.8 \
-                    libhaml-ruby1.8 liblockfile-ruby libgettext-ruby1.8 \
-                    libjson-ruby1.8 rake
+    $ bin/coquelicot start
 
-Finally you need to figure out the best way to host a Rack application
-depending on your setup. *evil grin*
+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:
 
-Coquelicot is intended to be run on a fully encrypted system and accessible
-only through HTTPS.
+    ProxyPass / http://127.0.0.1:51161/
+    SetEnv proxy-sendchunks 1
+    RequestHeader set X-Forwarded-SSL "on"
 
-Configuration
--------------
+Coquelicot has been written to use Rainbows! as its webserver. You can
+also run Coquelicot with mod_passenger, Mongrel, Thin or any Rack
+compatible webserver, but please read below about buffered input.
+
+### Configuration
 
 By default Coquelicot is configured to authenticate with the
 "simplepass" mechanism and some other reasonable defaults.
@@ -133,30 +153,69 @@ Further settings example:
  * `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.
+You can copy one of these examples to `conf/settings.yml` and adjust
+them according to your environment.
+
+A different location for the configuration file can be specified using
+the `-c` option when running `bin/coquelicot`.
 
-Garbage collection
-------------------
+### 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).
+way is to set up a cron job that will run every 5 minutes (or so):
+
+    bin/coquelicot gc
+
+### Migrate from Jyraphe
+
+[Jyraphe] is another free software web file sharing application.
+Coquelicot provides a migration script to import Jyraphe 0.5
+repositories as `bin/coquelicot migrate-jyraphe`:
+
+    Usage: coquelicot [options] migrate-jyraphe \ 
+                      [command options] JYRAPHE_VAR > REWRITE_RULES
 
-Test and development
---------------------
+    Options:
+        -c, --config FILE            read settings from FILE
+
+    Command options:
+        -p, --rewrite-prefix PREFIX  prefix URL in rewrite rules
+
+The last argument must be a path to the `var` directory of the Jyraphe
+installation. After migrating the files to Coquelicot, directives for
+Apache mod_rewrite will be printed on stdout which ought to be
+redirected to a file. The `-p` option can be used to add a specific
+paths in the redirected URLs.
+
+[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
 
-Coquelicot test suite is written using RSpec. Running the test suite is just a
-matter of typing:
+### 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 coquelicot start --no-daemon
+
 To update the translation source files, use:
 
     bundle exec rake updatepo
@@ -164,14 +223,93 @@ To update the translation source files, use:
 This will update `po/coquelicot.pot` and merge the new strings in the various
 `po/*/coquelicot.po` files.
 
-Migrate from Jyraphe
---------------------
+### 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.
 
-Jyraphe [1] is another free software web file sharing application.
-Coquelicot provides a migration script to import Jyraphe 0.5 repositories in
-`tools/migrate_jyraphe.rb`.
+ * `views/auth/<METHOD>.haml`:
 
-[1] http://home.gna.org/jyraphe/
+   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.
+
+### Watch for buffered inputs!
+
+Coquelicot is written in Ruby using Sinatra. Sinatra is based on the
+Rack webserver interface. Rack specification mandates that applications
+must be able to seek and rewind freely in the request content.
+
+Request data are always received as a stream through the network. So in
+order to comply with the specification, webservers implementing Rack will
+either buffer the input in memory (Webrick) or in a temporary file
+(Thin, Passenger or Mongrel).
+
+On top of that, when parsing `multipart/form-data` POST content,
+`Rack::Request` (used by Sinatra) will create a new temporary file for
+each files in the POST request.
+
+For the specific needs of Coquelicot, those behaviours will prevent
+users from uploading large files (if `/tmp` is in memory) or will be a
+breach of privacy, as a clear text version will be written to disk.
+
+To overcome these limitations, Coquelicot first uses a specific feature
+of the Rainbows! webserver of streaming its input directly to
+applications, and second bypass `Rack::Request` to directly handle
+POST content. Usage of any other Rack webserver is strongly discouraged
+and should be restricted to development and testing.
+
+### Implementation details
+
+Common application code lies in `Coquelicot::Application`. Except for
+one specific (and important) type of requests, namely `POST /update`.
+These requests are handled directly at bare Rack level by
+`Coquelicot::Rack::Upload`.
+
+This allows to work directly with POST data as the browser is sending
+them, so we can directly stream the uploaded file to our encrypted
+on-disk containers.
+
+The POST data must be in a very specific order, as we need to handle
+authentication, and various options prior to start recording the file
+content. Thanks to the W3C, the [HTML specification] states that parts
+of the POST data must be delivered in the same order the controls
+appears in the `<form/>` container.
+
+`Coquelicot::Rack::Multipart` expose a simple DSL to parse the fields as
+they are delivered. The later is used by `Coquelicot::Rack::Upload` to
+perform its logic pretty nicely.
+
+[HTML specification]: http://www.w3.org/TR/html4/interact/forms.html
 
 Future
 ------
@@ -187,108 +325,95 @@ Future
    stored file size. Original file size will also be recorded in server
    logs. Padding could be used to improve this situation.
 
- * Make a Gem
+ * Make a usable Gem
 
-   Most Ruby stuff is installed using Gem, so Coquelicot should be one.
+   Most Ruby stuff is installed using Gem, so Coquelicot should also be
+   installable that way. What is mostly missing is an easy way to create
+   a default configuration and directories to hold uploaded files and
+   temp. data.
 
  * Package for Debian
 
    A Debian package would be nice to spread Coquelicot setups.
 
- * Describe more setups
-
-   Describe how to setup Coquelicot with mod_passenger, Mongrel and
-   other webservers.
-
 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 fed 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>
+    Length: <content length is bytes>
     One-time-only: <true|false>
-    --- 
-    <original bytes forming the file content>
 
 Headers must be parseable using the YAML standard.
 
-File are truncated to zero length when they are "expired".
+### Content file
 
-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>
+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).
 
-Authentication Mechanisms
--------------------------
+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`.
 
-It is possible to authenticate users against your own common authentication
-mechanism.
+### Expired files
 
-Such an authentication mechanism needs to provide the following 3 files,
-with the following responsabilities:
+Both the content file and the metadata file are truncated to zero length when
+they are "expired".
 
- * `lib/coquelicot/auth/<METHOD>.rb`:
+### URL mapping
 
-   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.
+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:
 
- * `public/javascripts/coquelicot.auth.<METHOD>.js:`
+    <URL name> <metadata file name>
 
-    This file should define 'authentication' as an object with the following
-    methods:
+### Changes history
 
-    - `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.
+  version 2.0
+  :    Current version described above.
 
- * `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.
+  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-2012 potager.org <jardiniers@potager.org>  
-           © 2011 mh / immerda.ch <mh+coquelicot@immerda.ch>
+    Coquelicot © 2010-2013 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. See LICENSE for details.
+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  
-<https://secure.flickr.com/photos/jeanlouis_zimmermann/2478019744/>
+[“coquelicot” picture] © 2008 Jean-Louis Zimmermann  
+Licensed under [Creative Commons Attributions 2.0 Generic]  
+
+[“coquelicot” picture]: 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