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
135
136
137
138
139
140
141
142
use std::{error::Error, fmt::Display};
use inquire::Confirm;
use pants_gen::password::Password;
use serde::{Deserialize, Serialize};
use crate::errors::SchemaError;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum Store {
Password(String),
UsernamePassword(String, String),
}
impl Display for Store {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Password(p) => write!(f, "{}", p),
Self::UsernamePassword(username, password) => write!(f, "{}: {}", username, password),
}
}
}
impl Store {
// how to represent the type in the schema
pub fn repr(&self) -> String {
match self {
Self::Password(_) => "password".to_string(),
Self::UsernamePassword(_, _) => "username-password".to_string(),
}
}
// // from schema type and field values
// pub fn from_fields(
// repr: &str,
// value: HashMap<String, String>,
// ) -> Result<Store, Box<dyn Error>> {
// match repr {
// "password" => {
// if let Some(p) = value.get("password") {
// Ok(Self::Password(p.to_string()))
// } else {
// Err(Box::new(SchemaError::BadValues))
// }
// }
// _ => Err(Box::new(SchemaError::BadType)),
// }
// }
//
// // from schema type and array of values
// pub fn from_array(repr: &str, value: Vec<String>) -> Result<Store, Box<dyn Error>> {
// match repr {
// "password" => {
// if let Some(p) = value.first() {
// Ok(Self::Password(p.to_string()))
// } else {
// Err(Box::new(SchemaError::BadValues))
// }
// }
// _ => Err(Box::new(SchemaError::BadType)),
// }
// }
pub fn prompt(repr: &str) -> Result<Store, Box<dyn Error>> {
match repr {
"password" => Self::get_password().map(Store::Password),
"username-password" => {
let username_input = inquire::Text::new("Username:")
.with_help_message("New username")
.prompt();
let username = username_input?;
let password = Self::get_password()?;
Ok(Store::UsernamePassword(username, password))
}
_ => Err(Box::new(SchemaError::BadType)),
}
}
fn get_password() -> Result<String, Box<dyn Error>> {
let generate = Confirm::new("Generate password?")
.with_default(true)
.with_help_message("Create a random password or enter manually?")
.prompt();
match generate {
Ok(true) => {
let length_input = inquire::CustomType::<usize>::new("Length of password?")
.with_help_message("Number of characters use in the generated password")
.with_error_message("Please type a valid number")
.with_default(32)
.prompt()?;
let upper = inquire::Confirm::new("Use uppercase letters?")
.with_default(true)
.with_help_message(
"Use the uppercase alphabetic characters (A-Z) in password generation",
)
.prompt()?;
let lower = inquire::Confirm::new("Use lowercase letters?")
.with_default(true)
.with_help_message(
"Use the lowercase alphabetic characters (a-z) in password generation",
)
.prompt()?;
let numbers = inquire::Confirm::new("Use numbers?")
.with_default(true)
.with_help_message("Use the numbers (0-9) in password generation")
.prompt()?;
let symbols = inquire::Confirm::new("Use symbols?")
.with_default(true)
.with_help_message("Use special symbols in password generation")
.prompt()?;
let mut spec = Password::new().length(length_input);
if upper {
spec = spec.upper_at_least(1);
}
if lower {
spec = spec.lower_at_least(1);
}
if numbers {
spec = spec.number_at_least(1);
}
if symbols {
spec = spec.symbol_at_least(1);
}
let password = spec.generate().unwrap();
Ok(password)
}
Ok(false) => {
let password_input = inquire::Password::new("Password: ")
.with_display_toggle_enabled()
.with_display_mode(inquire::PasswordDisplayMode::Masked)
.prompt();
match password_input {
Ok(p) => Ok(p),
Err(_) => Err(Box::new(SchemaError::BadValues)),
}
}
Err(_) => Err(Box::new(SchemaError::BadValues)),
}
}
}