raffi 0.25.0

A simple fuzzel launcher based on YAML file
Documentation
---
title: Password Store
description: Copy or type passwords from pass, the standard Unix password manager
---

import { Aside } from '@astrojs/starlight/components';
import { Image } from 'astro:assets';
import passScreenshot from '../../../assets/screenshots/password-store.png';

<Image src={passScreenshot} alt="Password-store listing with fictional code, community and mail entries; no passwords are displayed" width={800} />

Type `pass ` (with the trailing space) to list the entries of your
[password store](https://www.passwordstore.org/). Each row shows the entry
name, with its folder underneath. Words after the keyword filter the list,
so `pass github` finds `web/github.com`. Pasting a URL, such as
`pass https://login.github.com/session`, lists first the entries with that
site's domain in their path (`web/github.com`, `github.com/alice` or
`alice@github.com`). Listing only reads file names; nothing is decrypted
until you pick an entry.

The entries you copy or type most come first, ordered by the
[`sort_mode`](../../configuration/general-settings/) used for launchers
(`hybrid` by default, `recency` for most recent first). While you type,
past use only decides between equally good matches.

<Aside type="note">
The password store addon is only available in native mode and needs `pass`
and `gpg`. It is on by default. When either is missing the list says
"pass not found" or "gpg not found".
</Aside>

| Key        | Action                                        |
|------------|-----------------------------------------------|
| Enter      | Copy the password                             |
| Ctrl+Enter | Type the password                             |
| Ctrl+U     | Copy the username                             |
| Ctrl+O     | Copy the OTP code                             |

The password is the first line of the entry. The username comes from a
`login:` line, else `user:`, else `username:`, wherever they sit in the
entry. With none of them, it is the entry's file name, which suits the common `site/username` layout. OTP
codes need the [pass-otp](https://github.com/tadfisher/pass-otp) extension
and an `otpauth://` line in the entry.

Raffi closes before it copies or types anything, so typing goes to the
window you were in. Copies are cleared from the clipboard after 45 seconds,
unless something else was copied meanwhile.

## The GPG passphrase

When gpg-agent already holds your passphrase, the entry decrypts right
away. Otherwise Raffi turns the search field into a masked passphrase
prompt. Type it and press Enter; a wrong passphrase keeps the prompt open
with an error, and Escape goes back to the list. Raffi hands the passphrase
to gpg on its standard input, and gpg-agent caches it as usual, so the next
entries and other `pass` commands don't ask again.

Raffi's prompt uses gpg's loopback pinentry. If you use a smartcard or a
YubiKey, or your `gpg-agent.conf` sets `no-allow-loopback-pinentry`, set
`pinentry: agent` instead. Raffi then closes first and lets gpg-agent show
its own pinentry window, and copies or types once you have answered it.

## Lock and sync

The list ends with two extra rows:

| Row                  | Enter                                                          |
|----------------------|----------------------------------------------------------------|
| Lock password store  | Run `gpgconf --reload gpg-agent` to forget passphrases, close Raffi |
| Sync password store  | Run `pass git pull --ff-only`, then reload the list             |

The sync row only shows when the store is a git repository. A pull that
cannot fast forward is reported as an error; Raffi never resets, stashes or
forces anything.

<Aside type="caution">
Reloading gpg-agent forgets every cached passphrase, including those of
other programs, and your SSH keys when gpg-agent is your SSH agent.
</Aside>

## Security notes

- Secrets reach `gpg`, the clipboard and the typing tool on standard input,
  never on a command line, and are never logged or saved in the search
  history.
- Raffi keeps when and how often you used each entry in
  `~/.cache/raffi/vault.cache`, by entry name, so that file shows which
  entries you use.
- What you type after `pass ` goes into the search history (Alt+P) when
  you copy or type an entry, so the history file can show which entries
  you looked up. Debug logs leave it out.
- With `wl-copy` 2.3 or newer the copy is marked sensitive, which clipboard
  managers such as cliphist honour. That is only a hint: other managers,
  `xclip` and `xsel` may keep the password in their history. Tools that keep
  the clipboard alive after its owner exits, such as wl-clip-persist, also
  defeat the 45 second clearing.
- Clearing the clipboard later needs `timeout` from coreutils. Without it
  Raffi refuses to copy rather than leave the password there for good; set
  `clipboard_timeout: 0` to copy without clearing.
- Typing uses `wtype` or `ydotool` after a short delay (`type_delay_ms`).
  Raffi cannot check which window has the focus by then, so make sure it is
  the one you expect, especially after a pinentry window.

To open the list from a key binding, pass the keyword as the initial query:

```sh
raffi -u native -i "pass "
```

## Configuration

```yaml
addons:
  pass:
    store_dir: ~/.password-store
    pinentry: raffi
    username_fields: [login, user, username]
    clipboard_timeout: 45
    type_delay_ms: 200
```

See the [addon reference](../../reference/addon-configuration/#password-store)
for every field.