nethsm_config/
prompt.rs

1use nethsm::{Passphrase, UserId, UserRole};
2use rpassword::prompt_password;
3use rprompt::prompt_reply;
4
5#[derive(Debug, thiserror::Error)]
6pub enum Error {
7    /// Getting backup passphrase failed
8    #[error("Unable to get backup passphrase")]
9    Backup,
10
11    /// Getting current backup passphrase failed
12    #[error("Unable to get current backup passphrase")]
13    CurrentBackup,
14
15    /// Getting current unlock passphrase failed
16    #[error("Unable to get current unlock passphrase")]
17    CurrentUnlock,
18
19    /// Getting new backup passphrase failed
20    #[error("Unable to get new backup passphrase")]
21    NewBackup,
22
23    /// Getting new unlock passphrase failed
24    #[error("Unable to get new unlock passphrase")]
25    NewUnlock,
26
27    /// Getting new passphrase for user failed
28    #[error("Unable to get new passphrase for user {0}")]
29    NewUser(String),
30
31    /// Getting unlock passphrase failed
32    #[error("Unable to get unlock passphrase")]
33    Unlock,
34
35    /// Getting current passphrase for user failed
36    #[error("Unable to get passphrase for user {user_id:?} ({real_name:?}) ")]
37    User {
38        user_id: Option<UserId>,
39        real_name: Option<String>,
40    },
41
42    /// Getting username failed
43    #[error("Unable to get username")]
44    UserName,
45
46    /// The user data is not correct
47    #[error("User data is invalid: {0}")]
48    NetHsmUser(#[from] nethsm::UserError),
49}
50
51/// Passphrase prompt
52#[derive(Debug)]
53pub enum PassphrasePrompt {
54    /// Prompt for backup passphrase
55    Backup,
56    /// Prompt for current backup passphrase
57    CurrentBackup,
58    /// Prompt for current unlock passphrase
59    CurrentUnlock,
60    /// Prompt for new backup passphrase
61    NewBackup,
62    /// Prompt for new unlock passphrase
63    NewUnlock,
64    /// Prompt for new user passphrase
65    NewUser(UserId),
66    /// Prompt for unlock passphrase
67    Unlock,
68    /// Prompt for current user passphrase
69    User {
70        /// The optional user ID to show.
71        user_id: Option<UserId>,
72        /// The optional real name to show.
73        real_name: Option<String>,
74    },
75}
76
77impl PassphrasePrompt {
78    /// Prompts for a passphrase
79    pub fn prompt(&self) -> Result<Passphrase, Error> {
80        let reason = match self {
81            Self::Backup => "Backup passphrase: ".to_string(),
82            Self::CurrentBackup => "Current backup passphrase: ".to_string(),
83            Self::CurrentUnlock => "Current unlock passphrase: ".to_string(),
84            Self::NewBackup => "New backup passphrase: ".to_string(),
85            Self::NewUnlock => "New unlock passphrase: ".to_string(),
86            Self::NewUser(user) => format!("New passphrase for user \"{user}\": "),
87            Self::Unlock => "Unlock passphrase: ".to_string(),
88            Self::User { user_id, real_name } => match (user_id, real_name) {
89                (Some(user_id), Some(real_name)) => {
90                    format!("Passphrase for user \"{user_id}\" (\"{real_name}\"): ")
91                }
92                (None, Some(real_name)) => format!("Passphrase for user \"{real_name}\": "),
93                (None, None) => "Passphrase for unknown user: ".to_string(),
94                (Some(user_id), None) => format!("Passphrase for unknown user \"{user_id}\": "),
95            },
96        };
97
98        Ok(Passphrase::new(prompt_password(reason).map_err(
99            |_| match self {
100                Self::Backup => Error::Backup,
101                Self::CurrentBackup => Error::CurrentBackup,
102                Self::CurrentUnlock => Error::CurrentUnlock,
103                Self::NewBackup => Error::NewBackup,
104                Self::NewUnlock => Error::NewUnlock,
105                Self::NewUser(user) => Error::NewUser(user.to_string()),
106                Self::Unlock => Error::Unlock,
107                Self::User { user_id, real_name } => Error::User {
108                    user_id: user_id.to_owned(),
109                    real_name: real_name.to_owned(),
110                },
111            },
112        )?))
113    }
114}
115
116/// Username prompt
117#[derive(Debug)]
118pub struct UserPrompt(UserRole);
119
120impl UserPrompt {
121    /// Creates a new [`UserPrompt`] based on a [`UserRole`]
122    pub fn new(role: UserRole) -> Self {
123        Self(role)
124    }
125
126    /// Prompt for a username
127    pub fn prompt(&self) -> Result<UserId, Error> {
128        let reason = match self.0 {
129            UserRole::Administrator => "Name of a user in the \"Administrator\" role: ".to_string(),
130            UserRole::Backup => "Name of a user in the \"Backup\" role: ".to_string(),
131            UserRole::Metrics => "Name of a user in the \"Metrics\" role: ".to_string(),
132            UserRole::Operator => "Name of a user in the \"Operator\" role: ".to_string(),
133        };
134
135        let name = UserId::new(prompt_reply(reason).map_err(|_| Error::UserName)?)?;
136        Ok(name)
137    }
138}