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}