1use nethsm::{Passphrase, UserId, UserRole};
2use rpassword::prompt_password;
3use rprompt::prompt_reply;
4
5#[derive(Debug, thiserror::Error)]
6pub enum Error {
7 #[error("Unable to get backup passphrase")]
9 Backup,
10
11 #[error("Unable to get current backup passphrase")]
13 CurrentBackup,
14
15 #[error("Unable to get current unlock passphrase")]
17 CurrentUnlock,
18
19 #[error("Unable to get new backup passphrase")]
21 NewBackup,
22
23 #[error("Unable to get new unlock passphrase")]
25 NewUnlock,
26
27 #[error("Unable to get new passphrase for user {0}")]
29 NewUser(String),
30
31 #[error("Unable to get unlock passphrase")]
33 Unlock,
34
35 #[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 #[error("Unable to get username")]
44 UserName,
45
46 #[error("User data is invalid: {0}")]
48 NetHsmUser(#[from] nethsm::UserError),
49}
50
51#[derive(Debug)]
53pub enum PassphrasePrompt {
54 Backup,
56 CurrentBackup,
58 CurrentUnlock,
60 NewBackup,
62 NewUnlock,
64 NewUser(UserId),
66 Unlock,
68 User {
70 user_id: Option<UserId>,
72 real_name: Option<String>,
74 },
75}
76
77impl PassphrasePrompt {
78 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#[derive(Debug)]
118pub struct UserPrompt(UserRole);
119
120impl UserPrompt {
121 pub fn new(role: UserRole) -> Self {
123 Self(role)
124 }
125
126 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}