{"id":27639824,"url":"https://github.com/dbohdan/pago","last_synced_at":"2025-04-23T22:34:38.456Z","repository":{"id":268255136,"uuid":"902768579","full_name":"dbohdan/pago","owner":"dbohdan","description":"Command-line password manager","archived":false,"fork":false,"pushed_at":"2025-04-14T12:23:54.000Z","size":282,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-14T13:37:20.151Z","etag":null,"topics":["age","age-encryption","go","golang","password-manager"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dbohdan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-13T08:25:42.000Z","updated_at":"2025-04-14T12:23:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"e6e8eff1-a049-4c4e-a38d-d468dd19acc2","html_url":"https://github.com/dbohdan/pago","commit_stats":null,"previous_names":["dbohdan/pago"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbohdan%2Fpago","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbohdan%2Fpago/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbohdan%2Fpago/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbohdan%2Fpago/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dbohdan","download_url":"https://codeload.github.com/dbohdan/pago/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250528204,"owners_count":21445507,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["age","age-encryption","go","golang","password-manager"],"created_at":"2025-04-23T22:34:37.903Z","updated_at":"2025-04-23T22:34:38.442Z","avatar_url":"https://github.com/dbohdan.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pago\n\n\u003e 🚧 **pago is in early [beta](https://en.wikipedia.org/wiki/Software_release_life_cycle#Beta).**\n\u003e Expect bugs, security vulnerabilities, and potential data loss.\n\n**pago** is a command-line password manager.\nIt provides the following in a single binary:\n- [age](https://github.com/FiloSottile/age) public-key and password encryption\n- Git version control of the password store ([go-git](https://github.com/go-git/go-git))\n- A fuzzy finder similar to [fzf](https://github.com/junegunn/fzf) for choosing entries ([go-fuzzyfinder](https://github.com/ktr0731/go-fuzzyfinder))\n- A multiline text editor for editing encrypted data without writing it to disk ([bubbles/textarea](https://github.com/charmbracelet/bubbles))\n\n## Description\n\npago encrypts passwords with one or more public keys using [age](https://github.com/FiloSottile/age) (pronounced with a hard \"g\").\nThe public keys are called \"recipients\".\nA private key matching one of the recipient public keys can decrypt the password.\nThe private keys are called \"identities\".\nThe file with the identities is encrypted with a password, also using age.\n\npago implements an agent like [ssh-agent](https://en.wikipedia.org/wiki/Ssh-agent) or [gpg-agent](https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html).\nThe agent caches the identities.\nThis mean you don't have to enter the master password again during a session.\npago starts the agent the first time you enter the master password.\nYou can also start and stop the agent manually.\n\nThe pago password store format is compatible with [passage](https://github.com/FiloSottile/passage).\nIt has the following differences:\n\n- The pago directory is located at `${XDG_DATA_HOME}/pago/`, while passage uses `~/.passage/`\n- passage supports an encrypted or an unencrypted identities file; pago only supports encrypted\n\n## Threat model\n\nAn attacker who gets ahold of your pago directory but not the master password should be unable to access the passwords stored in pago except by [brute-forcing](https://en.wikipedia.org/wiki/Brute-force_attack) the master password.\n\n## Motivation and alternatives\n\nMy primary password manager is [KeePassXC](https://github.com/keepassxreboot/keepassxc).\nI use a secondary password manager to access a subset of secrets in cron jobs and scripts and on headless remote systems.\n\nI used [`pass`](https://www.passwordstore.org/) for this for a time.\nWhile I liked the design of `pass` and found it pleasant to use, I didn't like setting up GPG on a new system.\nI went looking for a `pass` replacement based on age\nbecause I had replaced GPG with age for encrypting files.\nThe following is the late-2024 shortlist of password managers I compiled before I decided to work on pago.\nIt includes explanations for why I didn't adopt them.\n\nFirst, I needed the identities encrypted at rest and usable without reentering the password.\nThis ruled out [passage](https://github.com/FiloSottile/passage), which had no an agent, and [pa](https://github.com/biox/pa), which didn't support encryption for the identities file.\n[kbs2](https://github.com/woodruffw/kbs2) didn't integrate with Git.\n[seniorpw](https://gitlab.com/retirement-home/seniorpw) matched all of my criteria and was the closest to `pass`.\nIt is what I would most likely be using if I didn't decide to develop my own.\n\nAll of the above password managers are worth your attention.\nFor more options, see [\"Awesome age\"](https://github.com/FiloSottile/awesome-age).\n\n## History\n\npago is a heavily modified fork of [pash](https://github.com/dylanaraps/pash) (archived).\nIt has been ported from POSIX shell to Tcl to Go and from [GPG](https://gnupg.org/) to age.\n\n## Installation\n\nYou will need Go 1.22 or later to install pago.\nOnce Go is installed on your system, run the following commands:\n\n```shell\n# pago and pago-agent are two separate binaries.\n# You should install both unless you have a specific reason not to.\ngo install dbohdan.com/pago/cmd/pago@latest\ngo install dbohdan.com/pago/cmd/pago-agent@latest\n```\n\nShell completion files for Bash and fish are available in [`completions/`](completions/).\nTo install completions for fish, clone the repository and run `install.fish`.\n\n## Supported platforms\n\n- pago is used by the developer on Linux, NetBSD, and OpenBSD.\n- pago is automatically tested on FreeBSD and macOS.\n- pago does not build on Windows.\n\nThe pago agent and test suite don't work on Windows.\nInstead of offering a partial and untested Windows build, the project doesn't support Windows.\nWindows users interested in pago are encouraged to try it in [WSL](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux).\n\n## Usage\n\n### Initialize the password store\n\n```shell\npago init\n```\n\nThis will create a new password store, prompt you for a master password, and commit the recipients file to Git.\n\n### Add passwords\n\n```shell\n# Either generate or input a password.\npago add foo/bar\n\n# Generate a random password.\npago add -r foo/bar\n\n# Specify a custom length and character pattern (regular expression).\npago add -l 32 -p '[A-Za-z0-9#$%]' foo/bar\n\n# Input your own password.\npago add -i foo/bar\n\n# Read a multiline secret.\nage-keygen | pago add -m foo/bar\n```\n\nAdding a password creates a Git commit by default.\n\n### Access passwords\n\n```shell\n# Show a password.\npago show foo/bar\n\n# Copy to clipboard (clears after 30 seconds).\npago clip foo/bar\n\n# Copy with a custom timeout (in seconds; 0 to disable).\npago clip -t 20 foo/bar\n\n# List all entries organized in a tree.\npago show\n\n# Find entires by a name regular expression.\npago find fo\n\n# Select and entry interactively using a fuzzy finder\npago show --pick\n\n# The same as `pago show --pick foo`. Starts the search with `foo`.\npago pick foo\n```\n\n### Edit passwords\n\n```shell\n# Edit a password that already exists.\npago edit foo/bar\n\n# Create a password if it doesn't exist.\npago edit foo/new -f\n```\n\n### Generate passwords\n\n```shell\n# Generate a password without saving it.\npago generate\n\n# Customize the length and pattern.\npago generate --length 16 --pattern '[a-z0-9]'\n```\n\n### Delete passwords\n\n```shell\n# Delete with confirmation.\npago delete foo/bar\n\n# Force delete without confirmation.\npago delete -f foo/bar\n\n# Pick what password to delete using a fuzzy finder.\npago delete -p foo/bar\n```\n\nBy default, this will commit the deletion to Git.\n\n### Agent\n\nThe agent keeps your identities in memory to avoid repeated password prompts.\n\n```shell\n# Start automatically when needed (recommended).\npago show foo/bar\n\n# Start manually.\npago agent start\n\n# By default, the agent locks its memory to prevent secrets from being written to swap.\n# You may need to run the command `ulimit -l 100000` to let it lock enough memory.\n# Alternatively, you can disable memory locking\n# with the environment variable `PAGO_MEMLOCK=0` or the flag `--no-memlock`.\npago agent start --no-memlock\n\n# Run without an agent.\npago -s '' show foo/bar\n\n# Shut down.\npago agent stop\n```\n\n### Configuring memory locking\n\npago-agent uses under 100 MiB of memory on systems where it has been tested.\nIt needs to lock memory to avoid being swapped out.\nOn Free/Net/OpenBSD, the agent apparently needs the limit on locked memory to exceed its virtual memory, which can be over 1 GiB, even though only around 100 MiB is reserved.\n(You don't lose 1 GiB of memory.)\nConfigure your system to allow this or set the environment variable `PAGO_MEMLOCK=0` to disable locking.\n\nHere is how to allow users to lock more memory on typical systems.\nIn these examples, we set the limit to 8 GiB.\n\n#### Linux (systemd)\n\n1. Create `/etc/systemd/system.conf.d/` if it doesn't exist.\n2. Edit `/etc/systemd/system.conf.d/limits.conf` to contain the following:\n\n```ini\n[Manager]\nDefaultLimitMEMLOCK=8589934592\n```\n\n3. Restart your user session.\n\n#### Linux (other init systems)\n\n1. Edit `/etc/security/limits.conf` and add this line:\n\n```none\n* hard memlock 8589934592\n```\n\n2. Restart your user session.\n\n#### Free/Net/OpenBSD\n\n1. Edit `/etc/login.conf` and update the default value of `memorylocked`:\n\n```\ndefault:\\\n    [...]\n\t:memorylocked=8G:\\\n    [...]\n```\n\n2. On FreeBSD only, run the following command as root:\n\n```shell\ncap_mkdb /etc/login.conf\n```\n\n3. Restart your user session.\n\n### Environment variables\n\n- `PAGO_AGENT`:\n  The agent executable\n- `PAGO_CLIP`:\n  The command to use to copy the password to the clipboard.\n  The default differs by platform.\n  On Linux and BSD, it is `xclip -in -selection clip`.\n- `PAGO_CONFIRM`:\n  Whether pago should ask yes-no questions.\n  `0` means pago will assume \"yes\".\n- `PAGO_DIR`:\n  The pago data directory location.\n  Defaults to `~/.local/share/pago` on Linux and BSD.\n- `PAGO_GIT`:\n  Whether to use Git\n- `PAGO_LENGTH`:\n  The default length of random passwords\n- `PAGO_MEMLOCK`:\n  Whether the agent should lock its memory using [mlockall(2)](https://pubs.opengroup.org/onlinepubs/9799919799/functions/mlockall.html) to prevent secrets from being written to swap.\n  `0` to disable.\n- `PAGO_PATTERN`:\n  The default character pattern (regular expression) for random passwords\n- `PAGO_SOCK`:\n  The agent socket path\n- `PAGO_TIMEOUT`:\n  The default clipboard timeout\n\n### Interactive editor\n\nThe editor for the `edit` command editor includes the default [bubbles/textarea key bindings](https://github.com/charmbracelet/bubbles/blob/8624776d4572078ae6ff098d454c719047f9eb83/textarea/textarea.go#L71).\n\n#### Session\n\n- **Ctrl+D**: Save and exit\n- **Esc**/**Ctrl+C**: Exit without saving\n\n#### Navigation\n\n- **←**/**Ctrl+B**: Move cursor left by one character\n- **→**/**Ctrl+F**: Move cursor right by one character\n- **Alt+←**/**Alt+B**: Move cursor left by one word\n- **Alt+→**/**Alt+F**: Move cursor right by one word\n- **↑**/**Ctrl+P**: Move cursor up a line\n- **↓**/**Ctrl+N**: Move cursor down a line\n- **Home**/**Ctrl+A**: Move to line start\n- **End**/**Ctrl+E**: Move to line end\n- **Alt+\u003c**/**Ctrl+Home**: Move to beginning of input\n- **Alt+\u003e**/**Ctrl+End**: Move to end of input\n\n#### Editing\n\n- **Backspace**/**Ctrl+H**: Delete character before cursor\n- **Delete**/**Ctrl+D**: Delete character after cursor\n- **Alt+Backspace**/**Ctrl+W**: Delete word before cursor\n- **Alt+Delete**/**Alt+D**: Delete word after cursor\n- **Ctrl+K**: Delete all text after cursor\n- **Ctrl+U**: Delete all text before cursor\n- **Enter**/**Ctrl+M**: Insert newline\n- **Ctrl+V**: Paste from clipboard\n\n#### Text transformation\n\n- **Alt+C**: Capitalize word forward\n- **Alt+L**: Lowercase word forward\n- **Alt+U**: Uppercase word forward\n- **Ctrl+T**: Transpose characters at cursor\n\n## License\n\nMIT.\nSee the file [`LICENSE`](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdbohdan%2Fpago","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdbohdan%2Fpago","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdbohdan%2Fpago/lists"}