identity_credential/sd_jwt_vc/metadata/integrity.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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
use std::fmt::Display;
use std::str::FromStr;
use anyhow::anyhow;
use identity_core::convert::Base;
use identity_core::convert::BaseEncoding;
use serde::Deserialize;
use serde::Serialize;
/// An integrity metadata string as defined in [W3C SRI](https://www.w3.org/TR/SRI/#integrity-metadata).
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(try_from = "String")]
pub struct IntegrityMetadata(String);
impl IntegrityMetadata {
/// Parses an [`IntegrityMetadata`] from a string.
/// ## Example
/// ```rust
/// use identity_credential::sd_jwt_vc::metadata::IntegrityMetadata;
///
/// let integrity_data = IntegrityMetadata::parse(
/// "sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd",
/// )
/// .unwrap();
/// ```
pub fn parse(s: &str) -> Result<Self, anyhow::Error> {
s.parse()
}
/// Returns the digest algorithm's identifier string.
/// ## Example
/// ```rust
/// use identity_credential::sd_jwt_vc::metadata::IntegrityMetadata;
///
/// let integrity_data: IntegrityMetadata =
/// "sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd"
/// .parse()
/// .unwrap();
/// assert_eq!(integrity_data.alg(), "sha384");
/// ```
pub fn alg(&self) -> &str {
self.0.split_once('-').unwrap().0
}
/// Returns the base64 encoded digest part.
/// ## Example
/// ```rust
/// use identity_credential::sd_jwt_vc::metadata::IntegrityMetadata;
///
/// let integrity_data: IntegrityMetadata =
/// "sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd"
/// .parse()
/// .unwrap();
/// assert_eq!(
/// integrity_data.digest(),
/// "dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd"
/// );
/// ```
pub fn digest(&self) -> &str {
self.0.split('-').nth(1).unwrap()
}
/// Returns the digest's bytes.
pub fn digest_bytes(&self) -> Vec<u8> {
BaseEncoding::decode(self.digest(), Base::Base64).unwrap()
}
/// Returns the option part.
/// ## Example
/// ```rust
/// use identity_credential::sd_jwt_vc::metadata::IntegrityMetadata;
///
/// let integrity_data: IntegrityMetadata =
/// "sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd"
/// .parse()
/// .unwrap();
/// assert!(integrity_data.options().is_none());
/// ```
pub fn options(&self) -> Option<&str> {
self.0.splitn(3, '-').nth(2)
}
}
impl AsRef<str> for IntegrityMetadata {
fn as_ref(&self) -> &str {
self.0.as_str()
}
}
impl Display for IntegrityMetadata {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.0)
}
}
impl FromStr for IntegrityMetadata {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s.to_owned())
}
}
impl TryFrom<String> for IntegrityMetadata {
type Error = anyhow::Error;
fn try_from(value: String) -> Result<Self, Self::Error> {
let mut metadata_parts = value.splitn(3, '-');
let _alg = metadata_parts
.next()
.ok_or_else(|| anyhow!("invalid integrity metadata"))?;
let _digest = metadata_parts
.next()
.and_then(|digest| BaseEncoding::decode(digest, Base::Base64).ok())
.ok_or_else(|| anyhow!("invalid integrity metadata"))?;
let _options = metadata_parts.next();
Ok(Self(value))
}
}