transip 0.4.2

Call functions on the Transip Api Endpoint
Documentation
use ring::{
    rand,
    signature::{self, RsaKeyPair},
};
use std::{
    io::{BufReader, Read},
    path::Path,
};

use crate::base64::Base64;
use crate::fs::FileSystem;
use crate::{Error, Result};

pub struct KeyPair {
    inner: RsaKeyPair,
}

impl From<RsaKeyPair> for KeyPair {
    fn from(rsa_key_pair: RsaKeyPair) -> Self {
        Self {
            inner: rsa_key_pair,
        }
    }
}

impl KeyPair {
    pub fn try_from_reader<R>(r: R) -> Result<KeyPair>
    where
        R: Read,
    {
        let keys = rustls_pemfile::pkcs8_private_keys(&mut BufReader::new(r))
            .filter_map(|s| s.ok())
            .collect::<Vec<_>>();
        if keys.is_empty() {
            Err(Error::Key("None"))
        } else {
            signature::RsaKeyPair::from_pkcs8(keys[0].secret_pkcs8_der())
                .map_err(|error| Error::Rejected(error.to_string()))
                .map(KeyPair::from)
        }
    }

    pub fn try_from_file<P>(path: P) -> Result<KeyPair>
    where
        P: AsRef<Path>,
    {
        path.reader().and_then(KeyPair::try_from_reader)
    }

    pub fn sign<S>(&self, data: S) -> Result<String>
    where
        S: AsRef<[u8]>,
    {
        let rng = rand::SystemRandom::new();
        let mut signature = vec![0; self.inner.public().modulus_len()];
        self.inner
            .sign(
                &signature::RSA_PKCS1_SHA512,
                &rng,
                data.as_ref(),
                &mut signature,
            )
            .map_err(Error::Sign)?;

        Ok(signature.as_slice().base64_encode_standard_padding())
    }
}

#[cfg(test)]
mod test {
    use super::KeyPair;

    #[test]
    fn sign() {
        if std::env::var("EXPIRED_TOKEN").is_err() {
            let key_pair = KeyPair::try_from_file("/etc/transip/home.pem").unwrap();
            let signature = key_pair.sign("{}");
            assert!(signature.is_ok());
        }
    }
}