Skip to content

Commit 1357713

Browse files
committed
Add documentation for 0.1.1 release
1 parent d5dbc9a commit 1357713

File tree

10 files changed

+421
-47
lines changed

10 files changed

+421
-47
lines changed

ACKNOWLEDGEMENTS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ relay | 0.1.0 | MIT OR Apache-2.0
7272
reqwest | 0.8.2 | Apache-2.0, MIT
7373
ring | 0.11.0 | Specified in license file
7474
rocket | 0.3.5 | Apache-2.0, MIT
75+
rocket_codegen | 0.3.5 | Apache-2.0, MIT
7576
safemem | 0.2.0 | MIT OR Apache-2.0
7677
schannel | 0.1.9 | MIT
7778
scoped-tls | 0.1.0 | Apache-2.0, MIT

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "http-signatures"
33
description = "An implementation of the HTTP Signatures RFC"
4-
version = "0.1.0"
4+
version = "0.1.1"
55
license = "GPL-3.0"
66
authors = ["Riley Trautman <[email protected]>"]
77
repository = "https://github.com/asonix/http-signatures"

src/create.rs

Lines changed: 128 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with HTTP Signatures If not, see <http://www.gnu.org/licenses/>.
1515

16+
//! This module defines types and traits for creating HTTP Signatures.
17+
1618
use std::collections::HashMap;
1719
use std::convert::{TryFrom, TryInto};
1820
use std::sync::Arc;
@@ -23,33 +25,37 @@ use base64::encode;
2325
use untrusted::Input;
2426

2527
use super::{SignatureAlgorithm, ShaSize};
26-
use error::Error;
28+
use error::{Error, CreationError};
2729

30+
/// `AsHttpSignature` defines a trait for getting an Authorization Header string from any type that
31+
/// implements it. It provides two methods: as_http_signature, which implementors must define, and
32+
/// authorization_header, which uses as_http_signature to create the header string.
2833
pub trait AsHttpSignature<T>
2934
where
3035
T: Read,
3136
{
37+
/// Gets an `HttpSignature` struct from an immutably borrowed Self
3238
fn as_http_signature(
3339
&self,
3440
key_id: String,
3541
key: T,
3642
algorithm: SignatureAlgorithm,
3743
) -> Result<HttpSignature<T>, Error>;
3844

45+
/// Generates the Authorization Header from an immutably borrowed Self
3946
fn authorization_header(
4047
&self,
4148
key_id: String,
4249
key: T,
4350
algorithm: SignatureAlgorithm,
4451
) -> Result<String, Error> {
45-
let signing_string: SigningString<T> = self.as_http_signature(key_id, key, algorithm)?
46-
.into();
47-
let signature: Signature = signing_string.try_into()?;
48-
49-
Ok(signature.authorization())
52+
Ok(self.as_http_signature(key_id, key, algorithm)?
53+
.authorization_header()?)
5054
}
5155
}
5256

57+
/// `WithHttpSignature` defines a trait for adding an Authorization header to another library's
58+
/// request or response object.
5359
pub trait WithHttpSignature<T>: AsHttpSignature<T>
5460
where
5561
T: Read,
@@ -62,22 +68,58 @@ where
6268
) -> Result<&mut Self, Error>;
6369
}
6470

65-
pub struct HttpSignature<T> {
71+
/// The `HttpSignature` struct, this is the entry point for creating an Authorization header. It
72+
/// contains all the values required for generation.
73+
pub struct HttpSignature<T>
74+
where
75+
T: Read,
76+
{
77+
/// The keyId field in the Authorization header
6678
key_id: String,
79+
/// The key (implementing `Read`) used to sign the request
6780
key: T,
81+
/// The algorithm used to sign the request
6882
algorithm: SignatureAlgorithm,
83+
/// The headers that will be included in the signature
6984
headers: HashMap<String, Vec<String>>,
7085
}
7186

72-
impl<T> HttpSignature<T> {
87+
impl<T> HttpSignature<T>
88+
where
89+
T: Read,
90+
{
91+
/// Create a new HttpSignature from its components.
92+
///
93+
/// This method will Error if `headers` is empty.
94+
///
95+
/// ### Example
96+
/// ```rust
97+
/// # use std::fs::File;
98+
/// # use std::collections::HashMap;
99+
/// # use http_signatures::Error;
100+
/// use http_signatures::{HttpSignature, SignatureAlgorithm, ShaSize, REQUEST_TARGET};
101+
///
102+
/// # fn run() -> Result<(), Error> {
103+
/// let key_id = "test/assets/public.der".into();
104+
/// let priv_key = File::open("test/assets/private.der")?;
105+
///
106+
/// let alg = SignatureAlgorithm::RSA(ShaSize::FiveTwelve);
107+
///
108+
/// let mut headers = HashMap::new();
109+
/// headers.insert(REQUEST_TARGET.into(), vec!["get /".into()]);
110+
///
111+
/// let http_sig = HttpSignature::new(key_id, priv_key, alg, headers)?;
112+
/// # Ok(())
113+
/// # }
114+
/// ```
73115
pub fn new(
74116
key_id: String,
75117
key: T,
76118
algorithm: SignatureAlgorithm,
77119
headers: HashMap<String, Vec<String>>,
78-
) -> Result<Self, Error> {
120+
) -> Result<Self, CreationError> {
79121
if headers.is_empty() {
80-
return Err(Error::NoHeaders);
122+
return Err(CreationError::NoHeaders);
81123
}
82124

83125
Ok(HttpSignature {
@@ -99,17 +141,76 @@ impl<T> HttpSignature<T> {
99141
pub fn headers(&self) -> &HashMap<String, Vec<String>> {
100142
&self.headers
101143
}
144+
145+
/// Generate the Authorization Header from the `HttpSignature`
146+
///
147+
/// This method errors if signing the signing-string fails.
148+
///
149+
/// ### Example
150+
/// ```rust
151+
/// # use std::fs::File;
152+
/// # use std::collections::HashMap;
153+
/// # use http_signatures::{Error, SignatureAlgorithm, ShaSize, REQUEST_TARGET};
154+
/// use http_signatures::HttpSignature;
155+
/// # fn run() -> Result<(), Error> {
156+
/// # let key_id = "test/assets/public.der".into();
157+
/// # let priv_key = File::open("test/assets/private.der")?;
158+
/// # let alg = SignatureAlgorithm::RSA(ShaSize::FiveTwelve);
159+
/// # let mut headers = HashMap::new();
160+
/// # headers.insert(REQUEST_TARGET.into(), vec!["get /".into()]);
161+
/// # let http_signature = HttpSignature::new(key_id, priv_key, alg, headers)?;
162+
///
163+
/// let auth_header = http_signature.authorization_header()?;
164+
/// # Ok(())
165+
/// # }
166+
/// ```
167+
pub fn authorization_header(self) -> Result<String, CreationError> {
168+
let signing_string: SigningString<T> = self.into();
169+
let signature: Signature = signing_string.try_into()?;
170+
171+
Ok(signature.authorization())
172+
}
102173
}
103174

175+
/// A default implementation of `AsHttpSignature` for `HttpSignature`.
176+
///
177+
/// This only works if type `T` is `Clone` in addition to `Read`, which is normally required. This
178+
/// implementation doesn't serve much of a purpose.
179+
impl<T> AsHttpSignature<T> for HttpSignature<T>
180+
where
181+
T: Read + Clone,
182+
{
183+
fn as_http_signature(&self, _: String, _: T, _: SignatureAlgorithm) -> Result<Self, Error> {
184+
Ok(HttpSignature {
185+
key_id: self.key_id.clone(),
186+
key: self.key.clone(),
187+
algorithm: self.algorithm.clone(),
188+
headers: self.headers.clone(),
189+
})
190+
}
191+
}
192+
193+
/// The `SigningString<T>` struct uses what was given in the `HttpSignature` struct, but also has a
194+
/// plaintext field called `signing_string` which holds the string used to sign the request.
195+
///
196+
/// Since `From<HttpSignature<T>>` was implemented for `SigningString<T>`, the transition is as
197+
/// simple as calling `http_signature.into()`.
198+
///
199+
/// This struct does not have public fields, and does not have a constructor since it should only
200+
/// be used as an intermediate point from `HttpSignature<T>` to the signed string.
104201
pub struct SigningString<T> {
105202
key_id: String,
106203
key: T,
107204
headers: Vec<String>,
108205
algorithm: SignatureAlgorithm,
206+
// The plaintext string used to sign the request
109207
signing_string: String,
110208
}
111209

112-
impl<T> From<HttpSignature<T>> for SigningString<T> {
210+
impl<T> From<HttpSignature<T>> for SigningString<T>
211+
where
212+
T: Read,
213+
{
113214
fn from(http_signature: HttpSignature<T>) -> Self {
114215
let (header_keys, signing_vec): (Vec<_>, Vec<_>) = http_signature
115216
.headers
@@ -132,6 +233,11 @@ impl<T> From<HttpSignature<T>> for SigningString<T> {
132233
}
133234
}
134235

236+
/// `Signature` is the result of using the `key: T` of `SigningString<T>` to sign the
237+
/// `signing_string`.
238+
///
239+
/// To get the Authorization Header String from the Signature, the `authorization` method is
240+
/// provided.
135241
pub struct Signature {
136242
sig: String,
137243
key_id: String,
@@ -140,6 +246,7 @@ pub struct Signature {
140246
}
141247

142248
impl Signature {
249+
/// Get the Authorization Header String.
143250
pub fn authorization(self) -> String {
144251
let alg: &str = self.algorithm.into();
145252

@@ -151,7 +258,7 @@ impl Signature {
151258
)
152259
}
153260

154-
fn rsa<T>(mut key: T, size: &ShaSize, signing_string: &[u8]) -> Result<String, Error>
261+
fn rsa<T>(mut key: T, size: &ShaSize, signing_string: &[u8]) -> Result<String, CreationError>
155262
where
156263
T: Read,
157264
{
@@ -161,14 +268,14 @@ impl Signature {
161268

162269
let key_pair = signature::RSAKeyPair::from_der(private_key_der).map_err(
163270
|_| {
164-
Error::BadPrivateKey
271+
CreationError::BadPrivateKey
165272
},
166273
)?;
167274
let key_pair = Arc::new(key_pair);
168275

169-
let mut signing_state = signature::RSASigningState::new(key_pair).map_err(
170-
|_| Error::Unknown,
171-
)?;
276+
let mut signing_state = signature::RSASigningState::new(key_pair).map_err(|_| {
277+
CreationError::SigningError
278+
})?;
172279

173280
let rng = rand::SystemRandom::new();
174281
let mut signature = vec![0; signing_state.key_pair().public_modulus_len()];
@@ -183,12 +290,12 @@ impl Signature {
183290
signing_string,
184291
signature.as_mut_slice(),
185292
)
186-
.map_err(|_| Error::SigningError)?;
293+
.map_err(|_| CreationError::SigningError)?;
187294

188295
Ok(encode(signature.as_slice()))
189296
}
190297

191-
fn hmac<T>(mut key: T, size: &ShaSize, signing_string: &[u8]) -> Result<String, Error>
298+
fn hmac<T>(mut key: T, size: &ShaSize, signing_string: &[u8]) -> Result<String, CreationError>
192299
where
193300
T: Read,
194301
{
@@ -212,8 +319,10 @@ impl<T> TryFrom<SigningString<T>> for Signature
212319
where
213320
T: Read,
214321
{
215-
type Error = Error;
322+
type Error = CreationError;
216323

324+
/// Attempt to sign the signing_string. If signing fails, a `Signature` will not be created and
325+
/// an `Error` will be returned.
217326
fn try_from(signing_string: SigningString<T>) -> Result<Self, Self::Error> {
218327
Ok(match signing_string.algorithm {
219328
SignatureAlgorithm::RSA(size) => {

src/error.rs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,20 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with HTTP Signatures If not, see <http://www.gnu.org/licenses/>.
1515

16+
//! This module defines the Error types for http_signatures.
17+
1618
use std::io::Error as IoError;
1719

20+
/// The root Error
1821
#[derive(Debug)]
1922
pub enum Error {
23+
/// Problems opening files and such
2024
IO(IoError),
21-
NoHeaders,
22-
SigningError,
23-
BadPrivateKey,
25+
/// Problems verifying a request
26+
Verification(VerificationError),
27+
/// Problems creating a signature
28+
Creation(CreationError),
29+
/// Unknown error occurred
2430
Unknown,
2531
}
2632

@@ -30,22 +36,70 @@ impl From<IoError> for Error {
3036
}
3137
}
3238

39+
impl From<VerificationError> for Error {
40+
fn from(e: VerificationError) -> Self {
41+
Error::Verification(e)
42+
}
43+
}
44+
45+
impl From<DecodeError> for Error {
46+
fn from(e: DecodeError) -> Self {
47+
VerificationError::Decode(e).into()
48+
}
49+
}
50+
51+
impl From<CreationError> for Error {
52+
fn from(e: CreationError) -> Self {
53+
Error::Creation(e)
54+
}
55+
}
56+
57+
/// When creating a signature doesn't work
58+
#[derive(Debug)]
59+
pub enum CreationError {
60+
/// Problems reading keys
61+
IO(IoError),
62+
/// Headers must be provided to sign a request
63+
NoHeaders,
64+
/// An error occurred when signing the request
65+
SigningError,
66+
/// An error occurred when interacting with an RSA key
67+
BadPrivateKey,
68+
}
69+
70+
impl From<IoError> for CreationError {
71+
fn from(e: IoError) -> Self {
72+
CreationError::IO(e)
73+
}
74+
}
75+
76+
/// When decoding a signature doesn't work
3377
#[derive(Debug)]
3478
pub enum DecodeError {
79+
/// A required key is missing
3580
MissingKey(&'static str),
81+
/// The signature algorithm is not supported
3682
InvalidAlgorithm(String),
83+
/// The key was not properly encoded to base64
3784
NotBase64,
38-
Unknown,
3985
}
4086

87+
/// When a request cannot be verified
4188
#[derive(Debug)]
4289
pub enum VerificationError {
90+
/// Issues decoding a signature
4391
Decode(DecodeError),
92+
/// Headers present in the `headers` field are missing from the request
4493
MissingHeaders(String),
94+
/// When the `get_key` method from the `GetKey` type fails
4595
GetKey,
96+
/// Problems reading the required keys
4697
ReadKey,
98+
/// Problems verifying the signature
4799
BadSignature,
100+
/// When the Authorization header is missing
48101
HeaderNotPresent,
102+
/// When we're not sure what went wrong
49103
Unknown,
50104
}
51105

0 commit comments

Comments
 (0)