nethsm/
backup.rs

1//! Backup handling.
2
3use std::io::Read;
4
5use crate::Passphrase;
6
7/// Validates a [backup].
8///
9/// Parses a previously created backup file. If `passphrase` is
10/// [`Some`], additionally decrypts the backup and verifies the
11/// encrypted backup version number.
12///
13/// # Errors
14///
15/// Returns an [`nethsm_backup::Error`] if validating a [backup] fails:
16/// * the magic number is missing in the file
17/// * the version number is unknown
18/// * the provided passphrase is incorrect
19///
20/// # Examples
21///
22/// ```no_run
23/// use nethsm::{
24///     Connection,
25///     ConnectionSecurity,
26///     Credentials,
27///     NetHsm,
28///     Passphrase,
29///     validate_backup,
30/// };
31///
32/// # fn main() -> testresult::TestResult {
33/// // create a connection with a user in the Backup role
34/// let nethsm = NetHsm::new(
35///     Connection::new(
36///         "https://example.org/api/v1".try_into()?,
37///         ConnectionSecurity::Unsafe,
38///     ),
39///     Some(Credentials::new(
40///         "backup1".parse()?,
41///         Some(Passphrase::new("passphrase".to_string())),
42///     )),
43///     None,
44///     None,
45/// )?;
46///
47/// // create a backup and write it to file
48/// std::fs::write("nethsm.bkp", nethsm.backup()?)?;
49///
50/// // check for consistency only
51/// validate_backup(&mut std::fs::File::open("nethsm.bkp")?, None)?;
52///
53/// // check for correct passphrase by decrypting and validating the encrypted backup version
54/// validate_backup(
55///     &mut std::fs::File::open("nethsm.bkp")?,
56///     Passphrase::new("a sample password".into()),
57/// )?;
58/// # Ok(())
59/// # }
60/// ```
61/// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
62pub fn validate_backup(
63    reader: &mut impl Read,
64    passphrase: impl Into<Option<Passphrase>>,
65) -> Result<(), nethsm_backup::Error> {
66    let passphrase = passphrase.into();
67    let backup = nethsm_backup::Backup::parse(reader)?;
68    if let Some(passphrase) = passphrase {
69        let decryptor = backup.decrypt(passphrase.expose_borrowed().as_bytes())?;
70        let version = decryptor.version()?;
71        if version.len() != 1 || version[0] != 0 {
72            return Err(nethsm_backup::Error::BadVersion {
73                highest_supported_version: 0,
74                backup_version: version,
75            });
76        }
77    }
78    Ok(())
79}