#![deny(missing_docs)] and lots of documentation

lumi created

Change summary

sasl/src/error.rs                |  3 ++
sasl/src/lib.rs                  | 43 +++++++++++++++++++++++++++++++--
sasl/src/mechanisms/anonymous.rs |  5 +++
sasl/src/mechanisms/mod.rs       |  3 +
sasl/src/mechanisms/plain.rs     |  5 +++
sasl/src/mechanisms/scram.rs     | 28 ++++++++++++++++++++++
6 files changed, 83 insertions(+), 4 deletions(-)

Detailed changes

sasl/src/error.rs 🔗

@@ -1,8 +1,11 @@
 use openssl::error::ErrorStack;
 
+/// A wrapper enum for things that could go wrong in this crate.
 #[derive(Debug)]
 pub enum Error {
+    /// An error in OpenSSL.
     OpenSslErrorStack(ErrorStack),
+    /// An error in a SASL mechanism.
     SaslError(String),
 }
 

sasl/src/lib.rs 🔗

@@ -1,14 +1,50 @@
-//! Provides the `SaslMechanism` trait and some implementations.
+#![deny(missing_docs)]
+
+//! This crate provides a framework for SASL authentication and a few authentication mechanisms.
+//!
+//! # Examples
+//!
+//! ```rust
+//! use sasl::{SaslCredentials, SaslSecret, SaslMechanism, Error};
+//! use sasl::mechanisms::Plain;
+//!
+//! let creds = SaslCredentials {
+//!     username: "user".to_owned(),
+//!     secret: SaslSecret::Password("pencil".to_owned()),
+//!     channel_binding: None,
+//! };
+//!
+//! let mut mechanism = Plain::from_credentials(creds).unwrap();
+//!
+//! let initial_data = mechanism.initial().unwrap();
+//!
+//! assert_eq!(initial_data, b"\0user\0pencil");
+//! ```
+//!
+//! You may look at the tests of `mechanisms/scram.rs` for examples of more advanced usage.
+//!
+//! # Usage
+//!
+//! You can use this in your crate by adding this under `dependencies` in your `Cargo.toml`:
+//!
+//! ```toml,ignore
+//! sasl = "*"
+//! ```
 
 extern crate base64;
 extern crate openssl;
 
-pub mod error;
+mod error;
+
+pub use error::Error;
 
 /// A struct containing SASL credentials.
 pub struct SaslCredentials {
-    pub username: String,
+    /// The requested username.
+    pub username: String, // TODO: change this since some mechanisms do not use it
+    /// The secret used to authenticate.
     pub secret: SaslSecret,
+    /// Optionally, channel binding data, for *-PLUS mechanisms.
     pub channel_binding: Option<Vec<u8>>,
 }
 
@@ -20,6 +56,7 @@ pub enum SaslSecret {
     Password(String),
 }
 
+/// A trait which defines SASL mechanisms.
 pub trait SaslMechanism {
     /// The name of the mechanism.
     fn name(&self) -> &str;

sasl/src/mechanisms/anonymous.rs 🔗

@@ -4,9 +4,14 @@ use SaslCredentials;
 use SaslMechanism;
 use SaslSecret;
 
+/// A struct for the SASL ANONYMOUS mechanism.
 pub struct Anonymous;
 
 impl Anonymous {
+    /// Constructs a new struct for authenticating using the SASL ANONYMOUS mechanism.
+    ///
+    /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the
+    /// requested mechanism using `from_credentials`.
     pub fn new() -> Anonymous {
         Anonymous
     }

sasl/src/mechanisms/mod.rs 🔗

@@ -1,4 +1,5 @@
-///! Provides a few SASL mechanisms.
+//! Provides a few SASL mechanisms.
+
 mod anonymous;
 mod plain;
 mod scram;

sasl/src/mechanisms/plain.rs 🔗

@@ -4,12 +4,17 @@ use SaslCredentials;
 use SaslMechanism;
 use SaslSecret;
 
+/// A struct for the SASL PLAIN mechanism.
 pub struct Plain {
     username: String,
     password: String,
 }
 
 impl Plain {
+    /// Constructs a new struct for authenticating using the SASL PLAIN mechanism.
+    ///
+    /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the
+    /// requested mechanism using `from_credentials`.
     pub fn new<N: Into<String>, P: Into<String>>(username: N, password: P) -> Plain {
         Plain {
             username: username.into(),

sasl/src/mechanisms/scram.rs 🔗

@@ -66,13 +66,22 @@ fn generate_nonce() -> Result<String, ErrorStack> {
     Ok(base64::encode(&data))
 }
 
+/// A trait which defines the needed methods for SCRAM.
 pub trait ScramProvider {
+    /// The name of the hash function.
     fn name() -> &'static str;
+
+    /// A function which hashes the data using the hash function.
     fn hash(data: &[u8]) -> Vec<u8>;
+
+    /// A function which performs an HMAC using the hash function.
     fn hmac(data: &[u8], key: &[u8]) -> Vec<u8>;
+
+    /// A function which does PBKDF2 key derivation using the hash function.
     fn derive(data: &[u8], salt: &[u8], iterations: usize) -> Vec<u8>;
 }
 
+/// A `ScramProvider` which provides SCRAM-SHA-1 and SCRAM-SHA-1-PLUS
 pub struct Sha1;
 
 impl ScramProvider for Sha1 {
@@ -99,6 +108,7 @@ impl ScramProvider for Sha1 {
     }
 }
 
+/// A `ScramProvider` which provides SCRAM-SHA-256 and SCRAM-SHA-256-PLUS
 pub struct Sha256;
 
 impl ScramProvider for Sha256 {
@@ -136,6 +146,7 @@ enum ScramState {
     },
 }
 
+/// A struct for the SASL SCRAM-* and SCRAM-*-PLUS mechanisms.
 pub struct Scram<S: ScramProvider> {
     name: String,
     username: String,
@@ -147,6 +158,10 @@ pub struct Scram<S: ScramProvider> {
 }
 
 impl<S: ScramProvider> Scram<S> {
+    /// Constructs a new struct for authenticating using the SASL SCRAM-* mechanism.
+    ///
+    /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the
+    /// requested mechanism using `from_credentials`.
     pub fn new<N: Into<String>, P: Into<String>>(
         username: N,
         password: P,
@@ -162,6 +177,12 @@ impl<S: ScramProvider> Scram<S> {
         })
     }
 
+    /// Constructs a new struct for authenticating using the SASL SCRAM-* mechanism.
+    ///
+    /// This one takes a nonce instead of generating it.
+    ///
+    /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the
+    /// requested mechanism using `from_credentials`.
     pub fn new_with_nonce<N: Into<String>, P: Into<String>>(
         username: N,
         password: P,
@@ -178,11 +199,18 @@ impl<S: ScramProvider> Scram<S> {
         }
     }
 
+    /// Constructs a new struct for authenticating using the SASL SCRAM-*-PLUS mechanism.
+    ///
+    /// This means that this function will also take the channel binding data.
+    ///
+    /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the
+    /// requested mechanism using `from_credentials`.
     pub fn new_with_channel_binding<N: Into<String>, P: Into<String>>(
         username: N,
         password: P,
         channel_binding: Vec<u8>,
     ) -> Result<Scram<S>, Error> {
+        // TODO: channel binding modes other than tls-unique
         Ok(Scram {
             name: format!("SCRAM-{}-PLUS", S::name()),
             username: username.into(),