credential_exchange_format/
b64url.rs1use data_encoding::{Specification, BASE32_NOPAD, BASE64URL, BASE64URL_NOPAD};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
6#[serde(try_from = "&str", into = "String")]
7pub struct B64Url(Vec<u8>);
8
9impl From<Vec<u8>> for B64Url {
10 fn from(src: Vec<u8>) -> Self {
11 Self(src)
12 }
13}
14impl From<&[u8]> for B64Url {
15 fn from(src: &[u8]) -> Self {
16 Self(src.to_vec())
17 }
18}
19
20impl From<B64Url> for Vec<u8> {
21 fn from(src: B64Url) -> Self {
22 src.0
23 }
24}
25
26impl AsRef<[u8]> for B64Url {
27 fn as_ref(&self) -> &[u8] {
28 &self.0
29 }
30}
31
32impl From<B64Url> for String {
33 fn from(src: B64Url) -> Self {
34 String::from(&src)
35 }
36}
37impl From<&B64Url> for String {
38 fn from(src: &B64Url) -> Self {
39 BASE64URL_NOPAD.encode(&src.0)
40 }
41}
42
43impl std::fmt::Display for B64Url {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 f.write_str(String::from(self).as_str())
46 }
47}
48
49#[derive(Debug)]
51pub struct NotB64UrlEncoded;
52
53impl std::fmt::Display for NotB64UrlEncoded {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.write_str("Data isn't base64url encoded")
56 }
57}
58
59impl TryFrom<&str> for B64Url {
60 type Error = NotB64UrlEncoded;
61
62 fn try_from(value: &str) -> Result<Self, Self::Error> {
63 let specs = BASE64URL.specification();
64 let padding = specs.padding.unwrap();
65 let specs = Specification {
66 check_trailing_bits: false,
67 padding: None,
68 ..specs
69 };
70 let encoding = specs.encoding().unwrap();
71 let sane_string = value.trim_end_matches(padding);
72 encoding
73 .decode(sane_string.as_bytes())
74 .map(Self)
75 .map_err(|_| NotB64UrlEncoded)
76 }
77}
78
79#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
81#[serde(try_from = "&str", into = "String")]
82pub struct B32(Vec<u8>);
83
84impl From<Vec<u8>> for B32 {
85 fn from(src: Vec<u8>) -> Self {
86 Self(src)
87 }
88}
89impl From<&[u8]> for B32 {
90 fn from(src: &[u8]) -> Self {
91 Self(src.to_vec())
92 }
93}
94
95impl From<B32> for Vec<u8> {
96 fn from(src: B32) -> Self {
97 src.0
98 }
99}
100
101impl AsRef<[u8]> for B32 {
102 fn as_ref(&self) -> &[u8] {
103 &self.0
104 }
105}
106
107impl From<B32> for String {
108 fn from(src: B32) -> Self {
109 BASE32_NOPAD.encode(&src.0)
110 }
111}
112
113#[derive(Debug)]
115pub struct NotBase32Encoded;
116
117impl std::fmt::Display for NotBase32Encoded {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 f.write_str("Data isn't base32 encoded")
120 }
121}
122
123impl TryFrom<&str> for B32 {
124 type Error = NotBase32Encoded;
125
126 fn try_from(value: &str) -> Result<Self, Self::Error> {
127 let symbols = BASE32_NOPAD.specification().symbols;
128 let mut sane_string: String = value.to_ascii_uppercase();
129 sane_string.retain(|c| symbols.contains(c));
130 BASE32_NOPAD
131 .decode(sane_string.as_bytes())
132 .map(Self)
133 .map_err(|_| NotBase32Encoded)
134 }
135}