rocket_community/mtls/
name.rs

1use std::fmt;
2use std::ops::Deref;
3
4use ref_cast::RefCast;
5
6use crate::mtls::oid;
7use crate::mtls::x509::X509Name;
8
9/// An X.509 Distinguished Name (DN) found in a
10/// [`Certificate`](crate::mtls::Certificate).
11///
12/// This type is a wrapper over [`X509Name`] with convenient methods and
13/// complete documentation. Should the data exposed by the inherent methods not
14/// suffice, this type derefs to [`X509Name`].
15#[repr(transparent)]
16#[derive(Debug, PartialEq, RefCast)]
17pub struct Name<'a>(X509Name<'a>);
18
19impl<'a> Name<'a> {
20    /// Returns the _first_ UTF-8 _string_ common name, if any.
21    ///
22    /// Note that common names need not be UTF-8 strings, or strings at all.
23    /// This method returns the first common name attribute that is.
24    ///
25    /// # Example
26    ///
27    /// ```rust
28    /// # #[macro_use] extern crate rocket_community as rocket;
29    /// use rocket::mtls::Certificate;
30    ///
31    /// #[get("/auth")]
32    /// fn auth(cert: Certificate<'_>) {
33    ///     if let Some(name) = cert.subject().common_name() {
34    ///         println!("Hello, {}!", name);
35    ///     }
36    /// }
37    /// ```
38    pub fn common_name(&self) -> Option<&'a str> {
39        self.common_names().next()
40    }
41
42    /// Returns an iterator over all of the UTF-8 _string_ common names in
43    /// `self`.
44    ///
45    /// Note that common names need not be UTF-8 strings, or strings at all.
46    /// This method filters the common names in `self` to those that are. Use
47    /// the raw [`iter_common_name()`](#method.iter_common_name) to iterate over
48    /// all value types.
49    ///
50    /// # Example
51    ///
52    /// ```rust
53    /// # #[macro_use] extern crate rocket_community as rocket;
54    /// use rocket::mtls::Certificate;
55    ///
56    /// #[get("/auth")]
57    /// fn auth(cert: Certificate<'_>) {
58    ///     for name in cert.issuer().common_names() {
59    ///         println!("Issued by {}.", name);
60    ///     }
61    /// }
62    /// ```
63    pub fn common_names(&self) -> impl Iterator<Item = &'a str> + '_ {
64        self.iter_by_oid(&oid::OID_X509_COMMON_NAME)
65            .filter_map(|n| n.as_str().ok())
66    }
67
68    /// Returns the _first_ UTF-8 _string_ email address, if any.
69    ///
70    /// Note that email addresses need not be UTF-8 strings, or strings at all.
71    /// This method returns the first email address attribute that is.
72    ///
73    /// # Example
74    ///
75    /// ```rust
76    /// # #[macro_use] extern crate rocket_community as rocket;
77    /// use rocket::mtls::Certificate;
78    ///
79    /// #[get("/auth")]
80    /// fn auth(cert: Certificate<'_>) {
81    ///     if let Some(email) = cert.subject().email() {
82    ///         println!("Hello, {}!", email);
83    ///     }
84    /// }
85    /// ```
86    pub fn email(&self) -> Option<&'a str> {
87        self.emails().next()
88    }
89
90    /// Returns an iterator over all of the UTF-8 _string_ email addresses in
91    /// `self`.
92    ///
93    /// Note that email addresses need not be UTF-8 strings, or strings at all.
94    /// This method filters the email address in `self` to those that are. Use
95    /// the raw [`iter_email()`](#method.iter_email) to iterate over all value
96    /// types.
97    ///
98    /// # Example
99    ///
100    /// ```rust
101    /// # #[macro_use] extern crate rocket_community as rocket;
102    /// use rocket::mtls::Certificate;
103    ///
104    /// #[get("/auth")]
105    /// fn auth(cert: Certificate<'_>) {
106    ///     for email in cert.subject().emails() {
107    ///         println!("Reach me at: {}", email);
108    ///     }
109    /// }
110    /// ```
111    pub fn emails(&self) -> impl Iterator<Item = &'a str> + '_ {
112        self.iter_by_oid(&oid::OID_PKCS9_EMAIL_ADDRESS)
113            .filter_map(|n| n.as_str().ok())
114    }
115
116    /// Returns `true` if `self` has no data.
117    ///
118    /// When this is the case for a `subject()`, the subject data can be found
119    /// in the `subjectAlt` [`extension`].
120    ///
121    /// [`extension`]: crate::mtls::Certificate::extensions()
122    ///
123    /// # Example
124    ///
125    /// ```rust
126    /// # #[macro_use] extern crate rocket_community as rocket;
127    /// use rocket::mtls::Certificate;
128    ///
129    /// #[get("/auth")]
130    /// fn auth(cert: Certificate<'_>) {
131    ///     let no_data = cert.subject().is_empty();
132    /// }
133    /// ```
134    pub fn is_empty(&self) -> bool {
135        self.0.as_raw().is_empty()
136    }
137}
138
139impl<'a> Deref for Name<'a> {
140    type Target = X509Name<'a>;
141
142    fn deref(&self) -> &Self::Target {
143        &self.0
144    }
145}
146
147impl fmt::Display for Name<'_> {
148    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149        self.0.fmt(f)
150    }
151}