Add documentation and some functions on builder

pull/5/head
Trinity Pointard 6 years ago
parent 50947b8715
commit acce8261c9

@ -1,3 +1,44 @@
#![deny(missing_docs)]
//! # Rocket Csrf
//!
//! A crate to protect you application against csrf.
//!
//! ## Feature
//!
//! - Automatically protect all POST, PUT, DELETE and PATCH endpoints
//! - Ability to define exceptions
//!
//! ## Usage
//!
//! First add it to your `Cargo.toml` (at the moment using git version, because it was made mainly
//! for [https://github.com/Plume-org/Plume](Plume) and I didn't have the time to backport it to
//! older Rocket version)
//!
//! ```tome
//! [dependencies.rocket_csrf]
//! git = "https://github.com/fdb-hiroshima/rocket_csrf"
//! rev = "50947b8715ae1fa7b73e60b65fdbd1aaf7754f10"
//!
//! Then, in your `main.rs`:
//!
//! ```rust
//! extern crate rocket_csrf;
//!
//! //...
//!
//! fn main() {
//! rocket::ignite()
//! .attach(rocket_csrf::CsrfFairingBuilder::new()
//! //configure it here
//! .finish().unwrap())
//! //add your routes, other fairings...
//! .lanch();
//! }
//! ```
//!
//! You should define a route for csrf violation error, and registe it in the builder, otherwise
//! errors will simply be redirected to the route matching `/`
//!
extern crate csrf;
extern crate data_encoding;
extern crate rand;
@ -22,6 +63,39 @@ use std::env;
use std::io::Read;
use std::str::from_utf8;
/// Builder for [`CsrfFairing`]
///
/// The `CsrfFairingBuilder` type allows for creation and configuration of a [`CsrfFairing`], the
/// main struct of this crate.
///
/// # Usage
/// A Builder is created via the [`new`] method. Then you can configure it with others provided
/// methods, and get a [`CsrfFairing`] by a call to [`finalize`]
///
/// [`CsrfFairing`]: /rocket_csrf/struct.CsrfFairing.html
/// [`new`]: /rocket_csrf/struct.CsrfFairing.html#method.new
/// [`finalize`]: /rocket_csrf/struct.CsrfFairing.html#method.finalize
///
/// ## Examples
///
/// The following shippet show 'CsrfFairingBuilder' being used to create a fairing protecting all
/// endpoints and redirecting error to `/csrf-violation` and treat them as if they where `GET`
/// request then.
///
/// ```rust
/// #extern crate rocket_csrf
///
/// use rocket_csrf::CsrfFairingBuilder;
/// fn main() {
/// rocket::ignite()
/// .attach(rocket_csrf::CsrfFairingBuilder::new()
/// .set_default_target("/csrf-violation", rocket::http::Method::Get)
/// .finish().unwrap())
/// //add your routes, other fairings...
/// .launch();
/// }
/// ```
pub struct CsrfFairingBuilder {
duration: i64,
default_target: (String, Method),
@ -33,6 +107,9 @@ pub struct CsrfFairingBuilder {
}
impl CsrfFairingBuilder {
/// Create a new builder with default values.
pub fn new() -> Self {
CsrfFairingBuilder {
duration: 60 * 60,
@ -45,30 +122,126 @@ impl CsrfFairingBuilder {
}
}
/// Set the timeout (in seconds) of CSRF tokens generated by the final Fairing. Default timeout
/// is one hour.
pub fn set_timeout(mut self, timeout: i64) -> Self {
self.duration = timeout;
self
}
/// Set the default route when an invalide request is catched, you may add a <uri> as a segment
/// or a param to get the percent-encoded original target. You can also set the method of the
/// route to which you choosed to redirect.
///
/// # Example
///
/// ```rust
/// use rocket_csrf::CsrfFairingBuilder;
/// fn main() {
/// rocket::ignite()
/// .attach(rocket_csrf::CsrfFairingBuilder::new()
/// .set_default_target("/csrf-violation", rocket::http::Method::Get)
/// .finish().unwrap())
/// //add your routes, other fairings...
/// .launch();
/// }
pub fn set_default_target(mut self, default_target: String, method: Method) -> Self {
self.default_target = (default_target, method);
self
}
/// Set the list of exceptions which will not be redirected to the default route, removing any
/// previously added exceptions, to juste add exceptions use [`add_exceptions`] instead. A route may
/// contain dynamic parts noted as <name>, which will be replaced in the target route.
/// Note that this is not aware of Rocket's routes, so matching `/something/<dynamic>` while
/// match against `/something/static`, even if those are different routes for Rocket. To
/// circunvence this issue, you can add a (not so) exception matching the static route before
/// the dynamic one, and redirect it to the default target manually.
///
/// [`add_exceptions`]: /rocket_csrf/struct.CsrfFairing.html#method.add_exceptions
///
/// # Example
///
/// ```rust
/// use rocket_csrf::CsrfFairingBuilder;
/// fn main() {
/// rocket::ignite()
/// .attach(rocket_csrf::CsrfFairingBuilder::new()
/// .set_exceptions(vec![
/// ("/some/path".to_owned(), "/some/path".to_owned(), rocket::http::Method::Post))//don't verify csrf token
/// ("/some/<other>/path".to_owned(), "/csrf-error?where=<other>".to_owned(), rocket::http::Method::Get))
/// ])
/// .finish().unwrap())
/// //add your routes, other fairings...
/// .launch();
/// }
/// ```
pub fn set_exceptions(mut self, exceptions: Vec<(String, String, Method)>) -> Self {
self.exceptions = exceptions;
self
}
/// Add the to list of exceptions which will not be redirected to the default route. See
/// [`set_exceptions`] for more informations on how exceptions work.
///
/// [`set_exceptions`]: /rocket_csrf/struct.CsrfFairing.html#method.set_exceptions
pub fn add_exceptions(mut self, exceptions: Vec<(String, String, Method)>) -> Self {
self.exceptions.extend(exceptions);
self
}
/// Set the secret key used to generate secure cryptographic tokens. If not set, rocket_csrf
/// will attempt to get the secret used by Rocket for it's own private cookies via the
/// ROCKET_SECRET_KEY environment variable, or will generate a new one at each restart.
/// Having the secret key set (via this or Rocket environment variable) allow tokens to keep
/// their validity in case of an application restart.
///
/// # Example
///
/// ```rust
/// use rocket_csrf::CsrfFairingBuilder;
/// fn main() {
/// rocket::ignite()
/// .attach(rocket_csrf::CsrfFairingBuilder::new()
/// .set_secret([0;32])//don't do this, use trully secret array instead
/// .finish().unwrap())
/// //add your routes, other fairings...
/// .launch();
/// }
/// ```
pub fn set_secret(mut self, secret: [u8; 32]) -> Self {
self.secret = Some(secret);
self
}
/// Set if this should modify response to insert tokens automatically in all forms. If true,
/// this will insert tokens in all forms it encounter, if false, you will have to add them via
/// [`CsrfToken`], which you may obtain via request guards.
///
/// [`CsrfToken`]: /rocket_csrf/struct.CsrfToken.html
pub fn set_auto_insert(mut self, auto_insert: bool) -> Self {
self.auto_insert = auto_insert;
self
}
/// Set prefixs for which this will not try to add tokens in forms. This has no effect if
/// auto_insert is set to false. Not having to parse response on paths witch don't need it may
/// improve performances, but not that only html documents are parsed, so it's not usefull to
/// use it on routes containing only images or stillsheets.
pub fn set_auto_insert_disable_prefix(mut self, auto_insert_prefix: Vec<String>) -> Self {
self.auto_insert_disable_prefix = auto_insert_prefix;
self
}
/// Set the maximum size of a request before it get send chunked. A request will need at most
/// this additional memory for the buffer used to parse and tokens into forms. This have no
/// effect if auto_insert is set to false. Default value is 16Kio
pub fn set_auto_insert_max_chunk_size(mut self, chunk_size: u64) -> Self {
self.auto_insert_max_size = chunk_size;
self
}
/// Get the fairing from the builder.
pub fn finalize(self) -> Result<CsrfFairing, ()> {
let secret = self.secret.unwrap_or_else(|| {
env::vars()
@ -116,6 +289,13 @@ impl CsrfFairingBuilder {
}
}
/// Fairing to protect against Csrf attacks.
///
/// The `CsrfFairing` type protect a Rocket instance against Csrf attack by requesting mendatory
/// token on any POST, PUT, DELETE or PATCH request.
/// This is created via a [`CsrfFairingBuilder`], and implement nothing else than the `Fairing` trait.
///
/// [`CsrfFairingBuilder`]: /rocket_csrf/struct.CsrfFairing.html
pub struct CsrfFairing {
duration: i64,
default_target: (Path, Method),
@ -364,7 +544,7 @@ impl<'a> Read for CsrfProxy<'a> {
self.buf.push((buf[pos..].to_vec(), 0));
self.state = Reset;
return Ok(pos);
} //TODO
}
_ => SearchInput,
},
SearchMethod(pos) => match buf[i] as char {
@ -374,7 +554,7 @@ impl<'a> Read for CsrfProxy<'a> {
self.buf.push((buf[pos..].to_vec(), 0));
self.state = Reset;
return Ok(pos);
} //TODO
}
_ => SearchMethod(pos),
},
PartialNameMatch(count, pos) => match (buf[i] as char, count) {
@ -399,7 +579,6 @@ impl<'a> Read for CsrfProxy<'a> {
self.buf.push((buf[i + 1..].to_vec(), 0));
self.state = Reset;
return Ok(i + 1);
//TODO
} else {
CloseInputTag
},
@ -409,6 +588,13 @@ impl<'a> Read for CsrfProxy<'a> {
}
}
/// Csrf token to insert into pages.
///
/// The `CsrfToken` type allow you to add tokens into your pages anywhere you want, and is mainly
/// usefull if you disabled auto-insert when building the fairing registered in Rocket.
/// This impltement Serde's Serialize so you may insert it directly into your templats as if it was
/// a String. It also implement FromRequest so you can get it as a request guard. This is also the
/// only way to get this struct.
#[derive(Debug, Clone)]
pub struct CsrfToken {
value: String,

Loading…
Cancel
Save