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
51pub enum PassphrasePrompt {
53 Backup,
55 CurrentBackup,
57 CurrentUnlock,
59 NewBackup,
61 NewUnlock,
63 NewUser(UserId),
65 Unlock,
67 User {
69 user_id: Option<UserId>,
70 real_name: Option<String>,
71 },
72}
73
74impl PassphrasePrompt {
75 pub fn prompt(&self) -> Result<Passphrase, Error> {
77 let reason = match self {
78 Self::Backup => "Backup passphrase: ".to_string(),
79 Self::CurrentBackup => "Current backup passphrase: ".to_string(),
80 Self::CurrentUnlock => "Current unlock passphrase: ".to_string(),
81 Self::NewBackup => "New backup passphrase: ".to_string(),
82 Self::NewUnlock => "New unlock passphrase: ".to_string(),
83 Self::NewUser(user) => format!("New passphrase for user \"{user}\": "),
84 Self::Unlock => "Unlock passphrase: ".to_string(),
85 Self::User { user_id, real_name } => match (user_id, real_name) {
86 (Some(user_id), Some(real_name)) => {
87 format!("Passphrase for user \"{user_id}\" (\"{real_name}\"): ")
88 }
89 (None, Some(real_name)) => format!("Passphrase for user \"{real_name}\": "),
90 (None, None) => "Passphrase for unknown user: ".to_string(),
91 (Some(user_id), None) => format!("Passphrase for unknown user \"{user_id}\": "),
92 },
93 };
94
95 Ok(Passphrase::new(prompt_password(reason).map_err(
96 |_| match self {
97 Self::Backup => Error::Backup,
98 Self::CurrentBackup => Error::CurrentBackup,
99 Self::CurrentUnlock => Error::CurrentUnlock,
100 Self::NewBackup => Error::NewBackup,
101 Self::NewUnlock => Error::NewUnlock,
102 Self::NewUser(user) => Error::NewUser(user.to_string()),
103 Self::Unlock => Error::Unlock,
104 Self::User { user_id, real_name } => Error::User {
105 user_id: user_id.to_owned(),
106 real_name: real_name.to_owned(),
107 },
108 },
109 )?))
110 }
111}
112
113pub struct UserPrompt(UserRole);
115
116impl UserPrompt {
117 pub fn new(role: UserRole) -> Self {
119 Self(role)
120 }
121
122 pub fn prompt(&self) -> Result<UserId, Error> {
124 let reason = match self.0 {
125 UserRole::Administrator => "Name of a user in the \"Administrator\" role: ".to_string(),
126 UserRole::Backup => "Name of a user in the \"Backup\" role: ".to_string(),
127 UserRole::Metrics => "Name of a user in the \"Metrics\" role: ".to_string(),
128 UserRole::Operator => "Name of a user in the \"Operator\" role: ".to_string(),
129 };
130
131 let name = UserId::new(prompt_reply(reason).map_err(|_| Error::UserName)?)?;
132 Ok(name)
133 }
134}