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