1use std::{error::Error, fmt::Display};
2
3use inquire::Confirm;
4use pants_gen::password::Password;
5use serde::{Deserialize, Serialize};
6
7use crate::errors::SchemaError;
8
9#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
10pub enum Store {
11 Password(String),
12 UsernamePassword(String, String),
13}
14
15impl Display for Store {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 Self::Password(p) => write!(f, "{}", p),
19 Self::UsernamePassword(username, password) => write!(f, "{}: {}", username, password),
20 }
21 }
22}
23
24impl Store {
25 pub fn repr(&self) -> String {
27 match self {
28 Self::Password(_) => "password".to_string(),
29 Self::UsernamePassword(_, _) => "username-password".to_string(),
30 }
31 }
32
33 pub fn prompt(repr: &str) -> Result<Store, Box<dyn Error>> {
65 match repr {
66 "password" => Self::get_password().map(Store::Password),
67 "username-password" => {
68 let username_input = inquire::Text::new("Username:")
69 .with_help_message("New username")
70 .prompt();
71 let username = username_input?;
72 let password = Self::get_password()?;
73 Ok(Store::UsernamePassword(username, password))
74 }
75 _ => Err(Box::new(SchemaError::BadType)),
76 }
77 }
78
79 fn get_password() -> Result<String, Box<dyn Error>> {
80 let generate = Confirm::new("Generate password?")
81 .with_default(true)
82 .with_help_message("Create a random password or enter manually?")
83 .prompt();
84 match generate {
85 Ok(true) => {
86 let length_input = inquire::CustomType::<usize>::new("Length of password?")
87 .with_help_message("Number of characters use in the generated password")
88 .with_error_message("Please type a valid number")
89 .with_default(32)
90 .prompt()?;
91 let upper = inquire::Confirm::new("Use uppercase letters?")
92 .with_default(true)
93 .with_help_message(
94 "Use the uppercase alphabetic characters (A-Z) in password generation",
95 )
96 .prompt()?;
97 let lower = inquire::Confirm::new("Use lowercase letters?")
98 .with_default(true)
99 .with_help_message(
100 "Use the lowercase alphabetic characters (a-z) in password generation",
101 )
102 .prompt()?;
103 let numbers = inquire::Confirm::new("Use numbers?")
104 .with_default(true)
105 .with_help_message("Use the numbers (0-9) in password generation")
106 .prompt()?;
107 let symbols = inquire::Confirm::new("Use symbols?")
108 .with_default(true)
109 .with_help_message("Use special symbols in password generation")
110 .prompt()?;
111
112 let mut spec = Password::new().length(length_input);
113
114 if upper {
115 spec = spec.upper_at_least(1);
116 }
117 if lower {
118 spec = spec.lower_at_least(1);
119 }
120 if numbers {
121 spec = spec.number_at_least(1);
122 }
123 if symbols {
124 spec = spec.symbol_at_least(1);
125 }
126 let password = spec.generate().unwrap();
127 Ok(password)
128 }
129 Ok(false) => {
130 let password_input = inquire::Password::new("Password: ")
131 .with_display_toggle_enabled()
132 .with_display_mode(inquire::PasswordDisplayMode::Masked)
133 .prompt();
134 match password_input {
135 Ok(p) => Ok(p),
136 Err(_) => Err(Box::new(SchemaError::BadValues)),
137 }
138 }
139 Err(_) => Err(Box::new(SchemaError::BadValues)),
140 }
141 }
142}