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}