azure_storage/shared_access_signature/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
use std::fmt;
use time::OffsetDateTime;

pub mod account_sas;
pub mod service_sas;

pub trait SasToken {
    fn token(&self) -> azure_core::Result<String>;
}

/// Converts an `OffsetDateTime` to an RFC3339 formatted string after truncating
/// any partial seconds.
pub(crate) fn format_date(d: OffsetDateTime) -> String {
    // When validating signatures, Azure Storage server creates a canonicalized
    // version of the request, then verifies the signature from the request with
    // the canonicalized version.
    //
    // The canonicalization at the server truncates the timestamps without
    // microseconds or nanoseconds.  As such, this needs to be truncated here
    // too.
    //
    // replacing nanosecond with 0 is known to not panic
    azure_core::date::to_rfc3339(&d.replace_nanosecond(0).unwrap())
}

/// Specifies the protocol permitted for a request made with the SAS ([Azure documentation](https://docs.microsoft.com/rest/api/storageservices/create-service-sas#specifying-the-http-protocol)).
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum SasProtocol {
    Https,
    HttpHttps,
}

impl fmt::Display for SasProtocol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SasProtocol::Https => write!(f, "https"),
            SasProtocol::HttpHttps => write!(f, "http,https"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use time::macros::datetime;

    #[test]
    // verify format_date truncates as expected.
    fn test_format_date_truncation() {
        let date = datetime!(2022-08-22 15:11:43.4185122 +00:00:00);
        assert_eq!(format_date(date), "2022-08-22T15:11:43Z");
    }
}