pkce_std/verifier.rs
1//! PKCE code verifiers.
2//!
3//! The [`Verifier<'_>`] type represents PKCE code verifiers, which are strings
4//! that consist of valid characters (see [`string`]) and have certain lengths
5//! (see [`length`]).
6//!
7//! # Examples
8//!
9//! Generating random verifiers:
10//!
11//! ```
12//! use pkce_std::{length::Length, verifier::Verifier};
13//!
14//! let length = Length::default();
15//!
16//! let verifier = Verifier::generate(length);
17//! let other = Verifier::generate(length);
18//!
19//! assert_ne!(verifier, other);
20//! ```
21//!
22//! Generating verifiers from random bytes:
23//!
24//! ```
25//! use pkce_std::{count::Count, verifier::Verifier};
26//!
27//! let count = Count::default();
28//!
29//! let verifier = Verifier::generate_encode(count);
30//! let other = Verifier::generate_encode(count);
31//!
32//! assert_ne!(verifier, other);
33//! ```
34//!
35//! [`Verifier<'_>`]: Verifier
36
37use std::{
38 borrow::Cow,
39 fmt,
40 hash::{Hash, Hasher},
41};
42
43use const_macros::{const_map_err, const_none, const_ok, const_try};
44use constant_time_eq::constant_time_eq;
45
46#[cfg(feature = "static")]
47use into_static::IntoStatic;
48
49#[cfg(feature = "diagnostics")]
50use miette::Diagnostic;
51
52#[cfg(feature = "serde")]
53use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
54
55use thiserror::Error;
56
57use crate::{
58 challenge::Challenge,
59 check::string::{self, const_check_str},
60 count::{self, Count},
61 encoding, generate,
62 length::{self, Length},
63 method::Method,
64};
65
66/// Represents the error message for invalid verifiers.
67pub const ERROR: &str = "invalid verifier; check the length and characters";
68
69/// Represents errors that can occur when constructing verifiers.
70///
71/// There are two cases when constructing can fail:
72///
73/// - [`Length::check`] fails, which means that the length of the string is invalid;
74/// - [`string::check`] fails, which means the string contains invalid characters.
75#[derive(Debug, Error)]
76#[cfg_attr(feature = "diagnostics", derive(Diagnostic))]
77pub enum Error {
78 /// Invalid verifier length.
79 #[error("invalid verifier length")]
80 #[cfg_attr(
81 feature = "diagnostics",
82 diagnostic(
83 code(pkce_std::verifier::length),
84 help("check the length of the verifier")
85 )
86 )]
87 Length(#[from] length::Error),
88
89 /// Invalid character(s) in verifier.
90 #[error("verifier contains invalid character(s)")]
91 #[cfg_attr(
92 feature = "diagnostics",
93 diagnostic(
94 code(pkce_std::verifier::check),
95 help("make sure the verifier is composed of valid characters only")
96 )
97 )]
98 String(#[from] string::Error),
99}
100
101/// Represents PKCE code verifiers.
102///
103/// Refer to the [module] documentation for more information.
104///
105/// # Examples
106///
107/// ```
108/// use pkce_std::verifier::Verifier;
109///
110/// let string = "dGhhbmtzIGZvciByZWFkaW5nIGRvY3MhIH4gbmVraXQ";
111///
112/// let expected = Verifier::borrowed(string).unwrap();
113///
114/// let bytes = "thanks for reading docs! ~ nekit";
115///
116/// let verifier = Verifier::encode(bytes).unwrap();
117///
118/// // `verifier` and `expected` are compared in constant time!
119/// assert_eq!(verifier, expected);
120/// ```
121///
122/// [module]: self
123#[derive(Debug, Clone)]
124pub struct Verifier<'v> {
125 value: Cow<'v, str>,
126}
127
128#[cfg(feature = "serde")]
129impl Serialize for Verifier<'_> {
130 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
131 self.get().serialize(serializer)
132 }
133}
134
135#[cfg(feature = "serde")]
136impl<'de> Deserialize<'de> for Verifier<'_> {
137 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
138 let value = Cow::deserialize(deserializer)?;
139
140 Self::new(value).map_err(de::Error::custom)
141 }
142}
143
144impl fmt::Display for Verifier<'_> {
145 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
146 self.get().fmt(formatter)
147 }
148}
149
150impl Verifier<'_> {
151 /// Returns the borrowed string.
152 pub fn get(&self) -> &str {
153 self.value.as_ref()
154 }
155}
156
157impl AsRef<str> for Verifier<'_> {
158 fn as_ref(&self) -> &str {
159 self.get()
160 }
161}
162
163impl PartialEq for Verifier<'_> {
164 fn eq(&self, other: &Self) -> bool {
165 constant_time_eq(self.get().as_bytes(), other.get().as_bytes())
166 }
167}
168
169impl Eq for Verifier<'_> {}
170
171impl Hash for Verifier<'_> {
172 fn hash<H: Hasher>(&self, hasher: &mut H) {
173 self.get().hash(hasher);
174 }
175}
176
177impl Verifier<'_> {
178 /// Generates random [`Self`] with specified length.
179 pub fn generate(length: Length) -> Self {
180 // SAFETY: `generate::string(length)` creates valid values for `Self`,
181 // meaning that their length is exactly `length` and they consist of valid characters.
182 unsafe { Self::owned_unchecked(generate::string(length)) }
183 }
184
185 /// Generates random [`Self`] with default length.
186 pub fn generate_default() -> Self {
187 Self::generate(Length::default())
188 }
189
190 /// Generates `count` random bytes length and encodes them into [`Self`].
191 pub fn generate_encode(count: Count) -> Self {
192 // SAFETY: `generate::bytes(count)` creates valid values for `Self::encode_unchecked`,
193 // meaning that their length is exactly `count`.
194 unsafe { Self::encode_unchecked(generate::bytes(count)) }
195 }
196
197 /// Generates random bytes of default length and encodes them into [`Self`].
198 pub fn generate_encode_default() -> Self {
199 Self::generate_encode(Count::default())
200 }
201}
202
203impl Verifier<'_> {
204 /// Computes the [`Challenge`] of [`Self`] with the given [`Method`].
205 pub fn challenge_using(&self, method: Method) -> Challenge {
206 Challenge::create_using(method, self)
207 }
208
209 /// Computes the [`Challenge`] of [`Self`] with the default [`Method`].
210 pub fn challenge(&self) -> Challenge {
211 self.challenge_using(Method::default())
212 }
213
214 /// Verifies the given [`Challenge`] against [`Self`].
215 pub fn verify(&self, challenge: &Challenge) -> bool {
216 let expected = self.challenge_using(challenge.method());
217
218 challenge == &expected
219 }
220}
221
222impl<'v> Verifier<'v> {
223 /// Constructs [`Self`], provided that the given value is valid.
224 ///
225 /// # Errors
226 ///
227 /// See [`Self::check`] for more information.
228 pub fn new(value: Cow<'v, str>) -> Result<Self, Error> {
229 Self::check(value.as_ref())?;
230
231 // SAFETY: `value` consists of valid characters
232 // and its length is in the valid range for `Self`
233 Ok(unsafe { Self::new_unchecked(value) })
234 }
235
236 /// Constructs [`Self`] without checking the value.
237 ///
238 /// # Safety
239 ///
240 /// The caller must ensure that `value` is valid for [`Self`].
241 ///
242 /// The value can be checked using [`Self::check`].
243 pub const unsafe fn new_unchecked(value: Cow<'v, str>) -> Self {
244 Self { value }
245 }
246
247 /// Constructs [`Self`] from borrowed `value`, provided it is valid.
248 ///
249 /// # Errors
250 ///
251 /// See [`Self::new`] for more information.
252 pub fn borrowed(value: &'v str) -> Result<Self, Error> {
253 Self::new(Cow::Borrowed(value))
254 }
255
256 /// Constructs [`Self`] from borrowed `value` without checking it.
257 ///
258 /// # Safety
259 ///
260 /// See [`Self::new_unchecked`] for more information.
261 pub const unsafe fn borrowed_unchecked(value: &'v str) -> Self {
262 // SAFETY: this function is `unsafe`, so the caller must ensure
263 // that `value` is valid for `Self`
264 unsafe { Self::new_unchecked(Cow::Borrowed(value)) }
265 }
266
267 /// Constructs [`Self`] from owned `value`, provided it is valid.
268 ///
269 /// # Errors
270 ///
271 /// See [`Self::new`] for more information.
272 pub fn owned(value: String) -> Result<Self, Error> {
273 Self::new(Cow::Owned(value))
274 }
275
276 /// Constructs [`Self`] from owned `value` without checking it.
277 ///
278 /// # Safety
279 ///
280 /// See [`Self::new_unchecked`] for more information.
281 pub const unsafe fn owned_unchecked(value: String) -> Self {
282 // SAFETY: this function is `unsafe`, so the caller must ensure
283 // that `value` is valid for `Self`
284 unsafe { Self::new_unchecked(Cow::Owned(value)) }
285 }
286
287 /// Similar to [`borrowed`], but can be used in `const` contexts.
288 ///
289 /// # Note
290 ///
291 /// One may need to increase the recursion limit when using longer strings.
292 ///
293 /// This is done via applying the `recursion_limit` attribute to the crate:
294 ///
295 /// ```
296 /// #![recursion_limit = "256"]
297 /// ```
298 ///
299 /// # Errors
300 ///
301 /// See [`const_check_str`] for more information.
302 ///
303 /// [`borrowed`]: Self::borrowed
304 /// [`const_check_str`]: Self::const_check_str
305 pub const fn const_borrowed(value: &'v str) -> Result<Self, Error> {
306 const_try!(Self::const_check_str(value));
307
308 // SAFETY: `value` is valid for `Self` here
309 Ok(unsafe { Self::borrowed_unchecked(value) })
310 }
311
312 /// Similar to [`const_borrowed`], but errors are discarded.
313 ///
314 /// [`const_borrowed`]: Self::const_borrowed
315 pub const fn const_borrowed_ok(value: &'v str) -> Option<Self> {
316 const_none!(const_ok!(Self::const_check_str(value)));
317
318 // SAFETY: `value` is valid for `Self` here
319 Some(unsafe { Self::borrowed_unchecked(value) })
320 }
321
322 /// Constantly checks if the given string is valid for [`Self`].
323 ///
324 /// # Note
325 ///
326 /// One may need to increase the recursion limit when checking longer strings.
327 ///
328 /// This is done via applying the `recursion_limit` attribute to the crate:
329 ///
330 /// ```
331 /// #![recursion_limit = "256"]
332 /// ```
333 ///
334 /// # Errors
335 ///
336 /// Returns [`enum@Error`] if the string is invalid, which means either:
337 ///
338 /// - the length of the string is invalid (see [`Length::check`]);
339 /// - the string contains invalid character(s) (see [`string::check`]).
340 pub const fn const_check_str(string: &str) -> Result<(), Error> {
341 const_try!(const_map_err!(Length::check(string.len()) => Error::Length));
342
343 const_try!(const_map_err!(const_check_str(string) => Error::String));
344
345 Ok(())
346 }
347
348 /// Checks if the given string is valid for [`Self`].
349 ///
350 /// # Errors
351 ///
352 /// Returns [`enum@Error`] if the string is invalid, which means either:
353 ///
354 /// - the length of the string is invalid (see [`Length::check`]);
355 /// - the string contains invalid character(s) (see [`string::check`]).
356 pub fn check_str(string: &str) -> Result<(), Error> {
357 Length::check(string.len())?;
358
359 string::check_str(string)?;
360
361 Ok(())
362 }
363
364 /// Similar to [`check_str`], except it is generic over [`AsRef<str>`].
365 ///
366 /// # Errors
367 ///
368 /// Any [`enum@Error`] returned by [`check_str`] is propagated.
369 ///
370 /// [`check_str`]: Self::check_str
371 pub fn check<S: AsRef<str>>(value: S) -> Result<(), Error> {
372 Self::check_str(value.as_ref())
373 }
374
375 /// Consumes [`Self`] and returns the contained string.
376 pub fn take(self) -> Cow<'v, str> {
377 self.value
378 }
379}
380
381impl Verifier<'_> {
382 /// Encodes the given `bytes` into [`Self`], provided `bytes` has valid length.
383 ///
384 /// # Errors
385 ///
386 /// Returns [`count::Error`] if the length of `bytes` is invalid.
387 pub fn encode<B: AsRef<[u8]>>(bytes: B) -> Result<Self, count::Error> {
388 Count::check(bytes.as_ref().len())?;
389
390 // SAFETY: `bytes` has length in the valid range for `Self::encode_unchecked`
391 Ok(unsafe { Self::encode_unchecked(bytes) })
392 }
393
394 /// Encodes the given `bytes` into [`Self`] without checking `bytes` length.
395 ///
396 /// # Safety
397 ///
398 /// The caller must ensure that `bytes` has valid length.
399 ///
400 /// The `bytes` can be checked using [`Count::check`] on its length.
401 pub unsafe fn encode_unchecked<B: AsRef<[u8]>>(bytes: B) -> Self {
402 let string = encoding::encode(bytes);
403
404 // SAFETY: this function is `unsafe`, so the caller must ensure that `bytes`
405 // has length in the valid range for encoding, which produces valid values for `Self`
406 unsafe { Self::owned_unchecked(string) }
407 }
408}
409
410/// Constructs [`Verifier`] from `value`, panicking if it is invalid.
411#[macro_export]
412macro_rules! const_borrowed_verifier {
413 ($value: expr) => {
414 $crate::verifier::Verifier::const_borrowed_ok($value).expect($crate::verifier::ERROR)
415 };
416}
417
418/// An alias for [`Verifier<'static>`].
419#[cfg(feature = "static")]
420pub type StaticVerifier = Verifier<'static>;
421
422#[cfg(feature = "static")]
423impl IntoStatic for Verifier<'_> {
424 type Static = StaticVerifier;
425
426 fn into_static(self) -> Self::Static {
427 // SAFETY: calling `into_static` does not change `value` validity
428 unsafe { Self::Static::new_unchecked(self.value.into_static()) }
429 }
430}