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