nethsm_config/
prompt.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use nethsm::{Passphrase, UserId, UserRole};
use rpassword::prompt_password;
use rprompt::prompt_reply;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// Getting backup passphrase failed
    #[error("Unable to get backup passphrase")]
    Backup,

    /// Getting current backup passphrase failed
    #[error("Unable to get current backup passphrase")]
    CurrentBackup,

    /// Getting current unlock passphrase failed
    #[error("Unable to get current unlock passphrase")]
    CurrentUnlock,

    /// Getting new backup passphrase failed
    #[error("Unable to get new backup passphrase")]
    NewBackup,

    /// Getting new unlock passphrase failed
    #[error("Unable to get new unlock passphrase")]
    NewUnlock,

    /// Getting new passphrase for user failed
    #[error("Unable to get new passphrase for user {0}")]
    NewUser(String),

    /// Getting unlock passphrase failed
    #[error("Unable to get unlock passphrase")]
    Unlock,

    /// Getting current passphrase for user failed
    #[error("Unable to get passphrase for user {user_id:?} ({real_name:?}) ")]
    User {
        user_id: Option<UserId>,
        real_name: Option<String>,
    },

    /// Getting username failed
    #[error("Unable to get username")]
    UserName,

    /// The user data is not correct
    #[error("User data is invalid: {0}")]
    NetHsmUser(#[from] nethsm::UserError),
}

/// Passphrase prompt
pub enum PassphrasePrompt {
    /// Prompt for backup passphrase
    Backup,
    /// Prompt for current backup passphrase
    CurrentBackup,
    /// Prompt for current unlock passphrase
    CurrentUnlock,
    /// Prompt for new backup passphrase
    NewBackup,
    /// Prompt for new unlock passphrase
    NewUnlock,
    /// Prompt for new user passphrase
    NewUser(UserId),
    /// Prompt for unlock passphrase
    Unlock,
    /// Prompt for current user passphrase
    User {
        user_id: Option<UserId>,
        real_name: Option<String>,
    },
}

impl PassphrasePrompt {
    /// Prompts for a passphrase
    pub fn prompt(&self) -> Result<Passphrase, Error> {
        let reason = match self {
            Self::Backup => "Backup passphrase: ".to_string(),
            Self::CurrentBackup => "Current backup passphrase: ".to_string(),
            Self::CurrentUnlock => "Current unlock passphrase: ".to_string(),
            Self::NewBackup => "New backup passphrase: ".to_string(),
            Self::NewUnlock => "New unlock passphrase: ".to_string(),
            Self::NewUser(user) => format!("New passphrase for user \"{user}\": "),
            Self::Unlock => "Unlock passphrase: ".to_string(),
            Self::User { user_id, real_name } => match (user_id, real_name) {
                (Some(user_id), Some(real_name)) => {
                    format!("Passphrase for user \"{user_id}\" (\"{real_name}\"): ")
                }
                (None, Some(real_name)) => format!("Passphrase for user \"{real_name}\": "),
                (None, None) => "Passphrase for unknown user: ".to_string(),
                (Some(user_id), None) => format!("Passphrase for unknown user \"{user_id}\": "),
            },
        };

        Ok(Passphrase::new(prompt_password(reason).map_err(
            |_| match self {
                Self::Backup => Error::Backup,
                Self::CurrentBackup => Error::CurrentBackup,
                Self::CurrentUnlock => Error::CurrentUnlock,
                Self::NewBackup => Error::NewBackup,
                Self::NewUnlock => Error::NewUnlock,
                Self::NewUser(user) => Error::NewUser(user.to_string()),
                Self::Unlock => Error::Unlock,
                Self::User { user_id, real_name } => Error::User {
                    user_id: user_id.to_owned(),
                    real_name: real_name.to_owned(),
                },
            },
        )?))
    }
}

/// Username prompt
pub struct UserPrompt(UserRole);

impl UserPrompt {
    /// Creates a new [`UserPrompt`] based on a [`UserRole`]
    pub fn new(role: UserRole) -> Self {
        Self(role)
    }

    /// Prompt for a username
    pub fn prompt(&self) -> Result<UserId, Error> {
        let reason = match self.0 {
            UserRole::Administrator => "Name of a user in the \"Administrator\" role: ".to_string(),
            UserRole::Backup => "Name of a user in the \"Backup\" role: ".to_string(),
            UserRole::Metrics => "Name of a user in the \"Metrics\" role: ".to_string(),
            UserRole::Operator => "Name of a user in the \"Operator\" role: ".to_string(),
        };

        let name = UserId::new(prompt_reply(reason).map_err(|_| Error::UserName)?)?;
        Ok(name)
    }
}