http-signatures 0.8.0

An implementation of the HTTP Signatures RFC
// This file is part of HTTP Signatures

// HTTP Signatures is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// HTTP Signatures is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with HTTP Signatures  If not, see <http://www.gnu.org/licenses/>.

//! Available with the `use_hyper` feature. This module defines `VerifyHeader` for
//! `hyper::server::Request`.
//!
//! This allows easy verification of incomming requests in Hyper.
//!
//! See
//! [this example](https://git.asonix.dog/asonix/http-signatures/src/branch/master/examples/hyper-server)
//! for usage information.

use hyper::{header::AUTHORIZATION, Request};

use crate::{
    error::VerificationError,
    prelude::*,
    verify::{SignedHeader, VerifyKey},
};

impl<B> VerifyHeader for Request<B> {
    fn verify_signature_header(&self, key: VerifyKey) -> Result<(), VerificationError> {
        let auth_header = self
            .headers()
            .get("Signature")
            .ok_or(VerificationError::HeaderNotPresent)?
            .to_str()
            .map_err(|_| VerificationError::HeaderNotPresent)?;

        verify_header(self, auth_header, key)
    }

    fn verify_authorization_header(&self, key: VerifyKey) -> Result<(), VerificationError> {
        let ref auth_header = self
            .headers()
            .get(AUTHORIZATION)
            .ok_or(VerificationError::HeaderNotPresent)?
            .to_str()
            .map_err(|_| VerificationError::HeaderNotPresent)?;

        verify_header(self, auth_header, key)
    }
}

fn verify_header<B>(
    req: &Request<B>,
    header: &str,
    key: VerifyKey,
) -> Result<(), VerificationError> {
    let auth_header = SignedHeader::new(header)?;

    let headers: Vec<(&str, &str)> = req
        .headers()
        .iter()
        .filter_map(|(header_name, header_value)| {
            header_value
                .to_str()
                .ok()
                .map(|header_value| (header_name.as_str(), header_value))
        })
        .collect();

    auth_header.verify(
        headers.as_ref(),
        &req.method().as_ref().to_lowercase(),
        req.uri().path(),
        req.uri().query(),
        key,
    )
}