bw/tools/
mod.rs

1use bitwarden_generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest};
2use bitwarden_pm::PasswordManagerClient;
3use clap::Args;
4
5use crate::render::CommandResult;
6
7#[derive(Args, Clone)]
8pub struct GenerateArgs {
9    // Password arguments
10    #[arg(short = 'u', long, action, help = "Include uppercase characters (A-Z)")]
11    pub uppercase: bool,
12
13    #[arg(short = 'l', long, action, help = "Include lowercase characters (a-z)")]
14    pub lowercase: bool,
15
16    #[arg(short = 'n', long, action, help = "Include numbers (0-9)")]
17    pub number: bool,
18
19    #[arg(
20        short = 's',
21        long,
22        action,
23        help = "Include special characters (!@#$%^&*)"
24    )]
25    pub special: bool,
26
27    #[arg(long, default_value = "16", help = "Length of generated password")]
28    pub length: u8,
29
30    #[arg(long, help = "Minimum number of numeric characters")]
31    pub min_numbers: Option<u8>,
32
33    #[arg(long, help = "Minimum number of special characters")]
34    pub min_special: Option<u8>,
35
36    #[arg(long, action, help = "Avoid ambiguous characters")]
37    pub ambiguous: bool,
38
39    // Passphrase arguments
40    #[arg(short = 'p', long, action, help = "Generate a passphrase")]
41    pub passphrase: bool,
42
43    #[arg(long, default_value = "5", help = "Number of words in the passphrase")]
44    pub words: u8,
45
46    #[arg(long, default_value = "-", help = "Separator between words")]
47    pub separator: char,
48
49    #[arg(long, action, help = "Capitalize the first letter of each word")]
50    pub capitalize: bool,
51
52    #[arg(long, action, help = "Include a number in one of the words")]
53    pub include_number: bool,
54}
55
56impl GenerateArgs {
57    pub fn run(mut self, client: &PasswordManagerClient) -> CommandResult {
58        let result = if self.passphrase {
59            client.generator().passphrase(PassphraseGeneratorRequest {
60                num_words: self.words,
61                word_separator: self.separator.to_string(),
62                capitalize: self.capitalize,
63                include_number: self.include_number,
64            })?
65        } else {
66            // Default options if none are specified
67            if !self.lowercase && !self.uppercase && !self.number && !self.special {
68                self.lowercase = true;
69                self.uppercase = true;
70                self.number = true;
71            }
72
73            client.generator().password(PasswordGeneratorRequest {
74                lowercase: self.lowercase,
75                uppercase: self.uppercase,
76                numbers: self.number,
77                special: self.special,
78                length: self.length,
79                min_number: self.min_numbers,
80                min_special: self.min_special,
81                avoid_ambiguous: self.ambiguous,
82                ..Default::default()
83            })?
84        };
85
86        Ok(result.into())
87    }
88}