azure-communications 0.1.1

API Wrapper for the Azure Communication Services in Rust.
Documentation
use crate::utils::{create_authorization_signature, format_utc_string};
use anyhow::Result;
use base64::{engine::general_purpose::STANDARD as base64, Engine};
use regex::Regex;
use reqwest::{
    header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_TYPE},
    Client, Url,
};
use ring::digest::{digest, SHA256};
use time::OffsetDateTime;

pub mod email;
pub mod sms;

#[derive(Debug, Clone)]
pub struct AzureCommunicationService {
    pub endpoint: String,
    pub access_key: String,
    pub request_client: Client,
}

impl AzureCommunicationService {
    pub fn new(connection_string: &str, request_client: Option<Client>) -> Self {
        let re = Regex::new(r"endpoint=(.*?);accesskey=(.*)").expect("Invalid regex");
        let caps = re
            .captures(connection_string)
            .expect("Invalid connection string");

        let endpoint = caps[1].to_string();
        let access_key = caps[2].to_string();
        let request_client = request_client.unwrap_or_default();

        AzureCommunicationService {
            endpoint: endpoint.to_string(),
            access_key: access_key.to_string(),
            request_client,
        }
    }
}

impl AzureCommunicationService {
    fn create_az_request(&self, url: Url, body: String) -> Result<reqwest::RequestBuilder> {
        let access_key = &self.access_key;
        let client = &self.request_client;

        let content_hash = digest(&SHA256, body.as_bytes());
        let content_hash_base64 = base64.encode(content_hash);

        let now = OffsetDateTime::now_utc();
        let date = format_utc_string(now)?;

        let signature = create_authorization_signature(&url, &body, access_key, &date)?;

        let mut headers = HeaderMap::new();
        headers.insert("x-ms-date", HeaderValue::from_str(&date)?);
        headers.insert(
            "x-ms-content-sha256",
            HeaderValue::from_str(&content_hash_base64)?,
        );
        headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
        headers.insert(
            AUTHORIZATION,
            HeaderValue::from_str(&format!(
                "HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature={}",
                signature
            ))?,
        );

        let request = client.post(url).headers(headers).body(body);

        Ok(request)
    }
}