rocket/mtls/name.rs
1use std::fmt;
2use std::ops::Deref;
3
4use ref_cast::RefCast;
5
6use crate::mtls::x509::X509Name;
7use crate::mtls::oid;
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;
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;
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).filter_map(|n| n.as_str().ok())
65 }
66
67 /// Returns the _first_ UTF-8 _string_ email address, if any.
68 ///
69 /// Note that email addresses need not be UTF-8 strings, or strings at all.
70 /// This method returns the first email address attribute that is.
71 ///
72 /// # Example
73 ///
74 /// ```rust
75 /// # #[macro_use] extern crate rocket;
76 /// use rocket::mtls::Certificate;
77 ///
78 /// #[get("/auth")]
79 /// fn auth(cert: Certificate<'_>) {
80 /// if let Some(email) = cert.subject().email() {
81 /// println!("Hello, {}!", email);
82 /// }
83 /// }
84 /// ```
85 pub fn email(&self) -> Option<&'a str> {
86 self.emails().next()
87 }
88
89 /// Returns an iterator over all of the UTF-8 _string_ email addresses in
90 /// `self`.
91 ///
92 /// Note that email addresses need not be UTF-8 strings, or strings at all.
93 /// This method filters the email address in `self` to those that are. Use
94 /// the raw [`iter_email()`](#method.iter_email) to iterate over all value
95 /// types.
96 ///
97 /// # Example
98 ///
99 /// ```rust
100 /// # #[macro_use] extern crate rocket;
101 /// use rocket::mtls::Certificate;
102 ///
103 /// #[get("/auth")]
104 /// fn auth(cert: Certificate<'_>) {
105 /// for email in cert.subject().emails() {
106 /// println!("Reach me at: {}", email);
107 /// }
108 /// }
109 /// ```
110 pub fn emails(&self) -> impl Iterator<Item = &'a str> + '_ {
111 self.iter_by_oid(&oid::OID_PKCS9_EMAIL_ADDRESS).filter_map(|n| n.as_str().ok())
112 }
113
114 /// Returns `true` if `self` has no data.
115 ///
116 /// When this is the case for a `subject()`, the subject data can be found
117 /// in the `subjectAlt` [`extension`].
118 ///
119 /// [`extension`]: crate::mtls::Certificate::extensions()
120 ///
121 /// # Example
122 ///
123 /// ```rust
124 /// # #[macro_use] extern crate rocket;
125 /// use rocket::mtls::Certificate;
126 ///
127 /// #[get("/auth")]
128 /// fn auth(cert: Certificate<'_>) {
129 /// let no_data = cert.subject().is_empty();
130 /// }
131 /// ```
132 pub fn is_empty(&self) -> bool {
133 self.0.as_raw().is_empty()
134 }
135}
136
137impl<'a> Deref for Name<'a> {
138 type Target = X509Name<'a>;
139
140 fn deref(&self) -> &Self::Target {
141 &self.0
142 }
143}
144
145impl fmt::Display for Name<'_> {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 self.0.fmt(f)
148 }
149}