1 /// Command-line parser for sq.
2 ///
3 /// If you change this file, please rebuild `sq`, run `make -C tool
4 /// update-usage`, and commit the resulting changes to
5 /// `tool/src/sq-usage.rs`.
6 
7 use clap::{App, Arg, ArgGroup, SubCommand, AppSettings};
8 
build() -> App<'static, 'static>9 pub fn build() -> App<'static, 'static> {
10     App::new("sq")
11         .version(env!("CARGO_PKG_VERSION"))
12         .about("Sequoia is an implementation of OpenPGP.  This is a command-line frontend.")
13         .setting(AppSettings::SubcommandRequiredElseHelp)
14         .arg(Arg::with_name("home").value_name("DIRECTORY")
15              .long("home")
16              .help("Sets the home directory to use"))
17         .arg(Arg::with_name("mapping").value_name("MAPPING")
18              .long("mapping")
19              .short("m")
20              .default_value("org.sequoia-pgp.contacts/default")
21              .help("Sets the realm and mapping to use"))
22         .arg(Arg::with_name("policy").value_name("NETWORK-POLICY")
23              .long("policy")
24              .short("p")
25              .help("Sets the network policy to use"))
26         .arg(Arg::with_name("force")
27              .long("force")
28              .short("f")
29              .help("Overwrite existing files"))
30         .arg(Arg::with_name("known-notation")
31              .long("known-notation")
32              .multiple(true)
33              .takes_value(true)
34              .value_name("NOTATION")
35              .number_of_values(1)
36              .help("The notation name is considered known. \
37                This is used when validating sigantures. \
38                Signatures that have unknown notations with the \
39                critical bit set are considered invalid."))
40         .subcommand(SubCommand::with_name("decrypt")
41                     .display_order(10)
42                     .about("Decrypts an OpenPGP message")
43                     .arg(Arg::with_name("input").value_name("FILE")
44                          .help("Sets the input file to use"))
45                     .arg(Arg::with_name("output").value_name("FILE")
46                          .long("output")
47                          .short("o")
48                          .help("Sets the output file to use"))
49                     .arg(Arg::with_name("signatures").value_name("N")
50                          .help("The number of valid signatures required.  \
51                                 Default: 0")
52                          .long("signatures")
53                          .short("n")
54                          .takes_value(true))
55                     .arg(Arg::with_name("sender-cert-file")
56                          .long("sender-cert-file")
57                          .multiple(true)
58                          .takes_value(true)
59                          .value_name("CERT-FILE")
60                          .number_of_values(1)
61                          .help("The sender's certificate verify signatures \
62                                 with, given as a file \
63                                 (can be given multiple times)"))
64                     .arg(Arg::with_name("secret-key-file")
65                          .long("secret-key-file")
66                          .multiple(true)
67                          .takes_value(true)
68                          .value_name("TSK-FILE")
69                          .number_of_values(1)
70                          .help("Secret key to decrypt with, given as a file \
71                                 (can be given multiple times)"))
72                     .arg(Arg::with_name("dump-session-key")
73                          .long("dump-session-key")
74                          .help("Prints the session key to stderr"))
75                     .arg(Arg::with_name("dump")
76                          .long("dump")
77                          .help("Print a packet dump to stderr"))
78                     .arg(Arg::with_name("hex")
79                          .long("hex")
80                          .short("x")
81                          .help("Print a hexdump (implies --dump)")))
82         .subcommand(SubCommand::with_name("encrypt")
83                     .display_order(20)
84                     .about("Encrypts a message")
85                     .arg(Arg::with_name("input").value_name("FILE")
86                          .help("Sets the input file to use"))
87                     .arg(Arg::with_name("output").value_name("FILE")
88                          .long("output")
89                          .short("o")
90                          .help("Sets the output file to use"))
91                     .arg(Arg::with_name("binary")
92                          .long("binary")
93                          .short("B")
94                          .help("Don't ASCII-armor encode the OpenPGP data"))
95                     .arg(Arg::with_name("recipient")
96                          .long("recipient")
97                          .short("r")
98                          .multiple(true)
99                          .takes_value(true)
100                          .value_name("LABEL")
101                          .number_of_values(1)
102                          .help("Recipient to encrypt for \
103                                 (can be given multiple times)"))
104                     .arg(Arg::with_name("recipient-key-file")
105                          .long("recipient-key-file")
106                          .multiple(true)
107                          .takes_value(true)
108                          .value_name("CERT-FILE")
109                          .number_of_values(1)
110                          .help("Recipient to encrypt for, given as a file \
111                                 (can be given multiple times)"))
112                     .arg(Arg::with_name("signer-key-file")
113                          .long("signer-key-file")
114                          .multiple(true)
115                          .takes_value(true)
116                          .value_name("TSK-FILE")
117                          .number_of_values(1)
118                          .help("Secret key to sign with, given as a file \
119                                 (can be given multiple times)"))
120                     .arg(Arg::with_name("symmetric")
121                          .long("symmetric")
122                          .short("s")
123                          .multiple(true)
124                          .help("Encrypt with a password \
125                                 (can be given multiple times)"))
126                     .arg(Arg::with_name("mode").value_name("MODE")
127                          .long("mode")
128                          .possible_values(&["transport", "rest", "all"])
129                          .default_value("all")
130                          .help("Selects what kind of keys are considered for \
131                                 encryption.  Transport select subkeys marked \
132                                 as suitable for transport encryption, rest \
133                                 selects those for encrypting data at rest, \
134                                 and all selects all encryption-capable \
135                                 subkeys"))
136                     .arg(Arg::with_name("compression")
137                          .value_name("KIND")
138                          .long("compression")
139                          .possible_values(&["none", "pad", "zip", "zlib",
140                                             "bzip2"])
141                          .default_value("pad")
142                          .help("Selects compression scheme to use"))
143                     .arg(Arg::with_name("time").value_name("TIME")
144                          .long("time")
145                          .short("t")
146                          .help("Chooses keys valid at the specified time and \
147                                 sets the signature's creation time"))
148         )
149 
150         .subcommand(SubCommand::with_name("sign")
151                     .display_order(25)
152                     .about("Signs a message")
153                     .arg(Arg::with_name("input").value_name("FILE")
154                          .help("Sets the input file to use"))
155                     .arg(Arg::with_name("output").value_name("FILE")
156                          .long("output")
157                          .short("o")
158                          .help("Sets the output file to use"))
159                     .arg(Arg::with_name("binary")
160                          .long("binary")
161                          .short("B")
162                          .help("Don't ASCII-armor encode the OpenPGP data"))
163                     .arg(Arg::with_name("detached")
164                          .long("detached")
165                          .help("Create a detached signature"))
166                     .arg(Arg::with_name("append")
167                          .long("append")
168                          .short("a")
169                          .conflicts_with("notarize")
170                          .help("Append signature to existing signature"))
171                     .arg(Arg::with_name("notarize")
172                          .long("notarize")
173                          .short("n")
174                          .conflicts_with("append")
175                          .help("Signs a message and all existing signatures"))
176                     .arg(Arg::with_name("secret-key-file")
177                          .long("secret-key-file")
178                          .multiple(true)
179                          .takes_value(true)
180                          .value_name("TSK-FILE")
181                          .number_of_values(1)
182                          .help("Secret key to sign with, given as a file \
183                                 (can be given multiple times)"))
184                     .arg(Arg::with_name("time").value_name("TIME")
185                          .long("time")
186                          .short("t")
187                          .help("Chooses keys valid at the specified time and \
188                                 sets the signature's creation time")))
189         .subcommand(SubCommand::with_name("verify")
190                     .display_order(26)
191                     .about("Verifies a message")
192                     .arg(Arg::with_name("input").value_name("FILE")
193                          .help("Sets the input file to use"))
194                     .arg(Arg::with_name("output").value_name("FILE")
195                          .long("output")
196                          .short("o")
197                          .help("Sets the output file to use"))
198                     .arg(Arg::with_name("detached")
199                          .long("detached")
200                          .takes_value(true)
201                          .value_name("SIG-FILE")
202                          .help("Verifies a detached signature"))
203                     .arg(Arg::with_name("signatures").value_name("N")
204                          .help("The number of valid signatures required.  \
205                                 Default: 0")
206                          .long("signatures")
207                          .short("n")
208                          .takes_value(true))
209                     .arg(Arg::with_name("sender-cert-file")
210                          .long("sender-cert-file")
211                          .multiple(true)
212                          .takes_value(true)
213                          .value_name("CERT-FILE")
214                          .number_of_values(1)
215                          .help("The sender's certificate verify signatures \
216                                 with, given as a file \
217                                 (can be given multiple times)")))
218         .subcommand(SubCommand::with_name("enarmor")
219                     .about("Applies ASCII Armor to a file")
220                     .arg(Arg::with_name("input").value_name("FILE")
221                          .help("Sets the input file to use"))
222                     .arg(Arg::with_name("output").value_name("FILE")
223                          .long("output")
224                          .short("o")
225                          .help("Sets the output file to use"))
226                     .arg(Arg::with_name("kind")
227                          .value_name("KIND")
228                          .long("kind")
229                          .possible_values(&["message", "publickey", "secretkey",
230                                             "signature", "file"])
231                          .default_value("file")
232                          .help("Selects the kind of header line to produce")))
233 
234         .subcommand(SubCommand::with_name("dearmor")
235                     .about("Removes ASCII Armor from a file")
236                     .arg(Arg::with_name("input").value_name("FILE")
237                          .help("Sets the input file to use"))
238                     .arg(Arg::with_name("output").value_name("FILE")
239                          .long("output")
240                          .short("o")
241                          .help("Sets the output file to use")))
242         .subcommand(SubCommand::with_name("autocrypt")
243                     .about("Autocrypt support")
244                     .setting(AppSettings::SubcommandRequiredElseHelp)
245                     .subcommand(SubCommand::with_name("decode")
246                                 .about("Converts Autocrypt-encoded keys to \
247                                         OpenPGP Certificates")
248                                 .arg(Arg::with_name("input").value_name("FILE")
249                                      .help("Sets the input file to use"))
250                                 .arg(Arg::with_name("output").value_name("FILE")
251                                      .long("output")
252                                      .short("o")
253                                      .help("Sets the output file to use")))
254                     .subcommand(SubCommand::with_name("encode-sender")
255                                 .about("Encodes the sender's OpenPGP \
256                                         Certificates into \
257                                         an Autocrypt header")
258                                 .arg(Arg::with_name("input").value_name("FILE")
259                                      .help("Sets the input file to use"))
260                                 .arg(Arg::with_name("output").value_name("FILE")
261                                      .long("output")
262                                      .short("o")
263                                      .help("Sets the output file to use"))
264                                 .arg(Arg::with_name("address")
265                                      .long("address")
266                                      .takes_value(true)
267                                      .help("Select userid to use.  \
268                                             [default: primary userid]"))
269                                 .arg(Arg::with_name("prefer-encrypt")
270                                      .long("prefer-encrypt")
271                                      .possible_values(&["nopreference",
272                                                         "mutual"])
273                                      .default_value("nopreference")
274                                      .help("Sets the prefer-encrypt \
275                                             attribute"))))
276         .subcommand(SubCommand::with_name("inspect")
277                     .about("Inspects a sequence of OpenPGP packets")
278                     .arg(Arg::with_name("input").value_name("FILE")
279                          .help("Sets the input file to use"))
280                     .arg(Arg::with_name("keygrips")
281                          .long("keygrips")
282                          .help("Print keygrips of keys and subkeys"))
283                     .arg(Arg::with_name("certifications")
284                          .long("certifications")
285                          .help("Print third-party certifications")))
286 
287         .subcommand(SubCommand::with_name("keyserver")
288                     .display_order(40)
289                     .about("Interacts with keyservers")
290                     .setting(AppSettings::SubcommandRequiredElseHelp)
291                     .arg(Arg::with_name("server").value_name("URI")
292                          .long("server")
293                          .short("s")
294                          .help("Sets the keyserver to use"))
295                     .subcommand(SubCommand::with_name("get")
296                                 .about("Retrieves a key")
297                                 .arg(Arg::with_name("output").value_name("FILE")
298                                      .long("output")
299                                      .short("o")
300                                      .help("Sets the output file to use"))
301                                 .arg(Arg::with_name("binary")
302                                      .long("binary")
303                                      .short("B")
304                                      .help("Don't ASCII-armor encode the OpenPGP data"))
305                                 .arg(Arg::with_name("keyid").value_name("KEYID")
306                                      .required(true)
307                                      .help("ID of the key to retrieve")))
308                     .subcommand(SubCommand::with_name("send")
309                                 .about("Sends a key")
310                                 .arg(Arg::with_name("input").value_name("FILE")
311                                      .help("Sets the input file to use"))))
312         .subcommand(SubCommand::with_name("mapping")
313                     .display_order(30)
314                     .about("Interacts with key mappings")
315                     .setting(AppSettings::SubcommandRequiredElseHelp)
316                     .subcommand(SubCommand::with_name("list")
317                                 .about("Lists keys in the mapping"))
318                     .subcommand(SubCommand::with_name("add")
319                                 .about("Add a key identified by fingerprint")
320                                 .arg(Arg::with_name("label").value_name("LABEL")
321                                      .required(true)
322                                      .help("Label to use"))
323                                 .arg(Arg::with_name("fingerprint").value_name("FINGERPRINT")
324                                      .required(true)
325                                      .help("Key to add")))
326                     .subcommand(SubCommand::with_name("import")
327                                 .about("Imports a key")
328                                 .arg(Arg::with_name("label").value_name("LABEL")
329                                      .required(true)
330                                      .help("Label to use"))
331                                 .arg(Arg::with_name("input").value_name("FILE")
332                                      .help("Sets the input file to use")))
333                     .subcommand(SubCommand::with_name("export")
334                                 .about("Exports a key")
335                                 .arg(Arg::with_name("label").value_name("LABEL")
336                                      .required(true)
337                                      .help("Label to use"))
338                                 .arg(Arg::with_name("output").value_name("FILE")
339                                      .long("output")
340                                      .short("o")
341                                      .help("Sets the output file to use"))
342                                 .arg(Arg::with_name("binary")
343                                      .long("binary")
344                                      .short("B")
345                                      .help("Don't ASCII-armor encode the OpenPGP data")))
346                     .subcommand(SubCommand::with_name("delete")
347                                 .about("Deletes bindings or mappings")
348                                 .arg(Arg::with_name("the-mapping")
349                                      .long("the-mapping")
350                                      .help("Delete the selected mapping (change with --mapping)"))
351                                 .arg(Arg::with_name("label")
352                                      .value_name("LABEL")
353                                      .help("Delete binding with this label")))
354                     .subcommand(SubCommand::with_name("stats")
355                                 .about("Get stats for the given label")
356                                 .arg(Arg::with_name("label").value_name("LABEL")
357                                      .required(true)
358                                      .help("Label to use")))
359                     .subcommand(SubCommand::with_name("log")
360                                 .about("Lists the keystore log")
361                                 .arg(Arg::with_name("label")
362                                      .value_name("LABEL")
363                                      .help("List messages related to this label"))))
364         .subcommand(SubCommand::with_name("list")
365                     .about("Lists key mappings and known keys")
366                     .setting(AppSettings::SubcommandRequiredElseHelp)
367                     .subcommand(SubCommand::with_name("mappings")
368                                 .about("Lists key mappings")
369                                 .arg(Arg::with_name("prefix").value_name("PREFIX")
370                                      .help("List only mappings with the given realm prefix")))
371                     .subcommand(SubCommand::with_name("bindings")
372                                 .about("Lists all bindings in all key mappings")
373                                 .arg(Arg::with_name("prefix").value_name("PREFIX")
374                                      .help("List only bindings from mappings with the given realm prefix")))
375                     .subcommand(SubCommand::with_name("keys")
376                                 .about("Lists all keys in the common key pool"))
377                     .subcommand(SubCommand::with_name("log")
378                                 .about("Lists the server log")))
379         .subcommand(
380             SubCommand::with_name("key")
381                 .about("Manipulates keys")
382                 .setting(AppSettings::SubcommandRequiredElseHelp)
383                 .subcommand(
384                     SubCommand::with_name("generate")
385                         .about("Generates a new key")
386                         .arg(Arg::with_name("userid")
387                              .value_name("EMAIL")
388                              .long("userid")
389                              .short("u")
390                              .multiple(true)
391                              .number_of_values(1)
392                              .takes_value(true)
393                              .help("Add userid to the key \
394                                     (can be given multiple times)"))
395                         .arg(Arg::with_name("cipher-suite")
396                              .value_name("CIPHER-SUITE")
397                              .long("cipher-suite")
398                              .short("c")
399                              .possible_values(&["rsa3k", "rsa4k", "cv25519"])
400                              .default_value("cv25519")
401                              .help("Cryptographic algorithms used for the key."))
402                         .arg(Arg::with_name("with-password")
403                              .long("with-password")
404                              .help("Prompt for a password to protect the \
405                                     generated key with."))
406 
407                         .group(ArgGroup::with_name("expiration-group")
408                                .args(&["expires", "expires-in"]))
409 
410                         .arg(Arg::with_name("expires")
411                              .value_name("TIME")
412                              .long("expires")
413                              .help("Absolute time When the key should expire, \
414                                     or 'never'."))
415                         .arg(Arg::with_name("expires-in")
416                              .value_name("DURATION")
417                              .long("expires-in")
418                              // Catch negative numbers.
419                              .allow_hyphen_values(true)
420                              .help("Relative time when the key should expire.  \
421                                     Either 'N[ymwd]', for N years, months, \
422                                     weeks, or days, or 'never'."))
423 
424                         .group(ArgGroup::with_name("cap-sign")
425                                .args(&["can-sign", "cannot-sign"]))
426                         .arg(Arg::with_name("can-sign")
427                              .long("can-sign")
428                              .help("The key has a signing-capable subkey \
429                                     (default)"))
430                         .arg(Arg::with_name("cannot-sign")
431                              .long("cannot-sign")
432                              .help("The key will not be able to sign data"))
433 
434                         .group(ArgGroup::with_name("cap-encrypt")
435                                .args(&["can-encrypt", "cannot-encrypt"]))
436                         .arg(Arg::with_name("can-encrypt").value_name("PURPOSE")
437                              .long("can-encrypt")
438                              .possible_values(&["transport", "storage",
439                                                 "universal"])
440                              .help("The key has an encryption-capable subkey \
441                                     (default: universal)"))
442                         .arg(Arg::with_name("cannot-encrypt")
443                              .long("cannot-encrypt")
444                              .help("The key will not be able to encrypt data"))
445 
446                         .arg(Arg::with_name("export").value_name("OUTFILE")
447                              .long("export")
448                              .short("e")
449                              .help("Exports the key instead of saving it in \
450                                     the store")
451                              .required(true))
452                         .arg(Arg::with_name("rev-cert").value_name("FILE or -")
453                              .long("rev-cert")
454                              .required_if("export", "-")
455                              .help("Sets the output file for the revocation \
456                                     certificate. Default is <OUTFILE>.rev, \
457                                     mandatory if OUTFILE is '-'."))))
458 
459         .subcommand(SubCommand::with_name("packet")
460                     .about("OpenPGP Packet manipulation")
461                     .setting(AppSettings::SubcommandRequiredElseHelp)
462                     .subcommand(SubCommand::with_name("dump")
463                                 .about("Lists OpenPGP packets")
464                                 .arg(Arg::with_name("input").value_name("FILE")
465                                      .help("Sets the input file to use"))
466                                 .arg(Arg::with_name("output").value_name("FILE")
467                                      .long("output")
468                                      .short("o")
469                                      .help("Sets the output file to use"))
470                                 .arg(Arg::with_name("session-key")
471                                      .long("session-key")
472                                      .takes_value(true)
473                                      .value_name("SESSION-KEY")
474                                      .help("Session key to decrypt encryption \
475                                             containers"))
476                                 .arg(Arg::with_name("mpis")
477                                      .long("mpis")
478                                      .help("Print MPIs"))
479                                 .arg(Arg::with_name("hex")
480                                      .long("hex")
481                                      .short("x")
482                                      .help("Print a hexdump")))
483 
484                     .subcommand(SubCommand::with_name("decrypt")
485                                 .display_order(10)
486                                 .about("Decrypts an OpenPGP message, dumping \
487                                         the content of the encryption \
488                                         container without further processing")
489                                 .arg(Arg::with_name("input").value_name("FILE")
490                                      .help("Sets the input file to use"))
491                                 .arg(Arg::with_name("output").value_name("FILE")
492                                      .long("output")
493                                      .short("o")
494                                      .help("Sets the output file to use"))
495                                 .arg(Arg::with_name("binary")
496                                      .long("binary")
497                                      .short("B")
498                                      .help("Don't ASCII-armor encode the \
499                                             OpenPGP data"))
500                                 .arg(Arg::with_name("secret-key-file")
501                                      .long("secret-key-file")
502                                      .multiple(true)
503                                      .takes_value(true)
504                                      .value_name("TSK-FILE")
505                                      .number_of_values(1)
506                                      .help("Secret key to decrypt with, given \
507                                             as a file \
508                                             (can be given multiple times)"))
509                                 .arg(Arg::with_name("dump-session-key")
510                                      .long("dump-session-key")
511                                      .help("Prints the session key to stderr")))
512 
513                     .subcommand(SubCommand::with_name("split")
514                                 .about("Splits a message into OpenPGP packets")
515                                 .arg(Arg::with_name("input").value_name("FILE")
516                                      .help("Sets the input file to use"))
517                                 .arg(Arg::with_name("prefix").value_name("FILE")
518                                      .long("prefix")
519                                      .short("p")
520                                      .help("Sets the prefix to use for output files \
521                                             (defaults to the input filename with a dash, \
522                                             or 'output')")))
523                     .subcommand(SubCommand::with_name("join")
524                                 .about("Joins OpenPGP packets split across \
525                                         files")
526                                 .arg(Arg::with_name("input").value_name("FILE")
527                                      .multiple(true)
528                                      .help("Sets the input files to use"))
529                                 .arg(Arg::with_name("output").value_name("FILE")
530                                      .long("output")
531                                      .short("o")
532                                      .help("Sets the output file to use"))
533                                 .arg(Arg::with_name("kind")
534                                      .value_name("KIND")
535                                      .long("kind")
536                                      .possible_values(&["message", "publickey",
537                                                         "secretkey",
538                                                         "signature", "file"])
539                                      .default_value("file")
540                                      .help("Selects the kind of header line to \
541                                             produce"))
542                                 .arg(Arg::with_name("binary")
543                                      .long("binary")
544                                      .short("B")
545                                      .help("Don't ASCII-armor encode the \
546                                             OpenPGP data"))))
547 
548         .subcommand(SubCommand::with_name("wkd")
549                     .about("Interacts with Web Key Directories")
550                     .setting(AppSettings::SubcommandRequiredElseHelp)
551                     .subcommand(SubCommand::with_name("url")
552                                 .about("Prints the Web Key Directory URL of \
553                                         an email address.")
554                                 .arg(Arg::with_name("input")
555                                     .value_name("EMAIL_ADDRESS")
556                                     .required(true)
557                                     .help("The email address from which to \
558                                             obtain the WKD URI.")))
559                     .subcommand(SubCommand::with_name("get")
560                                 .about("Writes to the standard output the \
561                                         Cert retrieved \
562                                         from a Web Key Directory, given an \
563                                         email address")
564                                 .arg(Arg::with_name("input")
565                                     .value_name("EMAIL_ADDRESS")
566                                     .required(true)
567                                     .help("The email address from which to \
568                                             obtain the Cert from a WKD."))
569                                 .arg(Arg::with_name("binary")
570                                     .long("binary")
571                                     .short("B")
572                                     .help("Don't ASCII-armor encode the OpenPGP data")))
573                     .subcommand(SubCommand::with_name("generate")
574                                 .about("Generates a Web Key Directory \
575                                         for the given domain and keys.  \
576                                         If the WKD exists, the new \
577                                         keys will be inserted and it \
578                                         is updated and existing ones \
579                                         will be updated.")
580                                 .arg(Arg::with_name("base_directory")
581                                      .value_name("WEB-ROOT")
582                                      .required(true)
583                                      .help("The location to write the WKD to. \
584                                             This must be the directory the \
585                                             webserver is serving the \
586                                             '.well-known' directory from."))
587                                 .arg(Arg::with_name("domain")
588                                     .value_name("DOMAIN")
589                                     .help("The domain for the WKD.")
590                                     .required(true))
591                                 .arg(Arg::with_name("input")
592                                     .value_name("KEYRING")
593                                     .help("The keyring file with the keys to add to the WKD."))
594                                 .arg(Arg::with_name("direct_method")
595                                      .long("direct_method")
596                                      .short("d")
597                                      .help("Use the direct method. \
598                                             [default: advanced method]"))
599                     )
600         )
601 }
602