unc_jsonrpc_client/
auth.rs1use std::ops::{Index, RangeFrom};
58use std::str;
59
60use super::header::{HeaderValue, InvalidHeaderValue, ToStrError};
61
62#[derive(Eq, Hash, Clone, Debug, PartialEq)]
64pub struct ApiKey(HeaderValue);
65
66impl ApiKey {
67 pub const HEADER_NAME: &'static str = "x-api-key";
68
69 pub fn new<K: AsRef<[u8]>>(api_key: K) -> Result<Self, InvalidHeaderValue> {
73 HeaderValue::from_bytes(api_key.as_ref()).map(|mut api_key| {
74 ApiKey({
75 api_key.set_sensitive(true);
76 api_key
77 })
78 })
79 }
80
81 pub fn to_str(&self) -> Result<&str, ToStrError> {
83 self.0.to_str()
84 }
85
86 pub fn as_bytes(&self) -> &[u8] {
88 self.0.as_bytes()
89 }
90}
91
92impl crate::header::HeaderEntry for ApiKey {
93 type HeaderName = &'static str;
94 type HeaderValue = HeaderValue;
95
96 fn header_name(&self) -> &Self::HeaderName {
97 &Self::HEADER_NAME
98 }
99
100 fn header_pair(self) -> (Self::HeaderName, Self::HeaderValue) {
101 (Self::HEADER_NAME, self.0)
102 }
103}
104
105#[derive(Eq, Hash, Copy, Clone, Debug, PartialEq)]
107#[non_exhaustive]
108pub enum AuthorizationScheme {
109 Bearer,
110}
111
112#[derive(Eq, Hash, Clone, Debug, PartialEq)]
114pub struct Authorization(AuthorizationScheme, HeaderValue);
115
116impl Authorization {
117 pub const HEADER_NAME: &'static str = "Authorization";
118
119 pub fn bearer<T: AsRef<str>>(token: T) -> Result<Self, InvalidHeaderValue> {
125 HeaderValue::from_bytes(&[b"Bearer ", token.as_ref().as_bytes()].concat()).map(
126 |mut token| {
127 Authorization(AuthorizationScheme::Bearer, {
128 token.set_sensitive(true);
129 token
130 })
131 },
132 )
133 }
134
135 pub fn scheme(&self) -> AuthorizationScheme {
137 self.0
138 }
139
140 pub fn as_str(&self) -> &str {
142 unsafe { str::from_utf8_unchecked(self.as_bytes()) }
143 }
144
145 pub fn as_bytes(&self) -> &[u8] {
147 self.strip_scheme(self.1.as_bytes())
148 }
149
150 fn strip_scheme<'a, T: Index<RangeFrom<usize>> + ?Sized>(&self, token: &'a T) -> &'a T::Output {
151 &token[match self.0 {
152 AuthorizationScheme::Bearer => 7,
153 }..]
154 }
155}
156
157impl crate::header::HeaderEntry for Authorization {
158 type HeaderName = &'static str;
159 type HeaderValue = HeaderValue;
160
161 fn header_name(&self) -> &Self::HeaderName {
162 &Self::HEADER_NAME
163 }
164
165 fn header_pair(self) -> (Self::HeaderName, Self::HeaderValue) {
166 (Self::HEADER_NAME, self.1)
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn sensitive_debug() {
176 let api_key = ApiKey::new("this is a very secret secret").expect("valid API key");
177
178 assert_eq!(format!("{:?}", api_key), "ApiKey(Sensitive)");
179
180 assert_eq!(
181 api_key.to_str().expect("valid utf8 secret"),
182 "this is a very secret secret"
183 );
184
185 assert_eq!(api_key.as_bytes(), b"this is a very secret secret");
186 }
187
188 #[test]
189 fn bearer_token() {
190 let token = Authorization::bearer("this is a very secret token").expect("valid token");
191
192 assert_eq!(format!("{:?}", token), "Authorization(Bearer, Sensitive)");
193
194 assert_eq!(token.scheme(), AuthorizationScheme::Bearer);
195
196 assert_eq!(token.as_str(), "this is a very secret token");
197
198 assert_eq!(token.as_bytes(), b"this is a very secret token");
199 }
200}