pashage

Yet Another Opinionated Re-engineering of the Unix Password Store
git clone https://git.instinctive.eu/pashage.git
Log | Files | Refs | README | LICENSE

README.md (24129B)


      1 [![Casual Maintenance Intended](https://casuallymaintained.tech/badge.svg)](https://casuallymaintained.tech/)
      2 
      3 # pashage
      4 
      5 Yet Another Opinionated Re-engineering of the Unix Password Store
      6 
      7 Core objectives:
      8 
      9 - same interface and similar feature set
     10   as [pass](https://www.passwordstore.org/)
     11 - simplicity, understandability, and hackability, from using POSIX shell,
     12   like [pash](https://github.com/dylanaraps/pash)
     13 - [age](https://age-encryption.org) as encryption backend,
     14   like [passage](https://github.com/FiloSottile/passage)
     15 - validation using [shellcheck](https://www.shellcheck.net/)
     16   and [shellspec tests](https://shellspec.info/)
     17 
     18 Portability is not a core objective, but a nice side-effect of using
     19 basic POSIX shell, and it is embraced when possible.
     20 
     21 Security is not branded as a core objective, because the author does not
     22 have the clout to declare anything secure, and you should probably not
     23 trust random READMEs anyway.
     24 However the simplicity should help you assess whether this password store
     25 is a worthwhile trade-off for _your_ threat model.
     26 
     27 For the reference, the author has views [similar to those of Filippo
     28 Valsorda](https://words.filippo.io/dispatches/passage/) and considers
     29 the password store shell script to be about as critical as the rest
     30 of her computer, and relies mostly on age to provide secure encryption
     31 at rest and on a [YubiKey](https://www.yubico.com/) to gatekeep decryption.
     32 
     33 ## Licencing
     34 
     35 This project was written from scratch, and every character of the script
     36 was typed with my fingers.
     37 However I looked deeply into pass, passage, and pash code bases.
     38 I don't know whether that's enough to make it a derivative work covered
     39 by the GPL, so to be on the safe side I'm using GPL v2+ too.
     40 
     41 ## Differences with `pass`
     42 
     43 ### Behavior Differences
     44 
     45 - Not using a terminal does not imply `--force`, instead `pashage` asks for
     46 a confirming `y` on a standard input line.
     47 
     48 - When copying a secret to the clipboard, the script keeps running while
     49 waiting for the automatic clearing. This provides a user-facing cue that
     50 the secret may still be the clipboard and allows to clear the clipboard
     51 earlier.
     52 
     53 - The commands `copy`, `edit`, `insert`, `list`, `move`, and `show`
     54 accept multiple arguments to operate on many secrets at once.
     55 
     56 - The commands `copy` and `move` also operate on unencrypted files in the
     57 password store.
     58 
     59 - The `edit` command does not warn a about using `/tmp` rather than
     60 `/dev/shm`, because the warning does not seem actionable and quickly
     61 becomes ignored noise.
     62 
     63 - The `edit` command uses `$VISUAL` rather than `$EDITOR` when it set and
     64 the terminal is not dumb.
     65 
     66 - The `find` command search-pattern is a regular expression rather than
     67 a glob.
     68 
     69 - The `find` command matches against the secret names without
     70 extension (`.age` or `.gpg`).
     71 
     72 - The `init` command is redesigned to accommodate `age` backend.
     73 I didn't really understand the original `init` command, so I'm not sure
     74 how different it is; but now it installs `.age-recipients` and re-encrypts.
     75 
     76 - The `insert` command makes the user try again when entering mismatching
     77 passwords.
     78 
     79 ### New Features and Extensions
     80 
     81 - The commands `copy` and `move` have new flags to control re-encryption
     82 (always, never, ask for each file).
     83 
     84 - The `find` and `list` commands have a new flag to output a
     85 machine-readable list of entries (e.g. for completion or wrappers).
     86 
     87 - The `generate` command has a new command-line argument to specify
     88 explicitly the character set.
     89 
     90 - The `generate` command optionally asks for confirmation before storing
     91 the generated secret (e.g. for iterative attempts against stupid password
     92 rules).
     93 
     94 - The `generate` command optionally asks for extra lines to append after
     95 the generated secret (e.g. for username, login page, or others comments).
     96 
     97 - The `init` command has new flags to control re-encryption (never or
     98 ask for each file).
     99 
    100 - The new `gitconfig` command configures an existing store repository to
    101 decrypt before `diff`.
    102 
    103 - The new `random` command leverages password generation without touching
    104 the password store.
    105 
    106 - The new `reencrypt` command re-encrypts secrets in-place.
    107 
    108 ## Roadmap
    109 
    110 The following features are currently under consideration:
    111 
    112 - v1.0.0:
    113     + completion for various shells
    114     + better logic for recursivity in re-encryption
    115 - v1.1.0:
    116     + partial display of secrets on standard output
    117     + successive clipboard copy of several lines from a single decryption
    118 (e.g. username then password)
    119 - maybe/later:
    120     + rewriting of git history to purge old cyphertexts
    121     + OTP support
    122     + extension support
    123 
    124 ## Dependencies
    125 
    126 Required dependencies:
    127 
    128 - POSIX-compliant shell, including POSIX-compliant utilities `[`, `basename`,
    129 `cat`, `cp`, `dd`, `diff`, `dirname`, `echo`, `find`, `grep`, `head`, `mkdir`,
    130 `mktemp`, `mv`, `printf`, `rm`, `stty`, `tail`, `tr`, and `true`;
    131 - [age](https://age-encryption.org/) encryption tool.
    132 
    133 Optional dependencies:
    134 
    135 - [feh](https://feh.finalrewind.org/)
    136 to display QR-codes graphically
    137 - [git](https://git-scm.com/)
    138 to track storage revision and replicate it
    139 - [GnuPG](https://gnupg.org/)
    140 to display GnuPG-encrypted password-store secrets
    141 - [GraphicsMagick](http://www.graphicsmagick.org/)
    142 to display QR-codes graphically
    143 - [ImageMagick](https://imagemagick.org/)
    144 to display QR-codes graphically
    145 - [openssl](https://www.openssl.org/)
    146 to encode and decode base-64 when interacting with clipboard
    147 - [qrencode](https://github.com/fukuchi/libqrencode)
    148 to generate QR-codes
    149 - [wl-clipboard](https://github.com/bugaevc/wl-clipboard)
    150 to copy and paste on Wayland
    151 - [xclip](https://github.com/astrand/xclip)
    152 to copy and paste on X11
    153 
    154 ## Manual
    155 
    156 **pashage** is a _password manager_, which means it manages a database of
    157 encrypted secrets, including encrypting externally-provided new secrets,
    158 generating and encrypting random strings, and decrypting and displaying
    159 stored secrets.
    160 
    161 It aims to be simple and composable, but its reliance on Unix philosophy
    162 and customs might make steep learning curve for users outside of this
    163 culture.
    164 
    165 It is used through a shell command, denoted as `pashage` in this document,
    166 immediately followed by a subcommand and its arguments. When no subcommand
    167 is specified, _list_ or _show_ is implicitly assumed.
    168 
    169 The database is optionally versioned using [git](https://git-scm.com/)
    170 to help with history audit and synchronization. It should be noted that
    171 this prevents re-encryption from erasing old cyphertext, leaving the secret
    172 vulnerable to compromised encryption keys.
    173 
    174 The cryptography is done by [age](https://age-encryption.org/) external
    175 command. It decrypts using the _identity_ file given in the environment,
    176 and crypts using a list of _recipients_ per subfolder, defaulting to the
    177 parent _recipient_ list or the _identity_.
    178 
    179 ## Command Reference
    180 
    181 Here is an alphabetical list of all subcommands and aliases:
    182 
    183 - `--help`: alias for _help_
    184 - `--version`: alias for _version_
    185 - `-h`: alias for _help_
    186 - `copy`
    187 - `cp`: alias for _copy_
    188 - `delete`
    189 - `edit`
    190 - `find`
    191 - `gen`: alias for _generate_
    192 - `generate`
    193 - `git`
    194 - `gitconfig`
    195 - `grep`
    196 - `help`
    197 - `init`
    198 - `insert`
    199 - `list`
    200 - `ls`: alias for _list_
    201 - `move`
    202 - `mv`: alias for _move_
    203 - `random`
    204 - `re-encrypt`: alias for _reencrypt_
    205 - `reencrypt`
    206 - `remove`: alias for _delete_
    207 - `rm`: alias for _delete_
    208 - `show`
    209 - `version`
    210 
    211 ### copy
    212 
    213 Syntax:
    214 
    215 ```
    216 pashage copy [--reencrypt,-e | --interactive,-i | --keep,-k ]
    217              [--force,-f] old-path ... new-path
    218 ```
    219 
    220 This subcommand copies secrets and recursively copies subfolders,
    221 using the same positional argument scheme as `cp(1)`.
    222 By default it asks before overwriting an existing secret and it re-encrypts
    223 the secret when the destination has a different _recipient_ list.
    224 
    225 Flags:
    226 - `-e` or `--reencrypt`: always re-encrypt secrets
    227 - `-f` or `--force`: overwrite existing secrets without asking
    228 - `-i` or `--interactive`: asks whether to re-encrypt or not for each secret
    229 - `-k` or `--keep`: never re-encrypt secrets
    230 
    231 Environment:
    232 - `PASHAGE_AGE`: external command to use instead of `age`
    233 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    234 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    235   `~/.passage/identities`
    236 - `PASSAGE_AGE`: external command to use instead of `age` when
    237   `PASHAGE_AGE` is unset
    238 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    239   when `PASHAGE_DIR` is unset
    240 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    241   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    242 - `PASSWORD_STORE_DIR`: database directory to use instead of
    243   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    244 
    245 ### delete
    246 
    247 Syntax:
    248 
    249 ```
    250 pashage delete [--recursive,-r] [--force,-f] pass-name ...
    251 ```
    252 
    253 This subcommand deletes secrets from the database. By default it skips
    254 subfolders and asks for confirmation for each secret.
    255 
    256 Flags:
    257 - `-f` or `--force`: delete without asking for confirmation
    258 - `-r` or `--recursive`: recursively delete all secrets in given subfolders
    259 
    260 Environment:
    261 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    262 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    263   when `PASHAGE_DIR` is unset
    264 - `PASSWORD_STORE_DIR`: database directory to use instead of
    265   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    266 
    267 ### edit
    268 
    269 Syntax:
    270 
    271 ```
    272 pashage edit pass-name ...
    273 ```
    274 
    275 This subcommand starts an interactive editor to update the secrets.
    276 
    277 Environment:
    278 - `EDITOR`: editor command to use instead of `vi` when `VISUAL` is not set
    279 - `PASHAGE_AGE`: external command to use instead of `age`
    280 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    281 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    282   `~/.passage/identities`
    283 - `PASSAGE_AGE`: external command to use instead of `age` when
    284   `PASHAGE_AGE` is unset
    285 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    286   when `PASHAGE_DIR` is unset
    287 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    288   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    289 - `PASSWORD_STORE_DIR`: database directory to use instead of
    290   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    291 - `TMPDIR`: temporary directory for the decrypted file to use instead of
    292   `/tmp` when `/dev/shm` is not available
    293 - `VISUAL`: editor command to use instead of `vi`
    294 
    295 ### find
    296 
    297 Syntax:
    298 
    299 ```
    300 pashage find [--raw,-r] [GREP_OPTIONS] regex
    301 ```
    302 
    303 This subcommand lists as a tree the secrets whose name match the given
    304 regular expression, using the corresponding `grep(1)` options.
    305 
    306 Flags:
    307 - `-r` or `--raw`: display the results as a raw list of secrets,
    308   rather than a tree
    309 
    310 Environment:
    311 - `CLICOLOR`: when set to a non-empty value, use ANSI escape sequences to
    312   color the output
    313 - `LC_CTYPE`: when it contains `UTF`, the tree is displayed using Unicode
    314   graphic characters instead of ASCII
    315 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    316 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    317   when `PASHAGE_DIR` is unset
    318 - `PASSWORD_STORE_DIR`: database directory to use instead of
    319   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    320 
    321 ### generate
    322 
    323 Syntax:
    324 
    325 ```
    326 pashage generate [--no-symbols,-n] [--clip,-c | --qrcode,-q]
    327                  [--in-place,-i | --force,-f] [--multiline,-m]
    328                  [--try,-t] pass-name [pass-length [character-set]]
    329 ```
    330 
    331 This subcommand generates a new secret from `/dev/urandom`, stores it in
    332 the database, and by default displays it on the standard output and asks
    333 for confirmation before overwriting an existing secret.
    334 
    335 Flags:
    336 - `-c` or `--clip`: paste the secret into the clipboard instead of using
    337   the standard output
    338 - `-f` or `--force`: replace existing secrets without asking
    339 - `-i` or `--in-place`: when the secret already exists, replace only its
    340   first line and re-use the following lines
    341 - `-m` or `--multiline`: read lines from standard input to append after the
    342   generated data into the secret file
    343 - `-n` or `--no-symbols`: generate a secret using only alphanumeric
    344   characters
    345 - `-q` or `--qrcode`: display the secret as a QR-code instead of using the
    346   standard output
    347 - `-t` or `--try`: display the secret and ask for confirmation before
    348   storing it into the database
    349 
    350 Environment:
    351 - `CLICOLOR`: when set to a non-empty value, use ANSI escape sequences to
    352   color the output
    353 - `PASHAGE_AGE`: external command to use instead of `age`
    354 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    355 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    356   `~/.passage/identities`
    357 - `PASSAGE_AGE`: external command to use instead of `age` when
    358   `PASHAGE_AGE` is unset
    359 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    360   when `PASHAGE_DIR` is unset
    361 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    362   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    363 - `PASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS`: default character set to use
    364   with `tr(1)` when `-n` is specified, instead of `[:alnum:]`
    365 - `PASSWORD_STORE_CHARACTER_SET`: default character set to use with `tr(1)`
    366   when `-n` is not specified, instead of `[:punct:][:alnum:]`
    367 - `PASSWORD_STORE_CLIP_TIME`: number of second before clearing the
    368   clipboard when `-c` is used, instead of 45
    369 - `PASSWORD_STORE_DIR`: database directory to use instead of
    370   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    371 - `PASSWORD_STORE_GENERATED_LENGTH`: number of characters in the generated
    372   secret when not explicitly given, instead of 25
    373 - `PASSWORD_STORE_X_SELECTION`: selection to use when `-c` and `xclip` are
    374   used, instead of `clipboard`
    375 
    376 ### git
    377 
    378 Syntax:
    379 
    380 ```
    381 pashage git git-command-args ...
    382 ```
    383 
    384 This subcommand invokes `git` in the database repository.
    385 Only `git init` and `git clone` are accepted when there is no underlying
    386 repository.
    387 
    388 Environment:
    389 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    390 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    391   when `PASHAGE_DIR` is unset
    392 - `PASSWORD_STORE_DIR`: database directory to use instead of
    393   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    394 
    395 ### gitconfig
    396 
    397 Syntax:
    398 
    399 ```
    400 pashage gitconfig
    401 ```
    402 
    403 This subcommand configures the underlying repository to automatically
    404 decrypt secrets to display differences.
    405 
    406 Environment:
    407 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    408 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    409   when `PASHAGE_DIR` is unset
    410 - `PASSWORD_STORE_DIR`: database directory to use instead of
    411   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    412 
    413 ### grep
    414 
    415 Syntax:
    416 
    417 ```
    418 pashage grep [GREP_OPTIONS] search-regex
    419 ```
    420 
    421 This subcommand successively decrypts all the secrets in the store and
    422 filter them through `grep(1)` using the given options, and outputs all the
    423 matching lines and the corresponding secret.
    424 
    425 Environment:
    426 - `CLICOLOR`: when set to a non-empty value, use ANSI escape sequences to
    427   color the output
    428 - `PASHAGE_AGE`: external command to use instead of `age`
    429 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    430 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    431   `~/.passage/identities`
    432 - `PASSAGE_AGE`: external command to use instead of `age` when
    433   `PASHAGE_AGE` is unset
    434 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    435   when `PASHAGE_DIR` is unset
    436 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    437   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    438 - `PASSWORD_STORE_DIR`: database directory to use instead of
    439   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    440 
    441 ### help
    442 
    443 Syntax:
    444 
    445 ```
    446 pashage help
    447 ```
    448 
    449 This subcommand displays on the standard output the version and help text,
    450 including all subcommands and flags and a brief description.
    451 
    452 This subcommand is not affected by the environment.
    453 
    454 ### init
    455 
    456 Syntax:
    457 
    458 ```
    459 pashage init [--interactive,-i | --keep,-k ]
    460              [--path=subfolder,-p subfolder] age-recipient ...
    461 ```
    462 
    463 This subcommand initializes an age _recipient_ list, by default of the root
    464 of the password store, and re-encrypts all the affected secrets.
    465 When the _recipient_ list is a single empty string, the _recipient_ list is
    466 instead removed, falling back to a parent _recipient_ list or ultimately to
    467 the age _identity_.
    468 
    469 Flags:
    470 - `-i` or `--interactive`: ask for each secret whether to re-encrypt it
    471   or not
    472 - `-k` or `--keep`: do not re-encrypt any secret
    473 - `-p` or `--path`: operate on the _recipient_ list in the given subfolder
    474   instead of the root of the password store
    475 
    476 Environment:
    477 - `PASHAGE_AGE`: external command to use instead of `age`
    478 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    479 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    480   `~/.passage/identities`
    481 - `PASSAGE_AGE`: external command to use instead of `age` when
    482   `PASHAGE_AGE` is unset
    483 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    484   when `PASHAGE_DIR` is unset
    485 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    486   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    487 - `PASSWORD_STORE_DIR`: database directory to use instead of
    488   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    489 
    490 ### insert
    491 
    492 Syntax:
    493 
    494 ```
    495 pashage insert [--echo,-e | --multiline,-m] [--force,-f] pass-name ...
    496 ```
    497 
    498 This subcommand adds new secrets in the database, using the provided data
    499 from the standard input. By default asks before overwriting an existing
    500 secret, and it reads a single secret line after turning off the console
    501 echo, and reads it a second time for confirmation.
    502 
    503 Flags:
    504 - `-e` or `--echo`: read a single line once without manipulating the
    505   standard input
    506 - `-m` or `--multiline`: read an arbitrary amount of lines from the standard
    507   input, without trying to manipulate the console, until the end of input
    508   or a blank line is entered
    509 - `-f` or `--force`: overwrite an existing secret without asking
    510 
    511 Environment:
    512 - `PASHAGE_AGE`: external command to use instead of `age`
    513 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    514 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    515   `~/.passage/identities`
    516 - `PASSAGE_AGE`: external command to use instead of `age` when
    517   `PASHAGE_AGE` is unset
    518 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    519   when `PASHAGE_DIR` is unset
    520 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    521   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    522 - `PASSWORD_STORE_DIR`: database directory to use instead of
    523   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    524 
    525 ### list
    526 
    527 Syntax:
    528 
    529 ```
    530 pashage [list] [--raw,-r] [subfolder ...]
    531 ```
    532 
    533 This subcommand displays the given subfolders as a tree or a raw list,
    534 or the whole store when no subfolder is specified.
    535 
    536 Note that when a secret is given instead of a subfolder, the _show_ command
    537 will be used instead, without any warning or error.
    538 
    539 Flags:
    540 - `-r` or `--raw`: display the results as a raw list of secrets
    541 
    542 Environment:
    543 - `CLICOLOR`: when set to a non-empty value, use ANSI escape sequences to
    544   color the output
    545 - `LC_CTYPE`: when it contains `UTF`, the tree is displayed using Unicode
    546   graphic characters instead of ASCII
    547 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    548 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    549   when `PASHAGE_DIR` is unset
    550 - `PASSWORD_STORE_DIR`: database directory to use instead of
    551   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    552 
    553 ### move
    554 
    555 Syntax:
    556 
    557 ```
    558 pashage move [--reencrypt,-e | --interactive,-i | --keep,-k ]
    559              [--force,-f] old-path ... new-path
    560 ```
    561 
    562 This subcommand moves or renames secrets and subfolders recursively,
    563 using the same positional argument scheme as `mv(1)`.
    564 By default it asks before overwriting an existing secret and it re-encrypts
    565 the secret when the destination has a different _recipient_ list.
    566 
    567 Flags:
    568 - `-e` or `--reencrypt`: always re-encrypt secrets
    569 - `-f` or `--force`: overwrite existing secrets without asking
    570 - `-i` or `--interactive`: asks whether to re-encrypt or not for each secret
    571 - `-k` or `--keep`: never re-encrypt secrets
    572 
    573 Environment:
    574 - `PASHAGE_AGE`: external command to use instead of `age`
    575 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    576 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    577   `~/.passage/identities`
    578 - `PASSAGE_AGE`: external command to use instead of `age` when
    579   `PASHAGE_AGE` is unset
    580 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    581   when `PASHAGE_DIR` is unset
    582 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    583   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    584 - `PASSWORD_STORE_DIR`: database directory to use instead of
    585   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    586 
    587 ### random
    588 
    589 Syntax:
    590 
    591 ```
    592 pashage random [pass-length [character-set]]
    593 ```
    594 
    595 This subcommand generates a new secret, like the _generate_ subcommand,
    596 then directly displays on the standard output without storing it.
    597 
    598 Environment:
    599 - `PASSWORD_STORE_CHARACTER_SET`: character set to use with `tr(1)` when
    600   `character-set` is not specified, instead of `[:punct:][:alnum:]`
    601 - `PASSWORD_STORE_GENERATED_LENGTH`: number of characters in the generated
    602   secret when not explicitly given, instead of 25
    603 
    604 ### reencrypt
    605 
    606 Syntax:
    607 
    608 ```
    609 pashage reencrypt [--deep,-d] [--interactive,-i] pass-name|subfolder ...
    610 ```
    611 
    612 This subcommand re-encrypts in place the given secrets, and all the secrets
    613 recursively in the given subfolders.
    614 
    615 Flags:
    616 - `-d` or `--deep`: re-encrypt subfolders with their own recipient list
    617 - `-i` or `--interactive`: asks whether to re-encrypt or not for each secret
    618 
    619 Environment:
    620 - `PASHAGE_AGE`: external command to use instead of `age`
    621 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    622 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    623   `~/.passage/identities`
    624 - `PASSAGE_AGE`: external command to use instead of `age` when
    625   `PASHAGE_AGE` is unset
    626 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    627   when `PASHAGE_DIR` is unset
    628 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    629   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    630 - `PASSWORD_STORE_DIR`: database directory to use instead of
    631   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    632 
    633 ### show
    634 
    635 Syntax:
    636 
    637 ```
    638 pashage [show] [--clip[=line-number],-c[line-number] |
    639                 --qrcode[=line-number],-q[line-number]] pass-name ...
    640 ```
    641 
    642 This subcommand decrypts the given secrets and by default displays the
    643 whole text on the standard output.
    644 
    645 Note that when a subfolder is given instead of a secret, the _list_ command
    646 will be used instead, without any warning or error.
    647 
    648 Flags:
    649 - `-c` or `--clip`: paste the given line (by default the first line) of the
    650   secret into the clipboard instead of using the standard output
    651 - `-q` or `--qrcode`: display the given line (by default the first line) of
    652   the secret as a QR-code instead of using the standard output
    653 
    654 Environment:
    655 - `PASHAGE_AGE`: external command to use instead of `age`
    656 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store`
    657 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    658   `~/.passage/identities`
    659 - `PASSAGE_AGE`: external command to use instead of `age` when
    660   `PASHAGE_AGE` is unset
    661 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store`
    662   when `PASHAGE_DIR` is unset
    663 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of
    664   `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset
    665 - `PASSWORD_STORE_DIR`: database directory to use instead of
    666   `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset
    667 
    668 ### version
    669 
    670 Syntax:
    671 
    672 ```
    673 pashage version
    674 ```
    675 
    676 This subcommand displays on the standard output the version and author
    677 list.
    678 
    679 This subcommand is not affected by the environment.