README.md (22891B)
1 [](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 `init` command is redesigned to accommodate `age` backend. 70 I didn't really understand the original `init` command, so I'm not sure 71 how different it is; but now it installs `.age-recipients` and re-encrypts. 72 73 - The `insert` command makes the user try again when entering mismatching 74 passwords. 75 76 ### New Features and Extensions 77 78 - The commands `copy` and `move` have new flags to control re-encryption 79 (always, never, ask for each file). 80 81 - The `find` and `list` commands have a new flag to output a 82 machine-readable list of entries (e.g. for completion or wrappers). 83 84 - The `generate` command has a new command-line argument to specify 85 explicitly the character set. 86 87 - The `generate` command optionally asks for confirmation before storing 88 the generated secret (e.g. for iterative attempts against stupid password 89 rules). 90 91 - The `generate` command optionally asks for extra lines to append after 92 the generated secret (e.g. for username, login page, or others comments). 93 94 - The `init` command has new flags to control re-encryption (never or 95 ask for each file). 96 97 - The new `gitconfig` command configures an existing store repository to 98 decrypt before `diff`. 99 100 - The new `random` command leverages password generation without touching 101 the password store. 102 103 - The new `reencrypt` command re-encrypts secrets in-place. 104 105 ## Roadmap 106 107 The following features are currently under consideration: 108 109 - v1.0.0: 110 + completion for various shells 111 + better logic for recursivity in re-encryption 112 - v1.1.0: 113 + partial display of secrets on standard output 114 + successive clipboard copy of several lines from a single decryption 115 (e.g. username then password) 116 - maybe/later: 117 + rewriting of git history to purge old cyphertexts 118 + OTP support 119 + extension support 120 121 ## Manual 122 123 **pashage** is a _password manager_, which means it manages a database of 124 encrypted secrets, including encrypting externally-provided new secrets, 125 generating and encrypting random strings, and decrypting and displaying 126 stored secrets. 127 128 It aims to be simple and composable, but its reliance on Unix philosophy 129 and customs might make steep learning curve for users outside of this 130 culture. 131 132 It is used through a shell command, denoted as `pashage` in this document, 133 immediately followed by a subcommand and its arguments. When no subcommand 134 is specified, _list_ or _show_ is implicitly assumed. 135 136 The database is optionally versioned using [git](https://git-scm.com/) 137 to help with history audit and synchronization. It should be noted that 138 this prevents re-encryption from erasing old cyphertext, leaving the secret 139 vulnerable to compromised encryption keys. 140 141 The cryptography is done by [age](https://age-encryption.org/) external 142 command. It decrypts using the _identity_ file given in the environment, 143 and crypts using a list of _recipients_ per subfolder, defaulting to the 144 parent _recipient_ list or the _identity_. 145 146 ## Command Reference 147 148 Here is an alphabetical list of all subcommands and aliases: 149 150 - `--help`: alias for _help_ 151 - `--version`: alias for _version_ 152 - `-h`: alias for _help_ 153 - `copy` 154 - `cp`: alias for _copy_ 155 - `delete` 156 - `edit` 157 - `find` 158 - `gen`: alias for _generate_ 159 - `generate` 160 - `git` 161 - `gitconfig` 162 - `grep` 163 - `help` 164 - `init` 165 - `insert` 166 - `list` 167 - `ls`: alias for _list_ 168 - `move` 169 - `mv`: alias for _move_ 170 - `random` 171 - `re-encrypt`: alias for _reencrypt_ 172 - `reencrypt` 173 - `remove`: alias for _delete_ 174 - `rm`: alias for _delete_ 175 - `show` 176 - `version` 177 178 ### copy 179 180 Syntax: 181 182 ``` 183 pashage copy [--reencrypt,-e | --interactive,-i | --keep,-k ] 184 [--force,-f] old-path ... new-path 185 ``` 186 187 This subcommand copies secrets and recursively copies subfolders, 188 using the same positional argument scheme as `cp(1)`. 189 By default it asks before overwriting an existing secret and it re-encrypts 190 the secret when the destination has a different _recipient_ list. 191 192 Flags: 193 - `-e` or `--reencrypt`: always re-encrypt secrets 194 - `-f` or `--force`: overwrite existing secrets without asking 195 - `-i` or `--interactive`: asks whether to re-encrypt or not for each secret 196 - `-k` or `--keep`: never re-encrypt secrets 197 198 Environment: 199 - `PASHAGE_AGE`: external command to use instead of `age` 200 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 201 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 202 `~/.passage/identities` 203 - `PASSAGE_AGE`: external command to use instead of `age` when 204 `PASHAGE_AGE` is unset 205 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 206 when `PASHAGE_DIR` is unset 207 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 208 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 209 - `PASSWORD_STORE_DIR`: database directory to use instead of 210 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 211 212 ### delete 213 214 Syntax: 215 216 ``` 217 pashage delete [--recursive,-r] [--force,-f] pass-name ... 218 ``` 219 220 This subcommand deletes secrets from the database. By default it skips 221 subfolders and asks for confirmation for each secret. 222 223 Flags: 224 - `-f` or `--force`: delete without asking for confirmation 225 - `-r` or `--recursive`: recursively delete all secrets in given subfolders 226 227 Environment: 228 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 229 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 230 when `PASHAGE_DIR` is unset 231 - `PASSWORD_STORE_DIR`: database directory to use instead of 232 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 233 234 ### edit 235 236 Syntax: 237 238 ``` 239 pashage edit pass-name ... 240 ``` 241 242 This subcommand starts an interactive editor to update the secrets. 243 244 Environment: 245 - `EDITOR`: editor command to use instead of `vi` when `VISUAL` is not set 246 - `PASHAGE_AGE`: external command to use instead of `age` 247 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 248 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 249 `~/.passage/identities` 250 - `PASSAGE_AGE`: external command to use instead of `age` when 251 `PASHAGE_AGE` is unset 252 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 253 when `PASHAGE_DIR` is unset 254 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 255 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 256 - `PASSWORD_STORE_DIR`: database directory to use instead of 257 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 258 - `TMPDIR`: temporary directory for the decrypted file to use instead of 259 `/tmp` when `/dev/shm` is not available 260 - `VISUAL`: editor command to use instead of `vi` 261 262 ### find 263 264 Syntax: 265 266 ``` 267 pashage find [--raw,-r] [GREP_OPTIONS] regex 268 ``` 269 270 This subcommand lists as a tree the secrets whose name match the given 271 regular expression, using the corresponding `grep(1)` options. 272 273 Flags: 274 - `-r` or `--raw`: display the results as a raw list of secrets, 275 rather than a tree 276 277 Environment: 278 - `CLICOLOR`: when set to a non-empty value, use ANSI escape sequences to 279 color the output 280 - `LC_CTYPE`: when it contains `UTF`, the tree is displayed using Unicode 281 graphic characters instead of ASCII 282 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 283 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 284 when `PASHAGE_DIR` is unset 285 - `PASSWORD_STORE_DIR`: database directory to use instead of 286 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 287 288 ### generate 289 290 Syntax: 291 292 ``` 293 pashage generate [--no-symbols,-n] [--clip,-c | --qrcode,-q] 294 [--in-place,-i | --force,-f] [--multiline,-m] 295 [--try,-t] pass-name [pass-length [character-set]] 296 ``` 297 298 This subcommand generates a new secret from `/dev/urandom`, stores it in 299 the database, and by default displays it on the standard output and asks 300 for confirmation before overwriting an existing secret. 301 302 Flags: 303 - `-c` or `--clip`: paste the secret into the clipboard instead of using 304 the standard output 305 - `-f` or `--force`: replace existing secrets without asking 306 - `-i` or `--in-place`: when the secret already exists, replace only its 307 first line and re-use the following lines 308 - `-m` or `--multiline`: read lines from standard input append after the 309 generated data into the secret file 310 - `-n` or `--no-symbols`: generate a secret using only alphanumeric 311 characters 312 - `-q` or `--qrcode`: display the secret as a QR-code instead of using the 313 standard output 314 - `-t` or `--try`: display the secret and ask for confirmation before 315 storing it into the database 316 317 Environment: 318 - `CLICOLOR`: when set to a non-empty value, use ANSI escape sequences to 319 color the output 320 - `PASHAGE_AGE`: external command to use instead of `age` 321 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 322 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 323 `~/.passage/identities` 324 - `PASSAGE_AGE`: external command to use instead of `age` when 325 `PASHAGE_AGE` is unset 326 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 327 when `PASHAGE_DIR` is unset 328 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 329 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 330 - `PASSWORD_STORE_CHARACTER_SET_NO_SYMBOLS`: default character set to use 331 with `tr(1)` when `-n` is specified, instead of `[:alnum:]` 332 - `PASSWORD_STORE_CHARACTER_SET`: default character set to use with `tr(1)` 333 when `-n` is not specified, instead of `[:punct:][:alnum:]` 334 - `PASSWORD_STORE_CLIP_TIME`: number of second before clearing the 335 clipboard when `-c` is used, instead of 45 336 - `PASSWORD_STORE_DIR`: database directory to use instead of 337 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 338 - `PASSWORD_STORE_GENERATED_LENGTH`: number of characters in the generated 339 secret when not explicitly given, instead of 25 340 - `PASSWORD_STORE_X_SELECTION`: selection to use when `-c` and `xclip` are 341 used, instead of `clipboard` 342 343 ### git 344 345 Syntax: 346 347 ``` 348 pashage git git-command-args ... 349 ``` 350 351 This subcommand invokes `git` in the database repository. 352 Only `git init` and `git clone` are accepted when there is no underlying 353 repository. 354 355 Environment: 356 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 357 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 358 when `PASHAGE_DIR` is unset 359 - `PASSWORD_STORE_DIR`: database directory to use instead of 360 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 361 362 ### gitconfig 363 364 Syntax: 365 366 ``` 367 pashage gitconfig 368 ``` 369 370 This subcommand configures the underlying repository to automatically 371 decrypt secrets to display differences. 372 373 Environment: 374 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 375 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 376 when `PASHAGE_DIR` is unset 377 - `PASSWORD_STORE_DIR`: database directory to use instead of 378 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 379 380 ### grep 381 382 Syntax: 383 384 ``` 385 pashage grep [GREP_OPTIONS] search-regex 386 ``` 387 388 This subcommand successively decrypts all the secrets in the store and 389 filter them through `grep(1)` using the given options, and outputs all the 390 matching lines and the corresponding secret. 391 392 Environment: 393 - `CLICOLOR`: when set to a non-empty value, use ANSI escape sequences to 394 color the output 395 - `PASHAGE_AGE`: external command to use instead of `age` 396 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 397 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 398 `~/.passage/identities` 399 - `PASSAGE_AGE`: external command to use instead of `age` when 400 `PASHAGE_AGE` is unset 401 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 402 when `PASHAGE_DIR` is unset 403 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 404 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 405 - `PASSWORD_STORE_DIR`: database directory to use instead of 406 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 407 408 ### help 409 410 Syntax: 411 412 ``` 413 pashage help 414 ``` 415 416 This subcommand displays on the standard output the version and help text, 417 including all subcommands and flags and a brief description. 418 419 This subcommand is not affected by the environment. 420 421 ### init 422 423 Syntax: 424 425 ``` 426 pashage init [--interactive,-i | --keep,-k ] 427 [--path=subfolder,-p subfolder] age-recipient ... 428 ``` 429 430 This subcommand initializes an age _recipient_ list, by default of the root 431 of the password store, and re-encrypts all the affected secrets. 432 When the _recipient_ list is a single empty string, the _recipient_ list is 433 instead removed, falling back to a parent _recipient_ list or ultimately to 434 the age _identity_. 435 436 Flags: 437 - `-i` or `--interactive`: ask for each secret whether to re-encrypt it 438 or not 439 - `-k` or `--keep`: do not re-encrypt any secret 440 - `-p` or `--path`: operate on the _recipient_ list in the given subfolder 441 instead of the root of the password store 442 443 Environment: 444 - `PASHAGE_AGE`: external command to use instead of `age` 445 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 446 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 447 `~/.passage/identities` 448 - `PASSAGE_AGE`: external command to use instead of `age` when 449 `PASHAGE_AGE` is unset 450 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 451 when `PASHAGE_DIR` is unset 452 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 453 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 454 - `PASSWORD_STORE_DIR`: database directory to use instead of 455 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 456 457 ### insert 458 459 Syntax: 460 461 ``` 462 pashage insert [--echo,-e | --multiline,-m] [--force,-f] pass-name ... 463 ``` 464 465 This subcommand adds new secrets in the database, using the provided data 466 from the standard input. By default asks before overwriting an existing 467 secret, and it reads a single secret line after turning off the console 468 echo, and reads it a second time for confirmation. 469 470 Flags: 471 - `-e` or `--echo`: read a single line once without manipulating the 472 standard input 473 - `-m` or `--multiline`: an arbitrary amount of lines from the standard 474 input, without trying to manipulate the console, until the end of input 475 or a blank line is entered 476 - `-f` or `--force`: overwrite an existing secret without asking 477 478 Environment: 479 - `PASHAGE_AGE`: external command to use instead of `age` 480 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 481 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 482 `~/.passage/identities` 483 - `PASSAGE_AGE`: external command to use instead of `age` when 484 `PASHAGE_AGE` is unset 485 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 486 when `PASHAGE_DIR` is unset 487 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 488 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 489 - `PASSWORD_STORE_DIR`: database directory to use instead of 490 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 491 492 ### list 493 494 Syntax: 495 496 ``` 497 pashage [list] [--raw,-r] [subfolder ...] 498 ``` 499 500 This subcommand displays the given subfolders as a tree or a raw list, 501 or the whole store when no subfolder is specified. 502 503 Note that when a secret is given instead of a subfolder, the _show_ command 504 will be used instead, without any warning or error. 505 506 Flags: 507 - `-r` or `--raw`: display the results as a raw list of secrets 508 509 Environment: 510 - `CLICOLOR`: when set to a non-empty value, use ANSI escape sequences to 511 color the output 512 - `LC_CTYPE`: when it contains `UTF`, the tree is displayed using Unicode 513 graphic characters instead of ASCII 514 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 515 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 516 when `PASHAGE_DIR` is unset 517 - `PASSWORD_STORE_DIR`: database directory to use instead of 518 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 519 520 ### move 521 522 Syntax: 523 524 ``` 525 pashage move [--reencrypt,-e | --interactive,-i | --keep,-k ] 526 [--force,-f] old-path ... new-path 527 ``` 528 529 This subcommand moves or renames secrets and subfolders recursively, 530 using the same positional argument scheme as `mv(1)`. 531 By default it asks before overwriting an existing secret and it re-encrypts 532 the secret when the destination has a different _recipient_ list. 533 534 Flags: 535 - `-e` or `--reencrypt`: always re-encrypt secrets 536 - `-f` or `--force`: overwrite existing secrets without asking 537 - `-i` or `--interactive`: asks whether to re-encrypt or not for each secret 538 - `-k` or `--keep`: never re-encrypt secrets 539 540 Environment: 541 - `PASHAGE_AGE`: external command to use instead of `age` 542 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 543 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 544 `~/.passage/identities` 545 - `PASSAGE_AGE`: external command to use instead of `age` when 546 `PASHAGE_AGE` is unset 547 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 548 when `PASHAGE_DIR` is unset 549 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 550 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 551 - `PASSWORD_STORE_DIR`: database directory to use instead of 552 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 553 554 ### random 555 556 Syntax: 557 558 ``` 559 pashage random [pass-length [character-set]] 560 ``` 561 562 This subcommand generates a new secret, like the _generate_ subcommand, 563 then directly displays on the standard output without storing it. 564 565 Environment: 566 - `PASSWORD_STORE_CHARACTER_SET`: character set to use with `tr(1)` when 567 `character-set` is not specified, instead of `[:punct:][:alnum:]` 568 - `PASSWORD_STORE_GENERATED_LENGTH`: number of characters in the generated 569 secret when not explicitly given, instead of 25 570 571 ### reencrypt 572 573 Syntax: 574 575 ``` 576 pashage reencrypt [--interactive,-i] pass-name|subfolder ... 577 ``` 578 579 This subcommand re-encrypts in place the given secrets, and all the secrets 580 recursively in the given subfolders. 581 582 Flags: 583 - `-i` or `--interactive`: asks whether to re-encrypt or not for each secret 584 585 Environment: 586 - `PASHAGE_AGE`: external command to use instead of `age` 587 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 588 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 589 `~/.passage/identities` 590 - `PASSAGE_AGE`: external command to use instead of `age` when 591 `PASHAGE_AGE` is unset 592 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 593 when `PASHAGE_DIR` is unset 594 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 595 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 596 - `PASSWORD_STORE_DIR`: database directory to use instead of 597 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 598 599 ### show 600 601 Syntax: 602 603 ``` 604 pashage [show] [--clip[=line-number],-c[line-number] | 605 --qrcode[=line-number],-q[line-number]] pass-name ... 606 ``` 607 608 This subcommand decrypts the given secrets and by default displays the 609 whole text on the standard output. 610 611 Note that when a subfolder is given instead of a secret, the _list_ command 612 will be used instead, without any warning or error. 613 614 Flags: 615 - `-c` or `--clip`: paste the given line (by default the first line) of the 616 secret into the clipboard instead of using the standard output 617 - `-q` or `--qrcode`: display the given line (by default the first line) of 618 the secret as a QR-code instead of using the standard output 619 620 Environment: 621 - `PASHAGE_AGE`: external command to use instead of `age` 622 - `PASHAGE_DIR`: database directory to use instead of `~/.passage/store` 623 - `PASHAGE_IDENTITIES_FILE`: _identity_ file to use instead of 624 `~/.passage/identities` 625 - `PASSAGE_AGE`: external command to use instead of `age` when 626 `PASHAGE_AGE` is unset 627 - `PASSAGE_DIR`: database directory to use instead of `~/.passage/store` 628 when `PASHAGE_DIR` is unset 629 - `PASSAGE_IDENTITIES_FILE`: _identity_ file to use instead of 630 `~/.passage/identities` when `PASHAGE_IDENTITIES_FILE` is unset 631 - `PASSWORD_STORE_DIR`: database directory to use instead of 632 `~/.passage/store` when both `PASHAGE_DIR` and `PASSAGE_DIR` are unset 633 634 ### version 635 636 Syntax: 637 638 ``` 639 pashage version 640 ``` 641 642 This subcommand displays on the standard output the version and author 643 list. 644 645 This subcommand is not affected by the environment.