nethsm/base/
impl_system.rs

1//! [`NetHsm`] implementation for system functionality.
2
3use std::net::Ipv4Addr;
4
5use base64ct::{Base64, Encoding};
6use chrono::{DateTime, Utc};
7use log::debug;
8use nethsm_sdk_rs::{
9    apis::default_api::{
10        config_backup_passphrase_put,
11        config_logging_get,
12        config_logging_put,
13        config_network_get,
14        config_network_put,
15        config_time_get,
16        config_time_put,
17        config_tls_cert_pem_get,
18        config_tls_cert_pem_put,
19        config_tls_csr_pem_post,
20        config_tls_generate_post,
21        config_tls_public_pem_get,
22        config_unattended_boot_get,
23        config_unattended_boot_put,
24        config_unlock_passphrase_put,
25        lock_post,
26        metrics_get,
27        provision_post,
28        random_post,
29        system_backup_post,
30        system_cancel_update_post,
31        system_commit_update_post,
32        system_factory_reset_post,
33        system_info_get,
34        system_reboot_post,
35        system_restore_post,
36        system_shutdown_post,
37        system_update_post,
38        unlock_post,
39    },
40    models::{
41        BackupPassphraseConfig,
42        DistinguishedName,
43        LoggingConfig,
44        NetworkConfig,
45        ProvisionRequestData,
46        RandomRequestData,
47        SystemInfo,
48        SystemUpdateData,
49        TimeConfig,
50        TlsKeyGenerateRequestData,
51        UnlockPassphraseConfig,
52        UnlockRequestData,
53    },
54};
55use serde_json::Value;
56
57use crate::{
58    BootMode,
59    Error,
60    LogLevel,
61    NetHsm,
62    Passphrase,
63    TlsKeyType,
64    base::utils::user_or_no_user_string,
65    nethsm_sdk::NetHsmApiError,
66    tls_key_type_matches_length,
67    user::NamespaceSupport,
68};
69#[cfg(doc)]
70use crate::{Credentials, SystemState, UserRole};
71
72impl NetHsm {
73    /// Provisions a NetHSM.
74    ///
75    /// [Provisioning] is the initial setup step for a NetHSM.
76    /// It sets the `unlock_passphrase`, which is used to [`unlock`][`NetHsm::unlock`] a device in
77    /// [`Locked`][`SystemState::Locked`] [state], the initial `admin_passphrase` for the
78    /// default [`Administrator`][`UserRole::Administrator`] account ("admin") and the
79    /// `system_time`. The unlock passphrase can later on be changed using
80    /// [`set_unlock_passphrase`][`NetHsm::set_unlock_passphrase`] and the admin passphrase using
81    /// [`set_user_passphrase`][`NetHsm::set_user_passphrase`].
82    ///
83    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
84    ///
85    /// # Errors
86    ///
87    /// Returns an [`Error::Api`] if provisioning fails:
88    /// * the NetHSM is not in [`Unprovisioned`][`SystemState::Unprovisioned`] [state]
89    /// * the provided data is malformed
90    ///
91    /// # Examples
92    ///
93    /// ```no_run
94    /// use chrono::Utc;
95    /// use nethsm::{Connection, ConnectionSecurity, NetHsm, Passphrase};
96    ///
97    /// # fn main() -> testresult::TestResult {
98    /// // no initial credentials are required
99    /// let nethsm = NetHsm::new(
100    ///     Connection::new(
101    ///         "https://example.org/api/v1".try_into()?,
102    ///         ConnectionSecurity::Unsafe,
103    ///     ),
104    ///     None,
105    ///     None,
106    ///     None,
107    /// )?;
108    ///
109    /// // provision the NetHSM
110    /// nethsm.provision(
111    ///     Passphrase::new("unlock-the-device".to_string()),
112    ///     Passphrase::new("admin-passphrase".to_string()),
113    ///     Utc::now(),
114    /// )?;
115    /// # Ok(())
116    /// # }
117    /// ```
118    /// [Provisioning]: https://docs.nitrokey.com/nethsm/getting-started#provisioning
119    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
120    pub fn provision(
121        &self,
122        unlock_passphrase: Passphrase,
123        admin_passphrase: Passphrase,
124        system_time: DateTime<Utc>,
125    ) -> Result<(), Error> {
126        debug!("Provision the NetHSM at {}", self.url.borrow());
127
128        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
129        provision_post(
130            &self.create_connection_config(),
131            ProvisionRequestData::new(
132                unlock_passphrase.expose_owned(),
133                admin_passphrase.expose_owned(),
134                system_time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
135            ),
136        )
137        .map_err(|error| {
138            Error::Api(format!(
139                "Provisioning failed: {}",
140                NetHsmApiError::from(error)
141            ))
142        })?;
143        Ok(())
144    }
145
146    /// Returns metrics for the NetHSM.
147    ///
148    /// Returns a [`Value`][`serde_json::Value`] which provides [metrics] for the NetHSM.
149    ///
150    /// This call requires using [`Credentials`] of a user in the [`Metrics`][`UserRole::Metrics`]
151    /// [role].
152    ///
153    /// # Errors
154    ///
155    /// Returns an [`Error::Api`] if the NetHSM [metrics] can not be retrieved:
156    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
157    /// * the used [`Credentials`] are not correct
158    /// * the used [`Credentials`] are not that of a user in the [`Metrics`][`UserRole::Metrics`]
159    ///   [role]
160    ///
161    /// # Examples
162    ///
163    /// ```no_run
164    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
165    ///
166    /// # fn main() -> testresult::TestResult {
167    /// // create a connection with a system-wide user in the Metrics role
168    /// let nethsm = NetHsm::new(
169    ///     Connection::new(
170    ///         "https://example.org/api/v1".try_into()?,
171    ///         ConnectionSecurity::Unsafe,
172    ///     ),
173    ///     Some(Credentials::new(
174    ///         "metrics".parse()?,
175    ///         Some(Passphrase::new("metrics-passphrase".to_string())),
176    ///     )),
177    ///     None,
178    ///     None,
179    /// )?;
180    ///
181    /// // retrieve the metrics
182    /// println!("{:?}", nethsm.metrics()?);
183    /// # Ok(())
184    /// # }
185    /// ```
186    /// [metrics]: https://docs.nitrokey.com/nethsm/administration#metrics
187    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
188    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
189    pub fn metrics(&self) -> Result<Value, Error> {
190        debug!(
191            "Retrieve metrics of the NetHSM at {} using {}",
192            self.url.borrow(),
193            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
194        );
195
196        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
197        let metrics = metrics_get(&self.create_connection_config()).map_err(|error| {
198            Error::Api(format!(
199                "Retrieving metrics failed: {}",
200                NetHsmApiError::from(error)
201            ))
202        })?;
203        Ok(metrics.entity)
204    }
205
206    /// Sets the [unlock passphrase].
207    ///
208    /// Changes the [unlock passphrase] from `current_passphrase` to `new_passphrase`.
209    ///
210    /// This call requires using [`Credentials`] of a system-wide user in the
211    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
212    ///
213    /// # Errors
214    ///
215    /// Returns an [`Error::Api`] if the [unlock passphrase] can not be changed:
216    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
217    /// * the provided `current_passphrase` is not correct
218    /// * the used [`Credentials`] are not correct
219    /// * the used [`Credentials`] are not that of a system-wide user in the
220    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
221    ///
222    /// # Examples
223    ///
224    /// ```no_run
225    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
226    ///
227    /// # fn main() -> testresult::TestResult {
228    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
229    /// let nethsm = NetHsm::new(
230    ///     Connection::new(
231    ///         "https://example.org/api/v1".try_into()?,
232    ///         ConnectionSecurity::Unsafe,
233    ///     ),
234    ///     Some(Credentials::new(
235    ///         "admin".parse()?,
236    ///         Some(Passphrase::new("passphrase".to_string())),
237    ///     )),
238    ///     None,
239    ///     None,
240    /// )?;
241    /// // add a user in the Administrator role for a namespace (N-Administrator)
242    /// nethsm.add_user(
243    ///     "Namespace1 Admin".to_string(),
244    ///     UserRole::Administrator,
245    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
246    ///     Some("namespace1~admin1".parse()?),
247    /// )?;
248    /// // create accompanying namespace
249    /// nethsm.add_namespace(&"namespace1".parse()?)?;
250    ///
251    /// // R-Administrators can set the unlock passphrase
252    /// nethsm.set_unlock_passphrase(
253    ///     Passphrase::new("current-unlock-passphrase".to_string()),
254    ///     Passphrase::new("new-unlock-passphrase".to_string()),
255    /// )?;
256    ///
257    /// // N-Administrators can not set the unlock passphrase
258    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
259    /// assert!(
260    ///     nethsm
261    ///         .set_unlock_passphrase(
262    ///             Passphrase::new("current-unlock-passphrase".to_string()),
263    ///             Passphrase::new("new-unlock-passphrase".to_string()),
264    ///         )
265    ///         .is_err()
266    /// );
267    /// # Ok(())
268    /// # }
269    /// ```
270    /// [unlock passphrase]: https://docs.nitrokey.com/nethsm/administration#unlock-passphrase
271    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
272    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
273    pub fn set_unlock_passphrase(
274        &self,
275        current_passphrase: Passphrase,
276        new_passphrase: Passphrase,
277    ) -> Result<(), Error> {
278        debug!(
279            "Set unlock passphrase for the NetHSM at {} using {}",
280            self.url.borrow(),
281            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
282        );
283
284        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
285        config_unlock_passphrase_put(
286            &self.create_connection_config(),
287            UnlockPassphraseConfig::new(
288                new_passphrase.expose_owned(),
289                current_passphrase.expose_owned(),
290            ),
291        )
292        .map_err(|error| {
293            Error::Api(format!(
294                "Changing unlock passphrase failed: {}",
295                NetHsmApiError::from(error)
296            ))
297        })?;
298        Ok(())
299    }
300
301    /// Returns the [boot mode].
302    ///
303    /// Returns a variant of [`BootMode`] which represents the NetHSM's [boot mode].
304    ///
305    /// This call requires using [`Credentials`] of a system-wide user in the
306    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
307    ///
308    /// # Errors
309    ///
310    /// Returns an [`Error::Api`] if the boot mode can not be retrieved:
311    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
312    /// * the used [`Credentials`] are not correct
313    /// * the used [`Credentials`] are not that of a system-wide user in the
314    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
315    ///
316    /// # Examples
317    ///
318    /// ```no_run
319    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
320    ///
321    /// # fn main() -> testresult::TestResult {
322    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
323    /// let nethsm = NetHsm::new(
324    ///     Connection::new(
325    ///         "https://example.org/api/v1".try_into()?,
326    ///         ConnectionSecurity::Unsafe,
327    ///     ),
328    ///     Some(Credentials::new(
329    ///         "admin".parse()?,
330    ///         Some(Passphrase::new("passphrase".to_string())),
331    ///     )),
332    ///     None,
333    ///     None,
334    /// )?;
335    /// // add a user in the Administrator role for a namespace (N-Administrator)
336    /// nethsm.add_user(
337    ///     "Namespace1 Admin".to_string(),
338    ///     UserRole::Administrator,
339    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
340    ///     Some("namespace1~admin1".parse()?),
341    /// )?;
342    /// // create accompanying namespace
343    /// nethsm.add_namespace(&"namespace1".parse()?)?;
344    ///
345    /// // R-Administrators can retrieve the boot mode
346    /// println!("{:?}", nethsm.get_boot_mode()?);
347    ///
348    /// // N-Administrators can not retrieve the boot mode
349    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
350    /// assert!(nethsm.get_boot_mode().is_err());
351    /// # Ok(())
352    /// # }
353    /// ```
354    /// [boot mode]: https://docs.nitrokey.com/nethsm/administration#boot-mode
355    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
356    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
357    pub fn get_boot_mode(&self) -> Result<BootMode, Error> {
358        debug!(
359            "Get the boot mode of the NetHSM at {} using {}",
360            self.url.borrow(),
361            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
362        );
363
364        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
365        Ok(BootMode::from(
366            config_unattended_boot_get(&self.create_connection_config())
367                .map_err(|error| {
368                    Error::Api(format!(
369                        "Retrieving boot mode failed: {}",
370                        NetHsmApiError::from(error)
371                    ))
372                })?
373                .entity,
374        ))
375    }
376
377    /// Sets the [boot mode].
378    ///
379    /// Sets the NetHSM's [boot mode] based on a [`BootMode`] variant.
380    ///
381    /// This call requires using [`Credentials`] of a system-wide user in the
382    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
383    ///
384    /// # Errors
385    ///
386    /// Returns an [`Error::Api`] if the boot mode can not be set:
387    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
388    /// * the used [`Credentials`] are not correct
389    /// * the used [`Credentials`] are not that of a system-wide user in the
390    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
391    ///
392    /// # Examples
393    ///
394    /// ```no_run
395    /// use nethsm::{
396    ///     BootMode,
397    ///     Connection,
398    ///     ConnectionSecurity,
399    ///     Credentials,
400    ///     NetHsm,
401    ///     Passphrase,
402    ///     UserRole,
403    /// };
404    ///
405    /// # fn main() -> testresult::TestResult {
406    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
407    /// let nethsm = NetHsm::new(
408    ///     Connection::new(
409    ///         "https://example.org/api/v1".try_into()?,
410    ///         ConnectionSecurity::Unsafe,
411    ///     ),
412    ///     Some(Credentials::new(
413    ///         "admin".parse()?,
414    ///         Some(Passphrase::new("passphrase".to_string())),
415    ///     )),
416    ///     None,
417    ///     None,
418    /// )?;
419    /// // add a user in the Administrator role for a namespace (N-Administrator)
420    /// nethsm.add_user(
421    ///     "Namespace1 Admin".to_string(),
422    ///     UserRole::Administrator,
423    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
424    ///     Some("namespace1~admin1".parse()?),
425    /// )?;
426    /// // create accompanying namespace
427    /// nethsm.add_namespace(&"namespace1".parse()?)?;
428    ///
429    /// // R-Administrators can set the boot mode
430    /// // set the boot mode to unattended
431    /// nethsm.set_boot_mode(BootMode::Unattended)?;
432    /// // set the boot mode to attended
433    /// nethsm.set_boot_mode(BootMode::Attended)?;
434    ///
435    /// // N-Administrators can not set the boot mode
436    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
437    /// assert!(nethsm.set_boot_mode(BootMode::Attended).is_err());
438    /// # Ok(())
439    /// # }
440    /// ```
441    /// [boot mode]: https://docs.nitrokey.com/nethsm/administration#boot-mode
442    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
443    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
444    pub fn set_boot_mode(&self, boot_mode: BootMode) -> Result<(), Error> {
445        debug!(
446            "Set the boot mode for the NetHSM at {} to {boot_mode} using {}",
447            self.url.borrow(),
448            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
449        );
450
451        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
452        config_unattended_boot_put(&self.create_connection_config(), boot_mode.into()).map_err(
453            |error| {
454                Error::Api(format!(
455                    "Setting boot mode failed: {}",
456                    NetHsmApiError::from(error)
457                ))
458            },
459        )?;
460        Ok(())
461    }
462
463    /// Returns the TLS public key of the API.
464    ///
465    /// Returns the NetHSM's public key part of its [TLS certificate] which is used for
466    /// communication with the API.
467    ///
468    /// This call requires using [`Credentials`] of a system-wide user in the
469    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
470    ///
471    /// # Errors
472    ///
473    /// Returns an [`Error::Api`] if the NetHSM's TLS public key can not be retrieved:
474    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
475    /// * the used [`Credentials`] are not correct
476    /// * the used [`Credentials`] are not that of a system-wide user in the
477    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
478    ///
479    /// # Examples
480    ///
481    /// ```no_run
482    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
483    ///
484    /// # fn main() -> testresult::TestResult {
485    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
486    /// let nethsm = NetHsm::new(
487    ///     Connection::new(
488    ///         "https://example.org/api/v1".try_into()?,
489    ///         ConnectionSecurity::Unsafe,
490    ///     ),
491    ///     Some(Credentials::new(
492    ///         "admin".parse()?,
493    ///         Some(Passphrase::new("passphrase".to_string())),
494    ///     )),
495    ///     None,
496    ///     None,
497    /// )?;
498    /// // add a user in the Administrator role for a namespace (N-Administrator)
499    /// nethsm.add_user(
500    ///     "Namespace1 Admin".to_string(),
501    ///     UserRole::Administrator,
502    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
503    ///     Some("namespace1~admin1".parse()?),
504    /// )?;
505    /// // create accompanying namespace
506    /// nethsm.add_namespace(&"namespace1".parse()?)?;
507    ///
508    /// // R-Administrators can get the TLS public key
509    /// println!("{}", nethsm.get_tls_public_key()?);
510    ///
511    /// // N-Administrators can not get the TLS public key
512    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
513    /// assert!(nethsm.get_tls_public_key().is_err());
514    /// # Ok(())
515    /// # }
516    /// ```
517    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
518    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
519    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
520    pub fn get_tls_public_key(&self) -> Result<String, Error> {
521        debug!(
522            "Retrieve the TLS public key for the NetHSM at {} using {}",
523            self.url.borrow(),
524            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
525        );
526
527        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
528        Ok(config_tls_public_pem_get(&self.create_connection_config())
529            .map_err(|error| {
530                Error::Api(format!(
531                    "Retrieving API TLS public key failed: {}",
532                    NetHsmApiError::from(error)
533                ))
534            })?
535            .entity)
536    }
537
538    /// Returns the TLS certificate of the API.
539    ///
540    /// Returns the NetHSM's [TLS certificate] which is used for communication with the API.
541    ///
542    /// This call requires using [`Credentials`] of a system-wide user in the
543    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
544    ///
545    /// # Errors
546    ///
547    /// Returns an [`Error::Api`] if the NetHSM's TLS certificate can not be retrieved:
548    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
549    /// * the used [`Credentials`] are not correct
550    /// * the used [`Credentials`] are not that of a system-wide user in the
551    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
552    ///
553    /// # Examples
554    ///
555    /// ```no_run
556    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
557    ///
558    /// # fn main() -> testresult::TestResult {
559    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
560    /// let nethsm = NetHsm::new(
561    ///     Connection::new(
562    ///         "https://example.org/api/v1".try_into()?,
563    ///         ConnectionSecurity::Unsafe,
564    ///     ),
565    ///     Some(Credentials::new(
566    ///         "admin".parse()?,
567    ///         Some(Passphrase::new("passphrase".to_string())),
568    ///     )),
569    ///     None,
570    ///     None,
571    /// )?;
572    /// // add a user in the Administrator role for a namespace (N-Administrator)
573    /// nethsm.add_user(
574    ///     "Namespace1 Admin".to_string(),
575    ///     UserRole::Administrator,
576    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
577    ///     Some("namespace1~admin1".parse()?),
578    /// )?;
579    /// // create accompanying namespace
580    /// nethsm.add_namespace(&"namespace1".parse()?)?;
581    ///
582    /// // R-Administrators can get the TLS certificate
583    /// println!("{}", nethsm.get_tls_cert()?);
584    ///
585    /// // N-Administrators can not get the TLS certificate
586    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
587    /// assert!(nethsm.get_tls_cert().is_err());
588    /// # Ok(())
589    /// # }
590    /// ```
591    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
592    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
593    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
594    pub fn get_tls_cert(&self) -> Result<String, Error> {
595        debug!(
596            "Retrieve the TLS certificate for the NetHSM at {} using {}",
597            self.url.borrow(),
598            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
599        );
600
601        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
602        Ok(config_tls_cert_pem_get(&self.create_connection_config())
603            .map_err(|error| {
604                Error::Api(format!(
605                    "Retrieving API TLS certificate failed: {}",
606                    NetHsmApiError::from(error)
607                ))
608            })?
609            .entity)
610    }
611
612    /// Returns a Certificate Signing Request ([CSR]) for the API's [TLS certificate].
613    ///
614    /// Based on [`DistinguishedName`] data returns a [CSR] in [PKCS#10] format for the NetHSM's
615    /// [TLS certificate].
616    ///
617    /// This call requires using [`Credentials`] of a system-wide user in the
618    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
619    ///
620    /// # Errors
621    ///
622    /// Returns an [`Error::Api`] if the [CSR] can not be retrieved:
623    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
624    /// * the used [`Credentials`] are not correct
625    /// * the used [`Credentials`] are not that of a system-wide user in the
626    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
627    ///
628    /// # Examples
629    ///
630    /// ```no_run
631    /// use nethsm::{
632    ///     Connection,
633    ///     ConnectionSecurity,
634    ///     Credentials,
635    ///     DistinguishedName,
636    ///     NetHsm,
637    ///     Passphrase,
638    ///     UserRole,
639    /// };
640    ///
641    /// # fn main() -> testresult::TestResult {
642    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
643    /// let nethsm = NetHsm::new(
644    ///     Connection::new(
645    ///         "https://example.org/api/v1".try_into()?,
646    ///         ConnectionSecurity::Unsafe,
647    ///     ),
648    ///     Some(Credentials::new(
649    ///         "admin".parse()?,
650    ///         Some(Passphrase::new("passphrase".to_string())),
651    ///     )),
652    ///     None,
653    ///     None,
654    /// )?;
655    /// // add a user in the Administrator role for a namespace (N-Administrator)
656    /// nethsm.add_user(
657    ///     "Namespace1 Admin".to_string(),
658    ///     UserRole::Administrator,
659    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
660    ///     Some("namespace1~admin1".parse()?),
661    /// )?;
662    /// // create accompanying namespace
663    /// nethsm.add_namespace(&"namespace1".parse()?)?;
664    ///
665    /// // R-Administrators can get a CSR for the TLS certificate
666    /// println!(
667    ///     "{}",
668    ///     nethsm.get_tls_csr(DistinguishedName {
669    ///         country_name: Some("DE".to_string()),
670    ///         state_or_province_name: Some("Berlin".to_string()),
671    ///         locality_name: Some("Berlin".to_string()),
672    ///         organization_name: Some("Foobar Inc".to_string()),
673    ///         organizational_unit_name: Some("Department of Foo".to_string()),
674    ///         common_name: "Foobar Inc".to_string(),
675    ///         email_address: Some("foobar@mcfooface.com".to_string()),
676    ///     })?
677    /// );
678    ///
679    /// // N-Administrators can not get a CSR for the TLS certificate
680    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
681    /// assert!(
682    ///     nethsm
683    ///         .get_tls_csr(DistinguishedName {
684    ///             country_name: Some("DE".to_string()),
685    ///             state_or_province_name: Some("Berlin".to_string()),
686    ///             locality_name: Some("Berlin".to_string()),
687    ///             organization_name: Some("Foobar Inc".to_string()),
688    ///             organizational_unit_name: Some("Department of Foo".to_string()),
689    ///             common_name: "Foobar Inc".to_string(),
690    ///             email_address: Some("foobar@mcfooface.com".to_string()),
691    ///         })
692    ///         .is_err()
693    /// );
694    /// # Ok(())
695    /// # }
696    /// ```
697    /// [CSR]: https://en.wikipedia.org/wiki/Certificate_signing_request
698    /// [PKCS#10]: https://en.wikipedia.org/wiki/Certificate_signing_request#Structure_of_a_PKCS_#10_CSR
699    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
700    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
701    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
702    pub fn get_tls_csr(&self, distinguished_name: DistinguishedName) -> Result<String, Error> {
703        debug!(
704            "Retrieve a Certificate Signing Request (for {}) for the TLS certificate of the NetHSM at {} using {}",
705            distinguished_name.common_name,
706            self.url.borrow(),
707            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
708        );
709
710        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
711        Ok(
712            config_tls_csr_pem_post(&self.create_connection_config(), distinguished_name)
713                .map_err(|error| {
714                    Error::Api(format!(
715                        "Retrieving CSR for TLS certificate failed: {}",
716                        NetHsmApiError::from(error),
717                    ))
718                })?
719                .entity,
720        )
721    }
722
723    /// Generates a new [TLS certificate] for the API.
724    ///
725    /// Generates a new [TLS certificate] (used for communication with the API) based on
726    /// `tls_key_type` and `length`.
727    ///
728    /// This call requires using [`Credentials`] of a system-wide user in the
729    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
730    ///
731    /// # Errors
732    ///
733    /// Returns an [`Error::Api`] if the new [TLS certificate] can not be generated:
734    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
735    /// * the `tls_key_type` and `length` combination is not valid
736    /// * the used [`Credentials`] are not correct
737    /// * the used [`Credentials`] are not that of a system-wide user in the
738    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
739    ///
740    /// # Examples
741    ///
742    /// ```no_run
743    /// use nethsm::{
744    ///     Connection,
745    ///     ConnectionSecurity,
746    ///     Credentials,
747    ///     NetHsm,
748    ///     Passphrase,
749    ///     TlsKeyType,
750    ///     UserRole,
751    /// };
752    ///
753    /// # fn main() -> testresult::TestResult {
754    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
755    /// let nethsm = NetHsm::new(
756    ///     Connection::new(
757    ///         "https://example.org/api/v1".try_into()?,
758    ///         ConnectionSecurity::Unsafe,
759    ///     ),
760    ///     Some(Credentials::new(
761    ///         "admin".parse()?,
762    ///         Some(Passphrase::new("passphrase".to_string())),
763    ///     )),
764    ///     None,
765    ///     None,
766    /// )?;
767    /// // add a user in the Administrator role for a namespace (N-Administrator)
768    /// nethsm.add_user(
769    ///     "Namespace1 Admin".to_string(),
770    ///     UserRole::Administrator,
771    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
772    ///     Some("namespace1~admin1".parse()?),
773    /// )?;
774    /// // create accompanying namespace
775    /// nethsm.add_namespace(&"namespace1".parse()?)?;
776    ///
777    /// // R-Administrators can generate a new TLS certificate
778    /// nethsm.generate_tls_cert(TlsKeyType::Rsa, Some(4096))?;
779    ///
780    /// // N-Administrators can not generate a new TLS certificate
781    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
782    /// assert!(
783    ///     nethsm
784    ///         .generate_tls_cert(TlsKeyType::Rsa, Some(4096))
785    ///         .is_err()
786    /// );
787    /// # Ok(())
788    /// # }
789    /// ```
790    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
791    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
792    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
793    pub fn generate_tls_cert(
794        &self,
795        tls_key_type: TlsKeyType,
796        length: Option<u32>,
797    ) -> Result<(), Error> {
798        debug!(
799            "Generate a TLS certificate ({tls_key_type}{}) on the NetHSM at {} using {}",
800            if let Some(length) = length {
801                format!(" {length} bit long")
802            } else {
803                "{}".to_string()
804            },
805            self.url.borrow(),
806            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
807        );
808
809        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
810        // ensure the tls_key_type - length combination is valid
811        tls_key_type_matches_length(tls_key_type, length)?;
812        config_tls_generate_post(
813            &self.create_connection_config(),
814            TlsKeyGenerateRequestData {
815                r#type: tls_key_type.into(),
816                length: length.map(|length| length as i32),
817            },
818        )
819        .map_err(|error| {
820            Error::Api(format!(
821                "Generating API TLS certificate failed: {}",
822                NetHsmApiError::from(error)
823            ))
824        })?;
825        Ok(())
826    }
827
828    /// Sets a new [TLS certificate] for the API.
829    ///
830    /// Accepts a Base64 encoded [DER] certificate provided using `certificate` which is added as
831    /// new [TLS certificate] for communication with the API.
832    ///
833    /// This call requires using [`Credentials`] of a system-wide user in the
834    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
835    ///
836    /// # Errors
837    ///
838    /// Returns an [`Error::Api`] if setting a new TLS certificate fails:
839    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
840    /// * the provided `certificate` is not valid
841    /// * the used [`Credentials`] are not correct
842    /// * the used [`Credentials`] are not that of a system-wide user in the
843    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
844    ///
845    /// # Examples
846    ///
847    /// ```no_run
848    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
849    ///
850    /// # fn main() -> testresult::TestResult {
851    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
852    /// let nethsm = NetHsm::new(
853    ///     Connection::new(
854    ///         "https://example.org/api/v1".try_into()?,
855    ///         ConnectionSecurity::Unsafe,
856    ///     ),
857    ///     Some(Credentials::new(
858    ///         "admin".parse()?,
859    ///         Some(Passphrase::new("passphrase".to_string())),
860    ///     )),
861    ///     None,
862    ///     None,
863    /// )?;
864    /// // add a user in the Administrator role for a namespace (N-Administrator)
865    /// nethsm.add_user(
866    ///     "Namespace1 Admin".to_string(),
867    ///     UserRole::Administrator,
868    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
869    ///     Some("namespace1~admin1".parse()?),
870    /// )?;
871    /// // create accompanying namespace
872    /// nethsm.add_namespace(&"namespace1".parse()?)?;
873    ///
874    /// let cert = r#"-----BEGIN CERTIFICATE-----
875    /// MIIBHjCBxKADAgECAghDngCv6xWIXDAKBggqhkjOPQQDAjAUMRIwEAYDVQQDDAlr
876    /// ZXlmZW5kZXIwIBcNNzAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQxEjAQ
877    /// BgNVBAMMCWtleWZlbmRlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJsHIrsZ
878    /// 6fJzrk12GK7nW6bGyTIIZiQUq0uaKbn21dgPiDCO5+iYVXAqnWu4IMVZQnkFJmte
879    /// PRUUuM3119f8ffkwCgYIKoZIzj0EAwIDSQAwRgIhALH4fDYJ21tRecXp9IipBlil
880    /// p+hJCj77zBvFmGYy/UnPAiEA8csj7U6BfzvK4EiQyUZa7/as+nXwj3XHU/i8LyLm
881    /// Chw=
882    /// -----END CERTIFICATE-----"#;
883    ///
884    /// // R-Administrators can set a new TLS certificate
885    /// nethsm.set_tls_cert(cert)?;
886    ///
887    /// // N-Administrators can not set a new TLS certificate
888    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
889    /// assert!(nethsm.set_tls_cert(cert).is_err());
890    /// # Ok(())
891    /// # }
892    /// ```
893    /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
894    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
895    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
896    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
897    pub fn set_tls_cert(&self, certificate: &str) -> Result<(), Error> {
898        debug!(
899            "Set a new TLS certificate for the NetHSM at {} using {}",
900            self.url.borrow(),
901            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
902        );
903
904        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
905        config_tls_cert_pem_put(&self.create_connection_config(), certificate).map_err(
906            |error| {
907                Error::Api(format!(
908                    "Setting API TLS certificate failed: {}",
909                    NetHsmApiError::from(error)
910                ))
911            },
912        )?;
913        Ok(())
914    }
915
916    /// Gets the [network configuration].
917    ///
918    /// Retrieves the [network configuration] of the NetHSM as [`NetworkConfig`].
919    ///
920    /// This call requires using [`Credentials`] of a system-wide user in the
921    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
922    ///
923    /// # Errors
924    ///
925    /// Returns an [`Error::Api`] if retrieving network configuration fails:
926    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
927    /// * the used [`Credentials`] are not correct
928    /// * the used [`Credentials`] are not that of a system-wide user in the
929    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
930    ///
931    /// # Examples
932    ///
933    /// ```no_run
934    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
935    ///
936    /// # fn main() -> testresult::TestResult {
937    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
938    /// let nethsm = NetHsm::new(
939    ///     Connection::new(
940    ///         "https://example.org/api/v1".try_into()?,
941    ///         ConnectionSecurity::Unsafe,
942    ///     ),
943    ///     Some(Credentials::new(
944    ///         "admin".parse()?,
945    ///         Some(Passphrase::new("passphrase".to_string())),
946    ///     )),
947    ///     None,
948    ///     None,
949    /// )?;
950    /// // add a user in the Administrator role for a namespace (N-Administrator)
951    /// nethsm.add_user(
952    ///     "Namespace1 Admin".to_string(),
953    ///     UserRole::Administrator,
954    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
955    ///     Some("namespace1~admin1".parse()?),
956    /// )?;
957    /// // create accompanying namespace
958    /// nethsm.add_namespace(&"namespace1".parse()?)?;
959    ///
960    /// // R-Administrators can get the network configuration
961    /// println!("{:?}", nethsm.get_network()?);
962    ///
963    /// // N-Administrators can not get the network configuration
964    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
965    /// assert!(nethsm.get_network().is_err());
966    /// # Ok(())
967    /// # }
968    /// ```
969    /// [network configuration]: https://docs.nitrokey.com/nethsm/administration#network
970    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
971    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
972    pub fn get_network(&self) -> Result<NetworkConfig, Error> {
973        debug!(
974            "Get network configuration for the NetHSM at {} using {}",
975            self.url.borrow(),
976            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
977        );
978
979        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
980        Ok(config_network_get(&self.create_connection_config())
981            .map_err(|error| {
982                Error::Api(format!(
983                    "Getting network config failed: {}",
984                    NetHsmApiError::from(error)
985                ))
986            })?
987            .entity)
988    }
989
990    /// Sets the [network configuration].
991    ///
992    /// Sets the [network configuration] of the NetHSM on the basis of a [`NetworkConfig`].
993    ///
994    /// This call requires using [`Credentials`] of a system-wide user in the
995    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
996    ///
997    /// # Errors
998    ///
999    /// Returns an [`Error::Api`] if setting the network configuration fails:
1000    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1001    /// * the provided `network_config` is not valid
1002    /// * the used [`Credentials`] are not correct
1003    /// * the used [`Credentials`] are not that of a system-wide user in the
1004    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1005    ///
1006    /// # Examples
1007    ///
1008    /// ```no_run
1009    /// use nethsm::{
1010    ///     Connection,
1011    ///     ConnectionSecurity,
1012    ///     Credentials,
1013    ///     NetHsm,
1014    ///     NetworkConfig,
1015    ///     Passphrase,
1016    ///     UserRole,
1017    /// };
1018    ///
1019    /// # fn main() -> testresult::TestResult {
1020    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1021    /// let nethsm = NetHsm::new(
1022    ///     Connection::new(
1023    ///         "https://example.org/api/v1".try_into()?,
1024    ///         ConnectionSecurity::Unsafe,
1025    ///     ),
1026    ///     Some(Credentials::new(
1027    ///         "admin".parse()?,
1028    ///         Some(Passphrase::new("passphrase".to_string())),
1029    ///     )),
1030    ///     None,
1031    ///     None,
1032    /// )?;
1033    /// // add a user in the Administrator role for a namespace (N-Administrator)
1034    /// nethsm.add_user(
1035    ///     "Namespace1 Admin".to_string(),
1036    ///     UserRole::Administrator,
1037    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1038    ///     Some("namespace1~admin1".parse()?),
1039    /// )?;
1040    /// // create accompanying namespace
1041    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1042    ///
1043    /// let network_config = NetworkConfig::new(
1044    ///     "192.168.1.1".to_string(),
1045    ///     "255.255.255.0".to_string(),
1046    ///     "0.0.0.0".to_string(),
1047    /// );
1048    ///
1049    /// // R-Administrators can set the network configuration
1050    /// nethsm.set_network(network_config.clone())?;
1051    ///
1052    /// // N-Administrators can not set the network configuration
1053    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1054    /// assert!(nethsm.set_network(network_config).is_err());
1055    /// # Ok(())
1056    /// # }
1057    /// ```
1058    /// [network configuration]: https://docs.nitrokey.com/nethsm/administration#network
1059    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1060    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1061    pub fn set_network(&self, network_config: NetworkConfig) -> Result<(), Error> {
1062        debug!(
1063            "Set a new network configuration (IP: {}, Netmask: {}, Gateway: {}) for the NetHSM at {} using {}",
1064            network_config.ip_address,
1065            network_config.netmask,
1066            network_config.gateway,
1067            self.url.borrow(),
1068            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1069        );
1070
1071        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1072        config_network_put(&self.create_connection_config(), network_config).map_err(|error| {
1073            Error::Api(format!(
1074                "Setting network config failed: {}",
1075                NetHsmApiError::from(error)
1076            ))
1077        })?;
1078        Ok(())
1079    }
1080
1081    /// Gets the current [time].
1082    ///
1083    /// This call requires using [`Credentials`] of a system-wide user in the
1084    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1085    ///
1086    /// # Errors
1087    ///
1088    /// Returns an [`Error::Api`] if retrieving [time] fails:
1089    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1090    /// * the used [`Credentials`] are not correct
1091    /// * the used [`Credentials`] are not that of a system-wide user in the
1092    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1093    ///
1094    /// # Examples
1095    ///
1096    /// ```no_run
1097    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1098    ///
1099    /// # fn main() -> testresult::TestResult {
1100    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1101    /// let nethsm = NetHsm::new(
1102    ///     Connection::new(
1103    ///         "https://example.org/api/v1".try_into()?,
1104    ///         ConnectionSecurity::Unsafe,
1105    ///     ),
1106    ///     Some(Credentials::new(
1107    ///         "admin".parse()?,
1108    ///         Some(Passphrase::new("passphrase".to_string())),
1109    ///     )),
1110    ///     None,
1111    ///     None,
1112    /// )?;
1113    /// // add a user in the Administrator role for a namespace (N-Administrator)
1114    /// nethsm.add_user(
1115    ///     "Namespace1 Admin".to_string(),
1116    ///     UserRole::Administrator,
1117    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1118    ///     Some("namespace1~admin1".parse()?),
1119    /// )?;
1120    /// // create accompanying namespace
1121    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1122    ///
1123    /// // R-Administrators can get the time
1124    /// println!("{:?}", nethsm.get_time()?);
1125    ///
1126    /// // N-Administrators can not get the time
1127    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1128    /// assert!(nethsm.get_time().is_err());
1129    /// # Ok(())
1130    /// # }
1131    /// ```
1132    /// [time]: https://docs.nitrokey.com/nethsm/administration#time
1133    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1134    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1135    pub fn get_time(&self) -> Result<String, Error> {
1136        debug!(
1137            "Retrieve the system time for the NetHSM at {} using {}",
1138            self.url.borrow(),
1139            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1140        );
1141
1142        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1143        Ok(config_time_get(&self.create_connection_config())
1144            .map_err(|error| {
1145                Error::Api(format!(
1146                    "Getting NetHSM system time failed: {}",
1147                    NetHsmApiError::from(error)
1148                ))
1149            })?
1150            .entity
1151            .time)
1152    }
1153
1154    /// Sets the current [time].
1155    ///
1156    /// This call requires using [`Credentials`] of a system-wide user in the
1157    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1158    ///
1159    /// # Errors
1160    ///
1161    /// Returns an [`Error::Api`] if setting [time] fails:
1162    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1163    /// * the provided `time` is not valid
1164    /// * the used [`Credentials`] are not correct
1165    /// * the used [`Credentials`] are not that of a system-wide user in the
1166    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1167    ///
1168    /// # Examples
1169    ///
1170    /// ```no_run
1171    /// use chrono::Utc;
1172    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1173    ///
1174    /// # fn main() -> testresult::TestResult {
1175    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1176    /// let nethsm = NetHsm::new(
1177    ///     Connection::new(
1178    ///         "https://example.org/api/v1".try_into()?,
1179    ///         ConnectionSecurity::Unsafe,
1180    ///     ),
1181    ///     Some(Credentials::new(
1182    ///         "admin".parse()?,
1183    ///         Some(Passphrase::new("passphrase".to_string())),
1184    ///     )),
1185    ///     None,
1186    ///     None,
1187    /// )?;
1188    /// // add a user in the Administrator role for a namespace (N-Administrator)
1189    /// nethsm.add_user(
1190    ///     "Namespace1 Admin".to_string(),
1191    ///     UserRole::Administrator,
1192    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1193    ///     Some("namespace1~admin1".parse()?),
1194    /// )?;
1195    /// // create accompanying namespace
1196    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1197    ///
1198    /// // R-Administrators can set the time
1199    /// nethsm.set_time(Utc::now())?;
1200    ///
1201    /// // N-Administrators can not set the time
1202    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1203    /// assert!(nethsm.set_time(Utc::now()).is_err());
1204    /// # Ok(())
1205    /// # }
1206    /// ```
1207    /// [time]: https://docs.nitrokey.com/nethsm/administration#time
1208    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1209    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1210    pub fn set_time(&self, time: DateTime<Utc>) -> Result<(), Error> {
1211        debug!(
1212            "Set the system time to {time} for the NetHSM at {} using {}",
1213            self.url.borrow(),
1214            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1215        );
1216
1217        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1218        config_time_put(
1219            &self.create_connection_config(),
1220            TimeConfig::new(time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)),
1221        )
1222        .map_err(|error| {
1223            Error::Api(format!(
1224                "Setting NetHSM system time failed: {}",
1225                NetHsmApiError::from(error)
1226            ))
1227        })?;
1228        Ok(())
1229    }
1230
1231    /// Gets the [logging configuration].
1232    ///
1233    /// This call requires using [`Credentials`] of a system-wide user in the
1234    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1235    ///
1236    /// # Errors
1237    ///
1238    /// Returns an [`Error::Api`] if getting the [logging configuration] fails:
1239    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1240    /// * the used [`Credentials`] are not correct
1241    /// * the used [`Credentials`] are not that of a system-wide user in the
1242    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1243    ///
1244    /// # Examples
1245    ///
1246    /// ```no_run
1247    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1248    ///
1249    /// # fn main() -> testresult::TestResult {
1250    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1251    /// let nethsm = NetHsm::new(
1252    ///     Connection::new(
1253    ///         "https://example.org/api/v1".try_into()?,
1254    ///         ConnectionSecurity::Unsafe,
1255    ///     ),
1256    ///     Some(Credentials::new(
1257    ///         "admin".parse()?,
1258    ///         Some(Passphrase::new("passphrase".to_string())),
1259    ///     )),
1260    ///     None,
1261    ///     None,
1262    /// )?;
1263    /// // add a user in the Administrator role for a namespace (N-Administrator)
1264    /// nethsm.add_user(
1265    ///     "Namespace1 Admin".to_string(),
1266    ///     UserRole::Administrator,
1267    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1268    ///     Some("namespace1~admin1".parse()?),
1269    /// )?;
1270    /// // create accompanying namespace
1271    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1272    ///
1273    /// // R-Administrators can get logging configuration
1274    /// println!("{:?}", nethsm.get_logging()?);
1275    ///
1276    /// // N-Administrators can not get logging configuration
1277    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1278    /// assert!(nethsm.get_logging().is_err());
1279    /// # Ok(())
1280    /// # }
1281    /// ```
1282    /// [logging configuration]: https://docs.nitrokey.com/nethsm/administration#logging
1283    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1284    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1285    pub fn get_logging(&self) -> Result<LoggingConfig, Error> {
1286        debug!(
1287            "Retrieve the logging information of the NetHSM at {} using {}",
1288            self.url.borrow(),
1289            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1290        );
1291
1292        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1293        Ok(config_logging_get(&self.create_connection_config())
1294            .map_err(|error| {
1295                Error::Api(format!(
1296                    "Getting logging config failed: {}",
1297                    NetHsmApiError::from(error)
1298                ))
1299            })?
1300            .entity)
1301    }
1302
1303    /// Sets the [logging configuration].
1304    ///
1305    /// Sets the NetHSM's [logging configuration] by providing `ip_address` and `port` of a host to
1306    /// send logs to. The log level is configured using `log_level`.
1307    ///
1308    /// This call requires using [`Credentials`] of a system-wide user in the
1309    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1310    ///
1311    /// # Errors
1312    ///
1313    /// Returns an [`Error::Api`] if setting the logging configuration fails:
1314    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1315    /// * the provided `ip_address`, `port` or `log_level` are not valid
1316    /// * the used [`Credentials`] are not correct
1317    /// * the used [`Credentials`] are not that of a system-wide user in the
1318    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1319    ///
1320    /// # Examples
1321    ///
1322    /// ```no_run
1323    /// use std::net::Ipv4Addr;
1324    ///
1325    /// use nethsm::{
1326    ///     Connection,
1327    ///     ConnectionSecurity,
1328    ///     Credentials,
1329    ///     LogLevel,
1330    ///     NetHsm,
1331    ///     Passphrase,
1332    ///     UserRole,
1333    /// };
1334    ///
1335    /// # fn main() -> testresult::TestResult {
1336    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1337    /// let nethsm = NetHsm::new(
1338    ///     Connection::new(
1339    ///         "https://example.org/api/v1".try_into()?,
1340    ///         ConnectionSecurity::Unsafe,
1341    ///     ),
1342    ///     Some(Credentials::new(
1343    ///         "admin".parse()?,
1344    ///         Some(Passphrase::new("passphrase".to_string())),
1345    ///     )),
1346    ///     None,
1347    ///     None,
1348    /// )?;
1349    /// // add a user in the Administrator role for a namespace (N-Administrator)
1350    /// nethsm.add_user(
1351    ///     "Namespace1 Admin".to_string(),
1352    ///     UserRole::Administrator,
1353    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1354    ///     Some("namespace1~admin1".parse()?),
1355    /// )?;
1356    /// // create accompanying namespace
1357    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1358    ///
1359    /// // R-Administrators can set logging configuration
1360    /// nethsm.set_logging(Ipv4Addr::new(192, 168, 1, 2), 513, LogLevel::Debug)?;
1361    ///
1362    /// // N-Administrators can not set logging configuration
1363    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1364    /// assert!(
1365    ///     nethsm
1366    ///         .set_logging(Ipv4Addr::new(192, 168, 1, 2), 513, LogLevel::Debug)
1367    ///         .is_err()
1368    /// );
1369    /// # Ok(())
1370    /// # }
1371    /// ```
1372    /// [logging configuration]: https://docs.nitrokey.com/nethsm/administration#logging
1373    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1374    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1375    pub fn set_logging(
1376        &self,
1377        ip_address: Ipv4Addr,
1378        port: u32,
1379        log_level: LogLevel,
1380    ) -> Result<(), Error> {
1381        debug!(
1382            "Set the logging configuration to {ip_address}:{port} ({log_level}) for the NetHSM at {} using {}",
1383            self.url.borrow(),
1384            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1385        );
1386
1387        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1388        let ip_address = ip_address.to_string();
1389        config_logging_put(
1390            &self.create_connection_config(),
1391            LoggingConfig::new(ip_address, port as i32, log_level.into()),
1392        )
1393        .map_err(|error| {
1394            Error::Api(format!(
1395                "Setting logging config failed: {}",
1396                NetHsmApiError::from(error)
1397            ))
1398        })?;
1399        Ok(())
1400    }
1401
1402    /// Sets the [backup] passphrase.
1403    ///
1404    /// Sets `current_passphrase` to `new_passphrase`, which changes the [backup] passphrase for the
1405    /// NetHSM.
1406    ///
1407    /// This call requires using [`Credentials`] of a system-wide user in the
1408    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1409    ///
1410    /// # Errors
1411    ///
1412    /// Returns an [`Error::Api`] if setting the backup passphrase fails:
1413    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1414    /// * the provided `current_passphrase` is not correct
1415    /// * the used [`Credentials`] are not correct
1416    /// * the used [`Credentials`] are not that of a system-wide user in the
1417    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1418    ///
1419    /// # Examples
1420    ///
1421    /// ```no_run
1422    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1423    ///
1424    /// # fn main() -> testresult::TestResult {
1425    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1426    /// let nethsm = NetHsm::new(
1427    ///     Connection::new(
1428    ///         "https://example.org/api/v1".try_into()?,
1429    ///         ConnectionSecurity::Unsafe,
1430    ///     ),
1431    ///     Some(Credentials::new(
1432    ///         "admin".parse()?,
1433    ///         Some(Passphrase::new("passphrase".to_string())),
1434    ///     )),
1435    ///     None,
1436    ///     None,
1437    /// )?;
1438    /// // add a user in the Administrator role for a namespace (N-Administrator)
1439    /// nethsm.add_user(
1440    ///     "Namespace1 Admin".to_string(),
1441    ///     UserRole::Administrator,
1442    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1443    ///     Some("namespace1~admin1".parse()?),
1444    /// )?;
1445    /// // create accompanying namespace
1446    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1447    ///
1448    /// // R-Administrators can set the backup passphrase
1449    /// nethsm.set_backup_passphrase(
1450    ///     Passphrase::new("current-backup-passphrase".to_string()),
1451    ///     Passphrase::new("new-backup-passphrase".to_string()),
1452    /// )?;
1453    ///
1454    /// // N-Administrators can not set logging configuration
1455    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1456    /// assert!(
1457    ///     nethsm
1458    ///         .set_backup_passphrase(
1459    ///             Passphrase::new("new-backup-passphrase".to_string()),
1460    ///             Passphrase::new("current-backup-passphrase".to_string()),
1461    ///         )
1462    ///         .is_err()
1463    /// );
1464    /// # Ok(())
1465    /// # }
1466    /// ```
1467    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
1468    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1469    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1470    pub fn set_backup_passphrase(
1471        &self,
1472        current_passphrase: Passphrase,
1473        new_passphrase: Passphrase,
1474    ) -> Result<(), Error> {
1475        debug!(
1476            "Set the backup passphrase for the NetHSM at {} using {}",
1477            self.url.borrow(),
1478            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1479        );
1480
1481        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1482        config_backup_passphrase_put(
1483            &self.create_connection_config(),
1484            BackupPassphraseConfig::new(
1485                new_passphrase.expose_owned(),
1486                current_passphrase.expose_owned(),
1487            ),
1488        )
1489        .map_err(|error| {
1490            Error::Api(format!(
1491                "Setting backup passphrase failed: {}",
1492                NetHsmApiError::from(error),
1493            ))
1494        })?;
1495        Ok(())
1496    }
1497
1498    /// Creates a [backup].
1499    ///
1500    /// Triggers the creation and download of a [backup] of the NetHSM.
1501    /// **NOTE**: Before creating the first [backup], the [backup] passphrase must be set using
1502    /// [`set_backup_passphrase`][`NetHsm::set_backup_passphrase`].
1503    ///
1504    /// This call requires using [`Credentials`] of a user in the [`Backup`][`UserRole::Backup`]
1505    /// [role].
1506    ///
1507    /// # Errors
1508    ///
1509    /// Returns an [`Error::Api`] if creating a [backup] fails:
1510    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1511    /// * the used [`Credentials`] are not correct
1512    /// * the used [`Credentials`] are not that of a user in the [`Backup`][`UserRole::Backup`]
1513    ///   [role]
1514    /// * the [backup] passphrase has not yet been set
1515    ///
1516    /// # Examples
1517    ///
1518    /// ```no_run
1519    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
1520    ///
1521    /// # fn main() -> testresult::TestResult {
1522    /// // create a connection with a user in the Backup role
1523    /// let nethsm = NetHsm::new(
1524    ///     Connection::new(
1525    ///         "https://example.org/api/v1".try_into()?,
1526    ///         ConnectionSecurity::Unsafe,
1527    ///     ),
1528    ///     Some(Credentials::new(
1529    ///         "backup1".parse()?,
1530    ///         Some(Passphrase::new("passphrase".to_string())),
1531    ///     )),
1532    ///     None,
1533    ///     None,
1534    /// )?;
1535    ///
1536    /// // create a backup and write it to file
1537    /// std::fs::write("nethsm.bkp", nethsm.backup()?)?;
1538    /// # Ok(())
1539    /// # }
1540    /// ```
1541    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
1542    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1543    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1544    pub fn backup(&self) -> Result<Vec<u8>, Error> {
1545        debug!(
1546            "Retrieve a backup of the NetHSM at {} using {}",
1547            self.url.borrow(),
1548            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1549        );
1550
1551        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1552        Ok(system_backup_post(&self.create_connection_config())
1553            .map_err(|error| {
1554                Error::Api(format!(
1555                    "Getting backup failed: {}",
1556                    NetHsmApiError::from(error)
1557                ))
1558            })?
1559            .entity)
1560    }
1561
1562    /// Triggers a [factory reset].
1563    ///
1564    /// Triggers a [factory reset] of the NetHSM.
1565    /// **WARNING**: This action deletes all user and system data! Make sure to create a [backup]
1566    /// using [`backup`][`NetHsm::backup`] first!
1567    ///
1568    /// This call requires using [`Credentials`] of a system-wide user in the
1569    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1570    ///
1571    /// # Errors
1572    ///
1573    /// Returns an [`Error::Api`] if resetting the NetHSM fails:
1574    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1575    /// * the used [`Credentials`] are not correct
1576    /// * the used [`Credentials`] are not that of a system-wide user in the
1577    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1578    ///
1579    /// # Examples
1580    ///
1581    /// ```no_run
1582    /// use nethsm::{
1583    ///     Connection,
1584    ///     ConnectionSecurity,
1585    ///     Credentials,
1586    ///     NetHsm,
1587    ///     Passphrase,
1588    ///     SystemState,
1589    ///     UserRole,
1590    /// };
1591    ///
1592    /// # fn main() -> testresult::TestResult {
1593    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1594    /// let nethsm = NetHsm::new(
1595    ///     Connection::new(
1596    ///         "https://example.org/api/v1".try_into()?,
1597    ///         ConnectionSecurity::Unsafe,
1598    ///     ),
1599    ///     Some(Credentials::new(
1600    ///         "admin".parse()?,
1601    ///         Some(Passphrase::new("passphrase".to_string())),
1602    ///     )),
1603    ///     None,
1604    ///     None,
1605    /// )?;
1606    /// // add a user in the Administrator role for a namespace (N-Administrator)
1607    /// nethsm.add_user(
1608    ///     "Namespace1 Admin".to_string(),
1609    ///     UserRole::Administrator,
1610    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1611    ///     Some("namespace1~admin1".parse()?),
1612    /// )?;
1613    /// // create accompanying namespace
1614    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1615    ///
1616    /// // N-Administrators can not trigger factory reset
1617    /// assert_eq!(nethsm.state()?, SystemState::Operational);
1618    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1619    /// assert!(nethsm.factory_reset().is_err());
1620    ///
1621    /// // R-Administrators are able to trigger a factory reset
1622    /// assert_eq!(nethsm.state()?, SystemState::Operational);
1623    /// nethsm.use_credentials(&"admin".parse()?)?;
1624    /// nethsm.factory_reset()?;
1625    /// assert_eq!(nethsm.state()?, SystemState::Unprovisioned);
1626    /// # Ok(())
1627    /// # }
1628    /// ```
1629    /// [factory reset]: https://docs.nitrokey.com/nethsm/administration#reset-to-factory-defaults
1630    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
1631    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1632    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1633    pub fn factory_reset(&self) -> Result<(), Error> {
1634        debug!(
1635            "Trigger a factory reset of the NetHSM at {} using {}",
1636            self.url.borrow(),
1637            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1638        );
1639
1640        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1641        system_factory_reset_post(&self.create_connection_config()).map_err(|error| {
1642            Error::Api(format!(
1643                "Factory reset failed: {}",
1644                NetHsmApiError::from(error)
1645            ))
1646        })?;
1647        Ok(())
1648    }
1649
1650    /// Restores NetHSM from [backup].
1651    ///
1652    /// [Restores] a NetHSM from a [backup], by providing a `backup_passphrase` (see
1653    /// [`set_backup_passphrase`][`NetHsm::set_backup_passphrase`]) a new `system_time` for the
1654    /// NetHSM and a backup file (created using [`backup`][`NetHsm::backup`]).
1655    ///
1656    /// The NetHSM must be in [`Operational`][`SystemState::Operational`] or
1657    /// [`Unprovisioned`][`SystemState::Unprovisioned`] [state].
1658    ///
1659    /// Any existing user data is safely removed and replaced by that of the [backup], after which
1660    /// the NetHSM ends up in [`Locked`][`SystemState::Locked`] [state].
1661    /// If the NetHSM is in [`Unprovisioned`][`SystemState::Unprovisioned`] [state], additionally
1662    /// the system configuration from the backup is applied and leads to a
1663    /// [`reboot`][`NetHsm::reboot`] of the NetHSM.
1664    ///
1665    /// This call requires using [`Credentials`] of a system-wide user in the
1666    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1667    ///
1668    /// # Errors
1669    ///
1670    /// Returns an [`Error::Api`] if restoring the NetHSM from [backup] fails:
1671    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] or
1672    ///   [`Unprovisioned`][`SystemState::Unprovisioned`] [state]
1673    /// * the used [`Credentials`] are not correct
1674    /// * the used [`Credentials`] are not that of a system-wide user in the
1675    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1676    ///
1677    /// # Examples
1678    ///
1679    /// ```no_run
1680    /// use chrono::Utc;
1681    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1682    ///
1683    /// #
1684    /// # fn main() -> testresult::TestResult {
1685    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1686    /// let nethsm = NetHsm::new(
1687    ///     Connection::new(
1688    ///         "https://example.org/api/v1".try_into()?,
1689    ///         ConnectionSecurity::Unsafe,
1690    ///     ),
1691    ///     Some(Credentials::new(
1692    ///         "admin".parse()?,
1693    ///         Some(Passphrase::new("passphrase".to_string())),
1694    ///     )),
1695    ///     None,
1696    ///     None,
1697    /// )?;
1698    /// // add a user in the Administrator role for a namespace (N-Administrator)
1699    /// nethsm.add_user(
1700    ///     "Namespace1 Admin".to_string(),
1701    ///     UserRole::Administrator,
1702    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1703    ///     Some("namespace1~admin1".parse()?),
1704    /// )?;
1705    /// // create accompanying namespace
1706    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1707    ///
1708    /// // N-Administrators can not restore from backup
1709    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1710    /// assert!(
1711    ///     nethsm
1712    ///         .restore(
1713    ///             Passphrase::new("backup-passphrase".to_string()),
1714    ///             Utc::now(),
1715    ///             std::fs::read("nethsm.bkp")?,
1716    ///         )
1717    ///         .is_err()
1718    /// );
1719    ///
1720    /// // R-Administrators can restore from backup
1721    /// nethsm.use_credentials(&"admin".parse()?)?;
1722    /// nethsm.restore(
1723    ///     Passphrase::new("backup-passphrase".to_string()),
1724    ///     Utc::now(),
1725    ///     std::fs::read("nethsm.bkp")?,
1726    /// )?;
1727    /// # Ok(())
1728    /// # }
1729    /// ```
1730    /// [Restores]: https://docs.nitrokey.com/nethsm/administration#restore
1731    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
1732    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1733    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1734    pub fn restore(
1735        &self,
1736        backup_passphrase: Passphrase,
1737        system_time: DateTime<Utc>,
1738        backup: Vec<u8>,
1739    ) -> Result<(), Error> {
1740        debug!(
1741            "Restore the NetHSM at {} from backup with the new system time {system_time} using {}",
1742            self.url.borrow(),
1743            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1744        );
1745
1746        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1747        system_restore_post(
1748            &self.create_connection_config(),
1749            Some(nethsm_sdk_rs::models::RestoreRequestArguments {
1750                backup_passphrase: Some(backup_passphrase.expose_owned()),
1751                system_time: Some(system_time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)),
1752            }),
1753            Some(backup),
1754        )
1755        .map_err(|error| {
1756            Error::Api(format!(
1757                "Restoring backup failed: {}",
1758                NetHsmApiError::from(error)
1759            ))
1760        })?;
1761        Ok(())
1762    }
1763
1764    /// Locks the NetHSM.
1765    ///
1766    /// Locks the NetHSM and sets its [state] to [`Locked`][`SystemState::Locked`].
1767    ///
1768    /// This call requires using [`Credentials`] of a system-wide user in the
1769    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1770    ///
1771    /// # Errors
1772    ///
1773    /// Returns an [`Error::Api`] if locking the NetHSM fails:
1774    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1775    /// * the used [`Credentials`] are not correct
1776    /// * the used [`Credentials`] are not that of a system-wide user in the
1777    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1778    ///
1779    /// # Examples
1780    ///
1781    /// ```no_run
1782    /// use nethsm::{
1783    ///     Connection,
1784    ///     ConnectionSecurity,
1785    ///     Credentials,
1786    ///     NetHsm,
1787    ///     Passphrase,
1788    ///     SystemState,
1789    ///     UserRole,
1790    /// };
1791    ///
1792    /// # fn main() -> testresult::TestResult {
1793    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1794    /// let nethsm = NetHsm::new(
1795    ///     Connection::new(
1796    ///         "https://example.org/api/v1".try_into()?,
1797    ///         ConnectionSecurity::Unsafe,
1798    ///     ),
1799    ///     Some(Credentials::new(
1800    ///         "admin".parse()?,
1801    ///         Some(Passphrase::new("passphrase".to_string())),
1802    ///     )),
1803    ///     None,
1804    ///     None,
1805    /// )?;
1806    /// // add a user in the Administrator role for a namespace (N-Administrator)
1807    /// nethsm.add_user(
1808    ///     "Namespace1 Admin".to_string(),
1809    ///     UserRole::Administrator,
1810    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1811    ///     Some("namespace1~admin1".parse()?),
1812    /// )?;
1813    /// // create accompanying namespace
1814    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1815    ///
1816    /// assert_eq!(nethsm.state()?, SystemState::Operational);
1817    ///
1818    /// // N-Administrators can not lock the NetHSM
1819    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1820    /// assert!(nethsm.lock().is_err());
1821    ///
1822    /// // R-Administrators can lock the NetHSM
1823    /// nethsm.use_credentials(&"admin".parse()?)?;
1824    /// nethsm.lock()?;
1825    /// assert_eq!(nethsm.state()?, SystemState::Locked);
1826    /// # Ok(())
1827    /// # }
1828    /// ```
1829    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1830    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1831    pub fn lock(&self) -> Result<(), Error> {
1832        debug!(
1833            "Lock the NetHSM at {} using {}",
1834            self.url.borrow(),
1835            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1836        );
1837
1838        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1839        lock_post(&self.create_connection_config()).map_err(|error| {
1840            Error::Api(format!(
1841                "Locking NetHSM failed: {}",
1842                NetHsmApiError::from(error)
1843            ))
1844        })?;
1845        Ok(())
1846    }
1847
1848    /// Unlocks the NetHSM.
1849    ///
1850    /// Unlocks the NetHSM if it is in [`Locked`][`SystemState::Locked`] [state] by providing
1851    /// `unlock_passphrase` and sets its [state] to [`Operational`][`SystemState::Operational`].
1852    ///
1853    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
1854    ///
1855    /// # Errors
1856    ///
1857    /// Returns an [`Error::Api`] if unlocking the NetHSM fails:
1858    /// * the NetHSM is not in [`Locked`][`SystemState::Locked`] [state]
1859    ///
1860    /// # Examples
1861    ///
1862    /// ```no_run
1863    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, SystemState};
1864    ///
1865    /// # fn main() -> testresult::TestResult {
1866    /// // no initial [`Credentials`] are required
1867    /// let nethsm = NetHsm::new(
1868    ///     Connection::new(
1869    ///         "https://example.org/api/v1".try_into()?,
1870    ///         ConnectionSecurity::Unsafe,
1871    ///     ),
1872    ///     None,
1873    ///     None,
1874    ///     None,
1875    /// )?;
1876    ///
1877    /// assert_eq!(nethsm.state()?, SystemState::Locked);
1878    /// // unlock the NetHSM
1879    /// nethsm.unlock(Passphrase::new("unlock-passphrase".to_string()))?;
1880    /// assert_eq!(nethsm.state()?, SystemState::Operational);
1881    /// # Ok(())
1882    /// # }
1883    /// ```
1884    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1885    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1886    pub fn unlock(&self, unlock_passphrase: Passphrase) -> Result<(), Error> {
1887        debug!(
1888            "Unlock the NetHSM at {} using {}",
1889            self.url.borrow(),
1890            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1891        );
1892
1893        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1894        unlock_post(
1895            &self.create_connection_config(),
1896            UnlockRequestData::new(unlock_passphrase.expose_owned()),
1897        )
1898        .map_err(|error| {
1899            Error::Api(format!(
1900                "Unlocking NetHSM failed: {}",
1901                NetHsmApiError::from(error)
1902            ))
1903        })?;
1904        Ok(())
1905    }
1906
1907    /// Retrieves [system information].
1908    ///
1909    /// Returns [system information] in the form of a [`SystemInfo`], which contains various pieces
1910    /// of information such as software version, software build, firmware version, hardware
1911    /// version, device ID and information on TPM related components such as attestation key and
1912    /// relevant PCR values.
1913    ///
1914    /// This call requires using [`Credentials`] of a system-wide user in the
1915    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1916    ///
1917    /// # Errors
1918    ///
1919    /// Returns an [`Error::Api`] if retrieving the system information fails:
1920    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1921    /// * the used [`Credentials`] are not correct
1922    /// * the used [`Credentials`] are not that of a system-wide user in the
1923    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1924    ///
1925    /// # Examples
1926    ///
1927    /// ```no_run
1928    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1929    ///
1930    /// # fn main() -> testresult::TestResult {
1931    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1932    /// let nethsm = NetHsm::new(
1933    ///     Connection::new(
1934    ///         "https://example.org/api/v1".try_into()?,
1935    ///         ConnectionSecurity::Unsafe,
1936    ///     ),
1937    ///     Some(Credentials::new(
1938    ///         "admin".parse()?,
1939    ///         Some(Passphrase::new("passphrase".to_string())),
1940    ///     )),
1941    ///     None,
1942    ///     None,
1943    /// )?;
1944    /// // add a user in the Administrator role for a namespace (N-Administrator)
1945    /// nethsm.add_user(
1946    ///     "Namespace1 Admin".to_string(),
1947    ///     UserRole::Administrator,
1948    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1949    ///     Some("namespace1~admin1".parse()?),
1950    /// )?;
1951    /// // create accompanying namespace
1952    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1953    ///
1954    /// // R-Administrators can retrieve system information
1955    /// println!("{:?}", nethsm.system_info()?);
1956    ///
1957    /// // N-Administrators can not retrieve system information
1958    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1959    /// assert!(nethsm.system_info().is_err());
1960    /// # Ok(())
1961    /// # }
1962    /// ```
1963    /// [system information]: https://docs.nitrokey.com/nethsm/administration#system-information
1964    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1965    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1966    pub fn system_info(&self) -> Result<SystemInfo, Error> {
1967        debug!(
1968            "Retrieve system information about the NetHSM at {} using {}",
1969            self.url.borrow(),
1970            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1971        );
1972
1973        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1974        Ok(system_info_get(&self.create_connection_config())
1975            .map_err(|error| {
1976                Error::Api(format!(
1977                    "Retrieving system information failed: {}",
1978                    NetHsmApiError::from(error)
1979                ))
1980            })?
1981            .entity)
1982    }
1983
1984    /// [Reboots] the NetHSM.
1985    ///
1986    /// [Reboots] the NetHSM, if it is in [`Operational`][`SystemState::Operational`] [state].
1987    ///
1988    /// This call requires using [`Credentials`] of a system-wide user in the
1989    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1990    ///
1991    /// # Errors
1992    ///
1993    /// Returns an [`Error::Api`] if rebooting the NetHSM fails:
1994    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1995    /// * the used [`Credentials`] are not correct
1996    /// * the used [`Credentials`] are not that of a system-wide user in the
1997    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1998    ///
1999    /// # Examples
2000    ///
2001    /// ```no_run
2002    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2003    ///
2004    /// # fn main() -> testresult::TestResult {
2005    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2006    /// let nethsm = NetHsm::new(
2007    ///     Connection::new(
2008    ///         "https://example.org/api/v1".try_into()?,
2009    ///         ConnectionSecurity::Unsafe,
2010    ///     ),
2011    ///     Some(Credentials::new(
2012    ///         "admin".parse()?,
2013    ///         Some(Passphrase::new("passphrase".to_string())),
2014    ///     )),
2015    ///     None,
2016    ///     None,
2017    /// )?;
2018    /// // add a user in the Administrator role for a namespace (N-Administrator)
2019    /// nethsm.add_user(
2020    ///     "Namespace1 Admin".to_string(),
2021    ///     UserRole::Administrator,
2022    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2023    ///     Some("namespace1~admin1".parse()?),
2024    /// )?;
2025    /// // create accompanying namespace
2026    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2027    ///
2028    /// // N-Administrators can not reboot the NetHSM
2029    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2030    /// assert!(nethsm.reboot().is_err());
2031    ///
2032    /// // R-Administrators can reboot the NetHSM
2033    /// nethsm.use_credentials(&"admin".parse()?)?;
2034    /// nethsm.reboot()?;
2035    /// # Ok(())
2036    /// # }
2037    /// ```
2038    /// [Reboots]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
2039    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2040    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2041    pub fn reboot(&self) -> Result<(), Error> {
2042        debug!(
2043            "Reboot the NetHSM at {} using {}",
2044            self.url.borrow(),
2045            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2046        );
2047
2048        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2049        system_reboot_post(&self.create_connection_config()).map_err(|error| {
2050            Error::Api(format!(
2051                "Rebooting NetHSM failed: {}",
2052                NetHsmApiError::from(error)
2053            ))
2054        })?;
2055        Ok(())
2056    }
2057
2058    /// [Shuts down] the NetHSM.
2059    ///
2060    /// [Shuts down] the NetHSM, if it is in [`Operational`][`SystemState::Operational`] [state].
2061    ///
2062    /// This call requires using [`Credentials`] of a system-wide user in the
2063    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2064    ///
2065    /// # Errors
2066    ///
2067    /// Returns an [`Error::Api`] if shutting down the NetHSM fails:
2068    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2069    /// * the used [`Credentials`] are not correct
2070    /// * the used [`Credentials`] are not that of a system-wide user in the
2071    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2072    ///
2073    /// # Examples
2074    ///
2075    /// ```no_run
2076    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2077    ///
2078    /// # fn main() -> testresult::TestResult {
2079    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2080    /// let nethsm = NetHsm::new(
2081    ///     Connection::new(
2082    ///         "https://example.org/api/v1".try_into()?,
2083    ///         ConnectionSecurity::Unsafe,
2084    ///     ),
2085    ///     Some(Credentials::new(
2086    ///         "admin".parse()?,
2087    ///         Some(Passphrase::new("passphrase".to_string())),
2088    ///     )),
2089    ///     None,
2090    ///     None,
2091    /// )?;
2092    /// // add a user in the Administrator role for a namespace (N-Administrator)
2093    /// nethsm.add_user(
2094    ///     "Namespace1 Admin".to_string(),
2095    ///     UserRole::Administrator,
2096    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2097    ///     Some("namespace1~admin1".parse()?),
2098    /// )?;
2099    /// // create accompanying namespace
2100    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2101    ///
2102    /// // N-Administrators can not shut down the NetHSM
2103    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2104    /// assert!(nethsm.shutdown().is_err());
2105    ///
2106    /// // R-Administrators can shut down the NetHSM
2107    /// nethsm.use_credentials(&"admin".parse()?)?;
2108    /// nethsm.shutdown()?;
2109    /// # Ok(())
2110    /// # }
2111    /// ```
2112    /// [Shuts down]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
2113    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2114    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2115    pub fn shutdown(&self) -> Result<(), Error> {
2116        debug!(
2117            "Shut down the NetHSM at {} using {}",
2118            self.url.borrow(),
2119            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2120        );
2121
2122        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2123        system_shutdown_post(&self.create_connection_config()).map_err(|error| {
2124            Error::Api(format!(
2125                "Shutting down NetHSM failed: {}",
2126                NetHsmApiError::from(error)
2127            ))
2128        })?;
2129        Ok(())
2130    }
2131
2132    /// Uploads a software update.
2133    ///
2134    /// WARNING: This function has shown flaky behavior during tests with the official container!
2135    /// Upload may have to be repeated!
2136    ///
2137    /// Uploads a [software update] to the NetHSM, if it is in
2138    /// [`Operational`][`SystemState::Operational`] [state] and returns information about the
2139    /// software update as [`SystemUpdateData`].
2140    /// Software updates can successively be installed ([`commit_update`][`NetHsm::commit_update`])
2141    /// or canceled ([`cancel_update`][`NetHsm::cancel_update`]).
2142    ///
2143    /// This call requires using [`Credentials`] of a system-wide user in the
2144    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2145    ///
2146    /// # Errors
2147    ///
2148    /// Returns an [`Error::Api`] if uploading the software update fails:
2149    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2150    /// * the used [`Credentials`] are not correct
2151    /// * the used [`Credentials`] are not that of a system-wide user in the
2152    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2153    ///
2154    /// # Examples
2155    ///
2156    /// ```no_run
2157    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2158    ///
2159    /// # fn main() -> testresult::TestResult {
2160    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2161    /// let nethsm = NetHsm::new(
2162    ///     Connection::new(
2163    ///         "https://example.org/api/v1".try_into()?,
2164    ///         ConnectionSecurity::Unsafe,
2165    ///     ),
2166    ///     Some(Credentials::new(
2167    ///         "admin".parse()?,
2168    ///         Some(Passphrase::new("passphrase".to_string())),
2169    ///     )),
2170    ///     None,
2171    ///     None,
2172    /// )?;
2173    /// // add a user in the Administrator role for a namespace (N-Administrator)
2174    /// nethsm.add_user(
2175    ///     "Namespace1 Admin".to_string(),
2176    ///     UserRole::Administrator,
2177    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2178    ///     Some("namespace1~admin1".parse()?),
2179    /// )?;
2180    /// // create accompanying namespace
2181    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2182    ///
2183    /// // N-Administrators can not upload software updates to the NetHSM
2184    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2185    /// assert!(nethsm.upload_update(std::fs::read("update.bin")?).is_err());
2186    ///
2187    /// // R-Administrators can upload software updates to the NetHSM
2188    /// nethsm.use_credentials(&"admin".parse()?)?;
2189    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
2190    /// # Ok(())
2191    /// # }
2192    /// ```
2193    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
2194    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2195    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2196    pub fn upload_update(&self, update: Vec<u8>) -> Result<SystemUpdateData, Error> {
2197        debug!(
2198            "Upload an update to the NetHSM at {} using {}",
2199            self.url.borrow(),
2200            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2201        );
2202
2203        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2204        Ok(system_update_post(&self.create_connection_config(), update)
2205            .map_err(|error| {
2206                println!("error during upload");
2207                Error::Api(format!(
2208                    "Uploading update failed: {}",
2209                    NetHsmApiError::from(error)
2210                ))
2211            })?
2212            .entity)
2213    }
2214
2215    /// Commits an already uploaded [software update].
2216    ///
2217    /// Commits a [software update] previously uploaded to the NetHSM (using
2218    /// [`upload_update`][`NetHsm::upload_update`]), if the NetHSM is in
2219    /// [`Operational`][`SystemState::Operational`] [state].
2220    /// Successfully committing a [software update] leads to the [reboot] of the NetHSM.
2221    ///
2222    /// This call requires using [`Credentials`] of a system-wide user in the
2223    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2224    ///
2225    /// # Errors
2226    ///
2227    /// Returns an [`Error::Api`] if committing the software update fails:
2228    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2229    /// * there is no software update to commit
2230    /// * the used [`Credentials`] are not correct
2231    /// * the used [`Credentials`] are not that of a system-wide user in the
2232    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2233    ///
2234    /// # Examples
2235    ///
2236    /// ```no_run
2237    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2238    ///
2239    /// # fn main() -> testresult::TestResult {
2240    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2241    /// let nethsm = NetHsm::new(
2242    ///     Connection::new(
2243    ///         "https://example.org/api/v1".try_into()?,
2244    ///         ConnectionSecurity::Unsafe,
2245    ///     ),
2246    ///     Some(Credentials::new(
2247    ///         "admin".parse()?,
2248    ///         Some(Passphrase::new("passphrase".to_string())),
2249    ///     )),
2250    ///     None,
2251    ///     None,
2252    /// )?;
2253    /// // add a user in the Administrator role for a namespace (N-Administrator)
2254    /// nethsm.add_user(
2255    ///     "Namespace1 Admin".to_string(),
2256    ///     UserRole::Administrator,
2257    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2258    ///     Some("namespace1~admin1".parse()?),
2259    /// )?;
2260    /// // create accompanying namespace
2261    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2262    ///
2263    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
2264    ///
2265    /// // N-Administrators can not commit software updates on a NetHSM
2266    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2267    /// assert!(nethsm.commit_update().is_err());
2268    ///
2269    /// // R-Administrators can commit software updates on a NetHSM
2270    /// nethsm.use_credentials(&"admin".parse()?)?;
2271    /// nethsm.commit_update()?;
2272    /// # Ok(())
2273    /// # }
2274    /// ```
2275    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
2276    /// [reboot]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
2277    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2278    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2279    pub fn commit_update(&self) -> Result<(), Error> {
2280        debug!(
2281            "Commit an already uploaded update on the NetHSM at {} using {}",
2282            self.url.borrow(),
2283            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2284        );
2285
2286        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2287        system_commit_update_post(&self.create_connection_config()).map_err(|error| {
2288            Error::Api(format!(
2289                "Committing update failed: {}",
2290                NetHsmApiError::from(error)
2291            ))
2292        })?;
2293        Ok(())
2294    }
2295
2296    /// Cancels an already uploaded [software update].
2297    ///
2298    /// Cancels a [software update] previously uploaded to the NetHSM (using
2299    /// [`upload_update`][`NetHsm::upload_update`]), if the NetHSM is in
2300    /// [`Operational`][`SystemState::Operational`] [state].
2301    ///
2302    /// This call requires using [`Credentials`] of a system-wide user in the
2303    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2304    ///
2305    /// # Errors
2306    ///
2307    /// Returns an [`Error::Api`] if canceling the software update fails:
2308    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2309    /// * there is no software update to cancel
2310    /// * the used [`Credentials`] are not correct
2311    /// * the used [`Credentials`] are not that of a system-wide user in the
2312    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2313    ///
2314    /// # Examples
2315    ///
2316    /// ```no_run
2317    /// use nethsm::{
2318    ///     Connection,
2319    ///     ConnectionSecurity,
2320    ///     Credentials,
2321    ///     NetHsm,
2322    ///     Passphrase,
2323    ///     SystemState,
2324    ///     UserRole,
2325    /// };
2326    ///
2327    /// # fn main() -> testresult::TestResult {
2328    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2329    /// let nethsm = NetHsm::new(
2330    ///     Connection::new(
2331    ///         "https://example.org/api/v1".try_into()?,
2332    ///         ConnectionSecurity::Unsafe,
2333    ///     ),
2334    ///     Some(Credentials::new(
2335    ///         "admin".parse()?,
2336    ///         Some(Passphrase::new("passphrase".to_string())),
2337    ///     )),
2338    ///     None,
2339    ///     None,
2340    /// )?;
2341    /// // add a user in the Administrator role for a namespace (N-Administrator)
2342    /// nethsm.add_user(
2343    ///     "Namespace1 Admin".to_string(),
2344    ///     UserRole::Administrator,
2345    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2346    ///     Some("namespace1~admin1".parse()?),
2347    /// )?;
2348    /// // create accompanying namespace
2349    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2350    ///
2351    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
2352    /// assert_eq!(nethsm.state()?, SystemState::Operational);
2353    ///
2354    /// // N-Administrators can not cancel software updates on a NetHSM
2355    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2356    /// assert!(nethsm.cancel_update().is_err());
2357    ///
2358    /// // R-Administrators can cancel software updates on a NetHSM
2359    /// nethsm.cancel_update()?;
2360    /// assert_eq!(nethsm.state()?, SystemState::Operational);
2361    /// # Ok(())
2362    /// # }
2363    /// ```
2364    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
2365    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2366    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2367    pub fn cancel_update(&self) -> Result<(), Error> {
2368        debug!(
2369            "Cancel an already uploaded update on the NetHSM at {} using {}",
2370            self.url.borrow(),
2371            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2372        );
2373
2374        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2375        system_cancel_update_post(&self.create_connection_config()).map_err(|error| {
2376            Error::Api(format!(
2377                "Cancelling update failed: {}",
2378                NetHsmApiError::from(error)
2379            ))
2380        })?;
2381        Ok(())
2382    }
2383
2384    /// Generates [random] bytes.
2385    ///
2386    /// Retrieves `length` [random] bytes from the NetHSM, if it is in
2387    /// [`Operational`][`SystemState::Operational`] [state].
2388    ///
2389    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
2390    /// [role].
2391    ///
2392    /// # Errors
2393    ///
2394    /// Returns an [`Error::Api`] if retrieving random bytes fails:
2395    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2396    /// * the used [`Credentials`] are not correct
2397    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
2398    ///   [role]
2399    ///
2400    /// # Examples
2401    ///
2402    /// ```no_run
2403    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2404    ///
2405    /// # fn main() -> testresult::TestResult {
2406    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2407    /// let nethsm = NetHsm::new(
2408    ///     Connection::new(
2409    ///         "https://example.org/api/v1".try_into()?,
2410    ///         ConnectionSecurity::Unsafe,
2411    ///     ),
2412    ///     Some(Credentials::new(
2413    ///         "admin".parse()?,
2414    ///         Some(Passphrase::new("passphrase".to_string())),
2415    ///     )),
2416    ///     None,
2417    ///     None,
2418    /// )?;
2419    /// // add a system-wide user in the Operator role
2420    /// nethsm.add_user(
2421    ///     "Operator1".to_string(),
2422    ///     UserRole::Operator,
2423    ///     Passphrase::new("operator-passphrase".to_string()),
2424    ///     Some("operator1".parse()?),
2425    /// )?;
2426    /// nethsm.use_credentials(&"operator1".parse()?)?;
2427    ///
2428    /// // get 10 random bytes
2429    /// println!("{:#?}", nethsm.random(10)?);
2430    /// # Ok(())
2431    /// # }
2432    /// ```
2433    /// [random]: https://docs.nitrokey.com/nethsm/operation#random
2434    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
2435    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2436    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2437    pub fn random(&self, length: u32) -> Result<Vec<u8>, Error> {
2438        debug!(
2439            "Create {length} random bytes on the NetHSM at {} using {}",
2440            self.url.borrow(),
2441            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2442        );
2443
2444        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
2445        let base64_bytes = random_post(
2446            &self.create_connection_config(),
2447            RandomRequestData::new(length as i32),
2448        )
2449        .map_err(|error| {
2450            Error::Api(format!(
2451                "Getting random bytes failed: {}",
2452                NetHsmApiError::from(error)
2453            ))
2454        })?
2455        .entity
2456        .random;
2457        Base64::decode_vec(&base64_bytes).map_err(Error::Base64Decode)
2458    }
2459}