rust_unique_pass/cli/
cli.rs

1use {crate::password::password_generation::MAX_TIMEOUT_MS, clap::Parser};
2
3/// # Overview
4/// コマンドライン引数を定義する構造体。
5/// `clap` クレートを使用して引数をパースします。
6
7#[derive(Parser, Debug, PartialEq)]
8#[command(about = "Command-line options for rupass.")]
9pub struct RupassArgs {
10    // 設定言語を指定する
11    #[clap(
12        short = 'l',
13        long = "language",
14        short_alias = 'L',
15        value_name = "LANGUAGE",
16        help = "Specifies the language for user prompts and messages.\
17            \nDefault: English. ISO639-3 codes: eng, jpn, deu."
18    )]
19    pub language: Option<String>,
20
21    // パスワード長を指定する
22    #[clap(
23        short = 'p',
24        long = "password-length",
25        value_name = "PASSWORD_LENGTH",
26        help = "Specify the length of the password. \
27            \nDefault: prompt (interactive).\
28            \nWith --no-prompt you must specify this."
29    )]
30    pub password_length: Option<usize>,
31
32    // 文字種を全て有効化するショートカット
33    #[clap(
34        short = 'a',
35        long = "all",
36        conflicts_with_all = [
37            "no_numbers",
38            "no_uppercase",
39            "no_lowercase",
40            "no_symbols",
41        ],
42        help = "Enable all character classes: numbers, uppercase, lowercase, symbols.\
43            \nConflicts: --no-numbers, --no-uppercase, --no-lowercase, --no-symbols"
44    )]
45    pub all: bool,
46
47    // 対話を行わずデフォルト(OFF)のまま進める
48    #[clap(
49        long = "no-prompt",
50        help = "Disable all interactive questions.\
51            \nUnspecified character classes stay OFF.\
52            \nRequires specifying --password-length."
53    )]
54    pub no_prompt: bool,
55
56    // 数字を含むかどうかのフラグ
57    #[clap(
58        short = 'n',
59        long = "numbers",
60        help = "Include numbers in the password.\
61            \nDefault: OFF.\
62            \nNegative form available: --no-numbers (-N)."
63    )]
64    pub numbers: bool,
65
66    // 数字を使用しないフラグ
67    #[clap(
68        short = 'N',
69        long = "no-numbers",
70        help = "Exclude numbers from the password (alias of not setting --numbers).",
71        conflicts_with = "numbers"
72    )]
73    pub no_numbers: bool,
74
75    // 大文字を含むかどうかのフラグ
76    #[clap(
77        short = 'u',
78        long = "uppercase",
79        help = "Include uppercase letters in the password.\
80            \nDefault: OFF.\
81            \nNegative form available: --no-uppercase (-U)."
82    )]
83    pub uppercase: bool,
84
85    // 大文字を使用しないフラグ
86    #[clap(
87        short = 'U',
88        long = "no-uppercase",
89        help = "Exclude uppercase letters from the password (alias of not setting --uppercase).",
90        conflicts_with = "uppercase"
91    )]
92    pub no_uppercase: bool,
93
94    // 小文字を含むかどうかのフラグ
95    #[clap(
96        short = 'w',
97        long = "lowercase",
98        help = "Include lowercase letters in the password.\
99            \nDefault: OFF.\
100            \nNegative form available: --no-lowercase (-W)."
101    )]
102    pub lowercase: bool,
103
104    // 小文字を使用しないフラグ
105    #[clap(
106        short = 'W',
107        long = "no-lowercase",
108        help = "Exclude lowercase letters from the password (alias of not setting --lowercase).",
109        conflicts_with = "lowercase"
110    )]
111    pub no_lowercase: bool,
112
113    // 特殊記号を含むかどうかのフラグ
114    #[clap(
115        short = 's',
116        long = "symbols",
117        help = "Include symbols in passwords.\
118        \nDefault: OFF.\
119        \nBy default uses ~!@#$%^&*_-+=(){}[]:;<>,.?/.\
120        \nNegative form available: --no-symbols (-S)."
121    )]
122    pub symbols: bool,
123
124    // 特殊記号を使用しないフラグ
125    #[clap(
126        short = 'S',
127        long = "no-symbols",
128        help = "Exclude symbols from the password (alias of not setting --symbols).",
129        conflicts_with = "symbols"
130    )]
131    pub no_symbols: bool,
132
133    // カスタム特殊記号セット
134    #[clap(
135        long = "symbols-set",
136        value_name = "SYMBOLS_SET",
137        help = "Custom set of symbols to use with --symbols (non-empty string).",
138        requires = "symbols",
139        conflicts_with = "no_symbols",
140        value_parser = clap::builder::NonEmptyStringValueParser::new()
141    )]
142    pub symbols_set: Option<String>,
143
144    // 強度探索の時間予算(ミリ秒)
145    #[clap(
146        long = "timeout-ms",
147        alias = "budget-ms",
148        value_name = "TIMEOUT_MS",
149        default_value_t = 150u64,
150        value_parser = clap::value_parser!(u64).range(10..=MAX_TIMEOUT_MS),
151        help = "Time budget in milliseconds for strength search.\
152            \nAlias: --budget-ms.\
153            \nMust be between 10 and 3600000. Default: 150"
154    )]
155    pub timeout_ms: u64,
156
157    // 早期終了の目標スコア
158    #[clap(
159        long = "min-score",
160        value_name = "MIN_SCORE",
161        default_value_t = 4u8,
162        value_parser = clap::value_parser!(u8).range(0..=4),
163        help = "Target zxcvbn score for early stop (0..=4). Default: 4"
164    )]
165    pub min_score: u8,
166
167    // 厳格モード:期限内未達で失敗
168    #[clap(
169        long = "strict",
170        help = "Strict mode: fail if target score not reached within time budget"
171    )]
172    pub strict: bool,
173
174    // 強度行の表示
175    #[clap(
176        long = "show-strength",
177        help = "Show strength line (score/entropy) on success"
178    )]
179    pub show_strength: bool,
180
181    // 静かな出力(別名: porcelain)
182    #[clap(
183        long = "quiet",
184        alias = "porcelain",
185        help = "Quiet (porcelain) output: print only the password on success"
186    )]
187    pub quiet: bool,
188}
189
190/// # Overview
191/// コマンドライン引数をパースして [`RupassArgs`] 構造体を生成します。
192/// `clap::Parser::parse()` を使用します。
193#[doc(alias = "parse")]
194#[doc(alias = "args")]
195pub fn parse_args() -> RupassArgs {
196    RupassArgs::parse()
197}