{"id":13781621,"url":"https://github.com/woodruffw/kbs2","last_synced_at":"2025-05-16T07:07:20.561Z","repository":{"id":37146630,"uuid":"263823753","full_name":"woodruffw/kbs2","owner":"woodruffw","description":"A secret manager backed by age","archived":false,"fork":false,"pushed_at":"2025-05-09T03:38:22.000Z","size":1186,"stargazers_count":119,"open_issues_count":15,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-12T05:54:17.928Z","etag":null,"topics":["age","hacktoberfest","password-manager","rust","secret-managers"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/kbs2","language":"Rust","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/woodruffw.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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},"funding":{"github":"woodruffw","thanks_dev":"u/gh/woodruffw"}},"created_at":"2020-05-14T05:29:44.000Z","updated_at":"2025-05-09T03:35:36.000Z","dependencies_parsed_at":"2023-12-25T16:49:31.286Z","dependency_job_id":"d0f6a928-1262-4ffd-b36e-f853932d1058","html_url":"https://github.com/woodruffw/kbs2","commit_stats":{"total_commits":893,"total_committers":7,"mean_commits":"127.57142857142857","dds":0.4557670772676372,"last_synced_commit":"448a8530304e838bdc48e8bb3c69a97263ad0088"},"previous_names":[],"tags_count":79,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/woodruffw%2Fkbs2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/woodruffw%2Fkbs2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/woodruffw%2Fkbs2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/woodruffw%2Fkbs2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/woodruffw","download_url":"https://codeload.github.com/woodruffw/kbs2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254485065,"owners_count":22078767,"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","hacktoberfest","password-manager","rust","secret-managers"],"created_at":"2024-08-03T18:01:27.748Z","updated_at":"2025-05-16T07:07:15.552Z","avatar_url":"https://github.com/woodruffw.png","language":"Rust","funding_links":["https://github.com/sponsors/woodruffw","https://thanks.dev/u/gh/woodruffw"],"categories":["Rust","Tools"],"sub_categories":[],"readme":"kbs2\n====\n\n[![CI](https://github.com/woodruffw/kbs2/actions/workflows/ci.yml/badge.svg)](https://github.com/woodruffw/kbs2/actions/workflows/ci.yml)\n[![Crates.io](https://img.shields.io/crates/v/kbs2)](https://crates.io/crates/kbs2)\n[![Packaging status](https://repology.org/badge/tiny-repos/kbs2.svg)](https://repology.org/project/kbs2/versions)\n\n**Warning! `kbs2` is beta-quality software! Using `kbs2` means accepting that your secrets may be\nlost or compromised at any time!**\n\n`kbs2` is a command line utility for managing *secrets*.\n\nQuick links:\n\n* [Installation](#installation)\n* [Quick start guide](#quick-start-guide)\n* [CLI documentation](#cli-documentation)\n  * [`kbs2 init`](#kbs2-init)\n  * [`kbs2 new`](#kbs2-new)\n  * [`kbs2 list`](#kbs2-list)\n  * [`kbs2 rm`](#kbs2-rm)\n  * [`kbs2 rename`](#kbs2-rename)\n  * [`kbs2 dump`](#kbs2-dump)\n  * [`kbs2 pass`](#kbs2-pass)\n  * [`kbs2 env`](#kbs2-env)\n  * [`kbs2 edit`](#kbs2-edit)\n  * [`kbs2 generate`](#kbs2-generate)\n  * [`kbs2 agent`](#kbs2-agent)\n    * [`kbs2 agent flush`](#kbs2-agent-flush)\n    * [`kbs2 agent unwrap`](#kbs2-agent-unwrap)\n  * [`kbs2 rewrap`](#kbs2-rewrap)\n  * [`kbs2 rekey`](#kbs2-rekey)\n  * [`kbs2 config`](#kbs2-config)\n    * [`kbs2 config dump`](#kbs2-config-dump)\n* [Configuration](#configuration)\n  * [Generators](#generators)\n* [Customization](#customization)\n  * [Custom commands](#custom-commands)\n  * [Hooks](#hooks)\n  * [Managing your key and master password](#managing-your-key-and-master-password)\n* [Why another password manager?](#why-another-password-manager)\n* [Technical details](#technical-details)\n* [Hacking](#hacking)\n* [History](#history)\n\n## Installation\n\n### Packages\n\n`kbs2` is available via a variety of official and community-supplied packages.\n\nSee the matrix below for a list of repositories containing `kbs2`.\n\n[![Packaging status](https://repology.org/badge/vertical-allrepos/kbs2.svg)](https://repology.org/project/kbs2/versions)\n\n**These packages are the recommended way to install `kbs2` if you are not developing it.**\n\n#### Debian/Ubuntu\n\n*This is an official package.*\n\nIf you're running a Debian or Ubuntu distribution on AMD64, you can use the `.deb` packages\nattached to the [latest release](https://github.com/woodruffw/kbs2/releases/latest).\n\nBy way of example:\n\n```console\n$ wget https://github.com/woodruffw/kbs2/releases/download/v0.7.2/kbs2_0.7.2_amd64.deb\n$ sudo dpkg -i kbs2_0.7.2_amd64.deb\n# don't forget to request kbs2's dependencies\n$ sudo apt-get -f install\n```\n\n#### Arch Linux\n\n*This is a community-maintained package.*\n\n`kbs2` can be installed from available\n[AUR packages](https://aur.archlinux.org/packages/?O=0\u0026SeB=b\u0026K=kbs2\u0026outdated=\u0026SB=n\u0026SO=a\u0026PP=50\u0026do_Search=Go)\nusing an [AUR helper](https://wiki.archlinux.org/index.php/AUR_helpers). For example,\n\n```console\n$ yay -S kbs2\n```\n\nOther distributions will be supported sooner or later. Help us by looking at the\n[open packaging issues](https://github.com/woodruffw/kbs2/labels/C%3Apackaging)!\n\n#### Nix\n\n*This is a community-maintained package.*\n\n`kbs2` can be installed through Nix:\n\n```console\n$ nix-env -iA nixpkgs.kbs2\n```\n\n#### Cargo\n\nIf you're a Linux user, you'll need some X11 libraries. For Debian-based distributions:\n\n```console\n$ sudo apt install -y libxcb-shape0-dev libxcb-xfixes0-dev\n```\n\n`kbs2` itself is most easily installed via `cargo`:\n\n```console\n$ cargo install kbs2\n```\n\nAfter installation, `kbs2` is completely ready for use. See the\n[Configuration](#configuration) section for some *optional* changes that you can\nmake.\n\n## Quick start guide\n\nInitialize a new `kbs2` configuration:\n\n```console\n$ kbs2 init\n```\n\nBy default, a fresh `kbs2` configuration will store records in `$HOME/.local/share/kbs2`. Users\ncan override this by passing `--store-dir DIR` to `kbs2 init`, or at any point by modifying\n`store` in the config itself.\n\n`kbs2 init` will automatically generate a configuration file and keypair, prompting you for\na \"master\" password.\n\n**Note**: By default, most `kbs2` commands will start the authentication agent (`kbs2 agent`)\nin the background if it isn't already running.\n\nCreate a new (login) record:\n\n```console\n$ kbs2 new amazon\n? Username? jonf-bonzo\n? Password? [hidden]\n```\n\nList available records:\n\n```console\n$ kbs2 list\namazon\nfacebook\n```\n\nPull the password from a record:\n\n```console\n$ kbs2 pass -c amazon\n# alternatively, pipeline it\n$ kbs2 pass facebook | pbcopy\n```\n\nRemove a record:\n\n```console\n$ kbs2 rm facebook\n```\n\n`kbs2`'s subcommands are substantially more featured than the above examples demonstrate;\nrun each with `--help` to see a full set of supported options.\n\n## CLI documentation\n\n### `kbs2 init`\n\n#### Usage\n\n```\ninitialize kbs2 with a new config and keypair\n\nUSAGE:\n    kbs2 init [FLAGS] [OPTIONS]\n\nFLAGS:\n    -f, --force                   overwrite the config and keyfile, if already present\n    -h, --help                    Prints help information\n        --insecure-not-wrapped    don't wrap the keypair with a master password\n\nOPTIONS:\n    -s, --store-dir \u003cDIR\u003e    the directory to store encrypted kbs2 records in\n                             [default: $HOME/.local/share/kbs2]\n```\n\n#### Examples\n\nCreate a new config and keypair, prompting the user for a master password:\n\n```console\n$ kbs2 init\n```\n\nCreate a new config and keypair **without** a master password:\n\n```console\n$ kbs2 init --insecure-not-wrapped\n```\n\nCreate a new config and keypair in a different location:\n\n```console\n$ kbs2 -c /some/config/dir init\n```\n\nCreate a new config keypair in a different location and specify a non-default store:\n\n```console\n$ kbs2 -c /home/config/dir init --store-dir /some/store/dir\n```\n\n### `kbs2 new`\n\n#### Usage\n\n```\ncreate a new record\n\nUSAGE:\n    kbs2 new [FLAGS] [OPTIONS] \u003clabel\u003e\n\nARGS:\n    \u003clabel\u003e    the record's label\n\nFLAGS:\n    -f, --force       overwrite, if already present\n    -h, --help        Prints help information\n    -t, --terse       read fields in a terse format, even when connected to a tty\n\nOPTIONS:\n    -G, --generator \u003cgenerator\u003e    use the given generator to generate sensitive fields\n                                   [default: default]\n    -k, --kind \u003ckind\u003e              the kind of record to create [default: login]\n                                   [possible values: login, environment, unstructured]\n```\n\n#### Examples\n\nCreate a new `login` record named `foobar`:\n\n```console\n$ kbs2 new foobar\n? Username? hasdrubal\n? Password? **********\n```\n\nCreate a new `environment` record named `twitter-api`, overwriting it if it already exists:\n\n```console\n$ kbs2 new -f -k environment twitter-api\n? Variable? TWITTER_API\n? Value? [hidden]\n[Press [enter] to auto-generate]\n```\n\nCreate a new `login` record named `pets.com`, generating the password with the default generator:\n\n```console\n$ kbs2 new pets.com\n? Username? catlover1312\n? Password?\n[Press [enter] to auto-generate]\n```\n\nEntering nothing in the password prompt will cause `kbs2` to generate a password\nusing the `\"default\"` generator. You can use the `--generator` option to specify\na different generator, if you have another one configured.\n\nCreate a new `login` record named `email`, getting the fields in a terse format:\n\n```console\n$ kbs2 new -t email \u003c \u003c(echo -e \"bill@microsoft.com\\x01hunter2\")\n```\n\nWhen in \"terse\" mode, `kbs2` expects fields to be separated by `\\x01` (ASCII SOH)\ncharacters.\n\n### `kbs2 list`\n\n#### Usage\n\n```\nlist records\n\nUSAGE:\n    kbs2 list [FLAGS] [OPTIONS]\n\nFLAGS:\n    -d, --details    print (non-field) details for each record\n    -h, --help       Prints help information\n\nOPTIONS:\n    -k, --kind \u003ckind\u003e    list only records of this kind\n                         [possible values: login, environment, unstructured]\n```\n\n#### Examples\n\nList all records, one per line:\n\n```console\n$ kbs2 list\nfoobar\ntwitter-api\npets.com\nemail\n```\n\nList (non-sensitive) details for each record. The format of the detailed listing is\n`{record} {kind} {timestamp}`.\n\n```console\n$ kbs2 list -d\nfoobar login 1590277900\ntwitter-api environment 1590277907\npets.com login 1590277920\nemail login 1590277953\n```\n\nList only environment records:\n\n```console\n$ kbs2 list -k environment\ntwitter-api\n```\n\n### `kbs2 rm`\n\n#### Usage\n\n```\nremove one or more records\n\nUSAGE:\n    kbs2 rm \u003clabel\u003e...\n\nARGS:\n    \u003clabel\u003e...    the labels of the records to remove\n\nFLAGS:\n    -h, --help    Prints help information\n```\n\n#### Examples\n\nRemove the `foobar` record:\n\n```console\n$ kbs2 rm foobar\n```\n\n### `kbs2 rename`\n\n#### Usage\n\n```\nrename a record\n\nUsage: kbs2 rename [OPTIONS] \u003cold-label\u003e \u003cnew-label\u003e\n\nArguments:\n  \u003cold-label\u003e  the record's current label\n  \u003cnew-label\u003e  the new record label\n\nOptions:\n  -f, --force  overwrite, if already present\n  -h, --help   Print help\n```\n\n#### Examples\n\nRename the `foo` record to `bar`:\n\n```console\n$ kbs2 rename foo bar\n```\n\nRename `foo` to `bar`, even if `bar` already exists:\n\n```console\n$ kbs2 rename --force foo bar\n```\n\n### `kbs2 dump`\n\n#### Usage\n\n```\ndump one or more records\n\nUSAGE:\n    kbs2 dump [FLAGS] \u003clabel\u003e...\n\nARGS:\n    \u003clabel\u003e...    the labels of the records to dump\n\nFLAGS:\n    -h, --help    Prints help information\n    -j, --json    dump in JSON format (JSONL when multiple)\n```\n\n#### Examples\n\nDump the `twitter-api` record:\n\n```console\n$ kbs2 dump twitter-api\nLabel twitter-api\nKind environment\nVariable TWITTER_API\nValue 92h2890fn83fb2378fbf283bf73fbxkfnso90\n```\n\nDump the `pets.com` record in JSON format:\n\n```console\n$ kbs2 dump -j pets.com | json_pp\n{\n   \"timestamp\" : 1590363392,\n   \"label\" : \"pets.com\",\n   \"body\" : {\n      \"fields\" : {\n         \"username\" : \"hasdrubal\",\n         \"password\" : \"hunter2\"\n      },\n      \"kind\" : \"Login\"\n   }\n}\n```\n\nDump multiple records, demonstrating JSONL:\n\n```console\n$ kbs2 dump -j carthage roma\n{\"timestamp\":1590363392,\"label\":\"bepis\",\"body\":{\"kind\":\"Login\",\"fields\":{\"username\":\"hamilcar\",\"password\":\"ihatecato\"}}}\n{\"timestamp\":1590363392,\"label\":\"conk\",\"body\":{\"kind\":\"Login\",\"fields\":{\"username\":\"cato\",\"password\":\"carthagodelendaest\"}}}\n```\n\n### `kbs2 pass`\n\n#### Usage\n\n```\nget the password in a login record\n\nUSAGE:\n    kbs2 pass [FLAGS] \u003clabel\u003e\n\nARGS:\n    \u003clabel\u003e    the record's label\n\nFLAGS:\n    -c, --clipboard    copy the password to the clipboard\n    -h, --help         Prints help information\n```\n\n#### Examples\n\nGet the password for the `pets.com` record:\n\n```console\n$ kbs2 pass pets.com\nhunter2\n```\n\nCopy the password for the `pets.com` record into the clipboard:\n\n```console\n$ kbs2 pass -c pets.com\n```\n\n### `kbs2 env`\n\n#### Usage\n\n```\nget an environment record\n\nUSAGE:\n    kbs2 env [FLAGS] \u003clabel\u003e\n\nARGS:\n    \u003clabel\u003e    the record's label\n\nFLAGS:\n    -h, --help          Prints help information\n    -n, --no-export     print only VAR=val without `export`\n    -v, --value-only    print only the environment variable value, not the variable name\n```\n\n#### Examples\n\nGet an environment record in `export`-able form:\n\n```console\n$ kbs2 env twitter-api\nexport TWITTER_API=92h2890fn83fb2378fbf283bf73fbxkfnso90\n```\n\nGet just the value in an environment record:\n\n```console\n$ kbs2 env -v twitter-api\n92h2890fn83fb2378fbf283bf73fbxkfnso90\n```\n\n### `kbs2 edit`\n\n#### Usage\n\n```\nmodify a record with a text editor\n\nUSAGE:\n    kbs2 edit [FLAGS] \u003clabel\u003e\n\nARGS:\n    \u003clabel\u003e    the record's label\n\nFLAGS:\n    -h, --help                  Prints help information\n    -p, --preserve-timestamp    don't update the record's timestamp\n```\n\n#### Examples\n\nOpen the `email` record for editing:\n\n```console\n$ kbs2 edit email\n```\n\nOpen the `email` record for editing with a custom `$EDITOR`:\n\n```console\n$ EDITOR=vim kbs2 edit email\n```\n\n### `kbs2 generate`\n\n#### Usage\n\n```\ngenerate secret values using a generator\n\nUSAGE:\n    kbs2 generate [generator]\n\nARGS:\n    \u003cgenerator\u003e    the generator to use [default: default]\n\nFLAGS:\n    -h, --help    Prints help information\n```\n\n#### Examples\n\nGenerate a secret using the default generator:\n\n```console\n$ kbs2 generate\nrrayxfky-81x=h6i\n```\n\nGenerate a secret using a generator named `pwgen`:\n\n```console\n$ kbs2 generate pwgen\niit4wie6faeL4aiyupheec5Xochosero\n```\n\n### `kbs2 agent`\n\n#### Usage\n\n```\nrun the kbs2 authentication agent\n\nUSAGE:\n    kbs2 agent [FLAGS] [SUBCOMMAND]\n\nFLAGS:\n    -F, --foreground    run the agent in the foreground\n    -h, --help          Prints help information\n\nSUBCOMMANDS:\n    flush     remove all unwrapped keys from the running agent\n    help      Prints this message or the help of the given subcommand(s)\n    unwrap    unwrap the current config's key in the running agent\n```\n\n#### Examples\n\nRun the `kbs2` agent in the background, prompting the user to unwrap the current config's key:\n\n```console\n$ kbs2 agent\n```\n\nRun the `kbs2` agent in the foreground, for debugging purposes:\n\n```console\n$ RUST_LOG=debug kbs2 agent --foreground\n```\n\n### `kbs2 agent flush`\n\n#### Usage\n\n```\nremove all unwrapped keys from the running agent\n\nUSAGE:\n    kbs2 agent flush [FLAGS]\n\nFLAGS:\n    -h, --help       Prints help information\n    -q, --quit       quit the agent after flushing\n```\n\n#### Examples\n\nRemove all keys from the current `kbs2` agent:\n\n```console\n$ kbs2 agent flush\n```\n\n### `kbs2 agent query`\n\n#### Usage\n\n```\nask the current agent whether it has the current config's key\n\nUSAGE:\n    kbs2 agent query\n\nFLAGS:\n    -h, --help       Prints help information\n    -V, --version    Prints version information\n```\n\n`kbs2 agent query` exits with a few discrete codes to signal the query status:\n\n* `0`: query succeeded, agent is running and has a keypair for the config's public key\n* `1`: query failed, agent is running but does not have the queried keypair\n* `2`: query failed, agent is running but the keypair isn't managed by the agent\n(i.e., it's an unwrapped keypair)\n* `3`: query failed, agent is not running\n\nAll other error codes should be treated as an unspecified error that prevented a query.\n\n#### Examples\n\nQuery the agent for the current config:\n\n```console\n$ kbs2 agent query \u0026\u0026 echo \"success\" || echo \"failure\"\n```\n\nQuery the agent for another config's keypair:\n\n```console\n$ kbs2 -c /some/other/config agent query\n```\n\n### `kbs2 agent unwrap`\n\n#### Usage\n\n```\nunwrap the current config's key in the running agent\n\nUSAGE:\n    kbs2 agent unwrap\n\nFLAGS:\n    -h, --help       Prints help information\n```\n\n#### Examples\n\nAdd the current config's key to the `kbs2` agent:\n\n```console\n$ kbs2 agent unwrap\n```\n\nAdd a custom config's key to the `kbs2` agent:\n\n```console\n$ kbs2 -c /path/to/config/dir agent unwrap\n```\n\n### `kbs2 rewrap`\n\n#### Usage\n\n```\nchange the master password on a wrapped key\n\nUSAGE:\n    kbs2 rewrap [FLAGS]\n\nFLAGS:\n    -f, --force        overwrite a previous backup, if one exists\n    -h, --help         Prints help information\n    -n, --no-backup    don't make a backup of the old wrapped key\n```\n\n#### Examples\n\nChange the password on the wrapped key in the default config:\n\n```console\n$ kbs2 rewrap\n```\n\nChange the password on a wrapped key in another config:\n\n```console\n$ kbs2 -c /path/to/config/dir rewrap\n```\n\nChange the password on a wrapped key without making a backup of the old wrapped key:\n\n```console\n$ kbs2 rewrap -n\n```\n\n### `kbs2 rekey`\n\n#### Usage\n\n```\nre-encrypt the entire store with a new keypair and master password\n\nUSAGE:\n    kbs2 rekey [FLAGS]\n\nFLAGS:\n    -h, --help         Prints help information\n    -n, --no-backup    don't make a backup of the old wrapped key, config, or store\n```\n\n#### Examples\n\nRe-key the default config and its store:\n\n```console\n$ kbs2 rekey\n```\n\nRe-key without making backups of the original keyfile, config, and store (**not** recommended):\n\n```console\n$ kbs2 rekey --no-backup\n```\n\nRe-key a different configuration and store:\n\n```console\n$ kbs2 -c /some/other/kbs2/conf/dir rekey\n```\n\n### `kbs2 config`\n\n#### Usage\n\n```\ninteract with kbs2's configuration file\n\nUSAGE:\n    kbs2 config \u003cSUBCOMMAND\u003e\n\nOPTIONS:\n    -h, --help    Print help information\n\nSUBCOMMANDS:\n    dump    dump the active configuration file as JSON\n    help    Print this message or the help of the given subcommand(s)\n```\n\n### `kbs2 config dump`\n\n#### Usage\n\n```\ndump the active configuration file as JSON\n\nUSAGE:\n    kbs2 config dump [OPTIONS]\n\nOPTIONS:\n    -h, --help      Print help information\n    -p, --pretty    pretty-print the JSON\n```\n\n#### Examples\n\nDump the current configuration as JSON:\n\n```console\n$ kbs2 config dump\n\n# pretty-print the dumped JSON\n$ kbs2 config dump --pretty\n```\n\n## Configuration\n\n`kbs2` stores its configuration in `\u003cconfig dir\u003e/kbs2/config.toml`, where `\u003cconfig dir\u003e` is determined\nby the the [XDG basedir specification](https://wiki.freedesktop.org/www/Specifications/basedir-spec/).\nOn Linux, it's probably `~/.config/kbs2`.\n\n**NOTE**: If `config.toml` isn't found in a configuration directory, `kbs2` attempts to use\n`kbs2.conf` in the same directory. This is for backwards compatibility, and will be removed\nonce `kbs2` has its first stable release.\n\n`config.toml` is TOML-formatted, and might look something like this after a clean start with `kbs2 init`:\n\n```toml\npublic-key = \"age1elujxyndwy0n9j2e2elmk9ns8vtltg69q620dr0sz4nu5fgj95xsl2peea\"\nkeyfile = \"/home/william/.config/kbs2/key\"\nstore = \"/home/william/.local/share/kbs2\"\n\n[commands.pass]\nclipboard-duration = 10\nclear-after = true\n```\n\n### `public-key` (default: generated by `kbs2 init`)\n\nThe `public-key` setting records the public half of the age keypair used by `kbs2`.\n\n`kbs2 init` pre-populates this setting; users should **not** modify it **unless** also modifying\nthe `keyfile` setting (e.g., to point to a pre-existing age keypair).\n\n### `keyfile` (default: generated by `kbs2 init`)\n\nThe `keyfile` setting records the path to the private half of the age keypair used by `kbs2`.\n\n`kbs2 init` pre-populates this setting; users should **not** modify it **unless** also modifying\nthe `public-key` setting (e.g., to point to a pre-existing age keypair).\n\n### `agent-autostart` (default: `true`)\n\nThe `agent-autostart` setting controls whether or not `kbs2` attempts to auto-start the\nauthentication agent (`kbs2 agent`) whenever encryption or decryption operations are requested.\nBy default, `kbs2 agent` will be started (unless it's already running).\n\nWhen set to `false`, `kbs2` will report an error if `kbs2 agent` is not running. In this case,\nusers should configure their system to launch `kbs2 agent` at login (or some other convenient time).\n\n### `wrapped` (default: `true`)\n\nThe `wrapped` settings records whether `keyfile` is a \"wrapped\" private key, i.e. whether\nthe private key itself is encrypted with a master password.\n\nBy default, `kbs2 init` asks the user for a master password and creates a wrapped key.\nSee the [`kbs2 init`](#kbs2-init) documentation for more information.\n\n### `store` (default: `$HOME/.local/share/kbs2`)\n\nThe `store` setting records the path to the secret store, i.e. where records are kept.\n\nUsers may modify this setting to store their records in a custom directory.\n\n### `pinentry` (default: `\"pinentry\"`)\n\nThe `pinentry` setting specifies the\n[Pinentry](https://gnupg.org/related_software/pinentry/index.html) binary to use for passphrase\noperations (i.e., prompting the user for their master password).\n\n`pinentry` is a reasonable default for most systems; macOS users may wish to use\n[`pinentry-mac`](https://github.com/GPGTools/pinentry-mac) instead.\n\n### `pre-hook` (default: `None`)\n\nThe `pre-hook` setting can be used to run a command before (almost) every `kbs2` invocation.\n\nThere are currently three cases where the configured `pre-hook` will *not* run:\n\n* `kbs2` (i.e., no subcommand)\n* `kbs2 agent` (and all `kbs2 agent` subcommands)\n* `kbs2 init`\n\nAll other subcommands, including custom subcommands, will cause the configured `pre-hook` to run.\n\nRead the [Hooks](#hooks) documentation for more details.\n\n### `post-hook` (default: `None`)\n\nThe `post-hook` setting can be used to run a command after (almost) every `kbs2` invocation,\n*on success*.\n\nThere are currently three cases where the configured `post-hook` will *not* run:\n\n* `kbs2` (i.e., no subcommand)\n* `kbs2 agent` (and all `kbs2 agent` subcommands)\n* `kbs2 init`\n\nAll other subcommands, including custom subcommands, will cause the configured `post-hook` to run.\n\nRead the [Hooks](#hooks) documentation for more details.\n\n### `error-hook` (default: `None`)\n\nThe `error-hook` setting can be used to run a command after (almost) every `kbs2` invocation,\n*on failure*.\n\nThere are currently three cases where the configured `error-hook` will *not* run:\n\n* `kbs2` (i.e., no subcommand)\n* `kbs2 agent` (and all `kbs2 agent` subcommands)\n* `kbs2 init`\n\nAll other subcommands, including custom subcommands, will cause the configured `error-hook` to run.\n\nThe `error-hook` setting passes a single argument to its hook, which is a string representation\nof the error that occurred.\n\nRead the [Hooks](#hooks) documentation for more details.\n\n### `reentrant-hooks` (default: `false`)\n\nThe `reentrant-hooks` setting controls whether hooks are run multiple times when a hook itself\nruns `kbs2`. By default, hooks are run only for the initial `kbs2` invocation.\n\nRead the [Reentrancy section](#reentrancy) of the [Hooks](#hooks) documentation for more details.\n\n### `commands.new.default-username` (default: `None`)\n\nThe `commands.new.default-username` setting allows the user to specify a default\nusername for logins created with `kbs2 new`.\n\nWhen specified, `kbs2 new`'s username prompt will fill in the default when the user presses\nonly `[enter]`.\n\n### `commands.new.pre-hook` (default: `None`)\n\nThe `commands.new.pre-hook` setting is like the global `pre-hook` setting, except that it runs\nimmediately before record creation during `kbs2 new` (and **only** `kbs2 new`).\n\n### `commands.new.post-hook` (default: `None`)\n\nThe `commands.new.post-hook` setting is like the global `post-hook` setting, except that it runs\nimmediately after record creation during `kbs2 new` (and **only** `kbs2 new`).\n\nThe `commands.new.post-hook` setting passes a single argument to its hook, which is the label\nof the record that was just created. For example, the following:\n\n```toml\n[commands.new]\npost-hook = \"~/.config/kbs2/hooks/post-new.sh\"\n```\n\n```bash\n# ~/.config/kbs2/hooks/post-new.sh\n\n\u003e\u00262 echo \"[+] created ${1}\"\n```\n\nwould produce:\n\n```console\n$ kbs2 new foo\n? Username? bar\n? Password? **********\n[+] created foo\n```\n\n### `commands.pass.clipboard-duration` (default: `10`)\n\nThe `commands.pass.clipboard-duration` setting determines the duration, in seconds, for persisting\na password stored in the clipboard via `kbs2 pass -c`.\n\n### `commands.pass.clear-after` (default: `true`)\n\nThe `commands.pass.clear-after` setting determines whether or not the clipboard is cleared at\nall after `kbs2 pass -c`.\n\nSetting this to `false` overrides any duration configured in `commands.pass.clipboard-duration`.\n\n### `commands.pass.pre-hook` (default: `None`)\n\nThe `command.pass.pre-hook` setting is like the global `pre-hook` setting, except that it runs\nimmediately before record access during `kbs2 pass` (and **only** `kbs2 pass`).\n\n### `command.pass.post-hook` (default: `None`)\n\nThe `command.pass.post-hook` setting is like the global `post-hook` setting, except that it runs\nimmediately after record access during `kbs2 pass` (and **only** `kbs2 pass`).\n\n### `command.pass.clear-hook` (default: `None`)\n\nThe `command.pass.clear-hook` is like the other `command.pass` hooks, except that it only runs\nafter the password has been cleared from the clipboard.\n\n### `commands.edit.editor` (default: `None`)\n\nThe `commands.edit.editor` setting controls which editor is used when opening a file with\n`kbs2 edit`. This setting takes precedence over the `$EDITOR` environment variable, which is\nused as a fallback.\n\nThis setting is allowed to contain flags. For example, the following would be split correctly:\n\n```toml\n[commands.edit]\neditor = \"subl -w\"\n```\n\n### `commands.edit.post-hook` (default: `None`)\n\nThe `command.edit.post-hook` setting is like the global `post-hook` setting, except that it runs\nimmediately after record editing during `kbs2 edit` (and **only** `kbs2 edit`).\n\n### `commands.rm.post-hook` (default: `None`)\n\nThe `command.rm.post-hook` setting is like the global `post-hook` setting, except that it runs\nimmediately after record removal during `kbs2 rm` (and **only** `kbs2 rm`).\n\nThe label of each record removed by `kbs2 rm` is passed as a separate argument to\nthe `post-hook`.\n\n### `commands.rename.post-hook` (default: `None`)\n\nThe `command.rename.post-hook` setting is like the global `post-hook` setting, except that it runs\nimmediately after record removal during `kbs2 rename` (and **only** `kbs2 rename`).\n\nThe record's old and new names are passed as separate arguments to the `post-hook`,\nin that order.\n\n### Generators\n\n`kbs2` supports *generators* for producing sensitive values, allowing users to automatically\ngenerate passwords and environment variables.\n\nGenerators are configured as entries in `[[generators]]`.\n\nThe following configures an generator named \"hexonly\" that generates a secret from the\nconfigured alphabet and length.\n\n```toml\n[[generators]]\nname = \"hexonly\"\nalphabets = [\"0123456789abcdef\"]\nlength = 16\n```\n\nBy default, `kbs2`'s configuration includes a `default` generator that looks\nsomething like this:\n\n```toml\n[[generators]]\nname = \"default\"\n# kbs2 samples from each alphabet, to ensure a good distribution of symbols\nalphabets = [\n    \"abcdefghijklmnopqrstuvwxyz\",\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\n    \"0123456789\",\n    \"(){}[]-_+=\",\n]\nlength = 16\n```\n\nThese generators can be used with `kbs2 new`. For example, the following will\nuse the `hexonly` generator when the user presses `[enter]` instead of manually\nentering a password.\n\n```console\n$ kbs2 new -G hexonly pets.com\n? Username? catlover2000\n? Password?\n[Press [enter] to auto-generate]\n```\n\n## Customization\n\nBeyond the configuration above, `kbs2` offers several avenues for customization.\n\n### Custom commands\n\n`kbs2` supports `git`-style subcommands, allowing you to easily write your own.\n\nFor example, running the following:\n\n```\n$ kbs2 frobulate --xyz\n```\n\nwill cause `kbs2` to run `kbs2-frobulate --xyz`. Custom commands are allowed to read from and\nwrite to the config file under the `[commands.ext.\u003cname\u003e]` hierarchy.\n\nWhen run via `kbs2`, custom commands receive the following environment variables:\n\n* `KBS2_CONFIG_DIR`: The path to the configuration directory that `kbs2` itself was loaded with.\nSubcommands can use this path to read the current configuration file or any other content stored\nin the configuration directory.\n    * **NOTE**: Subcommands are encouraged to use `kbs2 config dump` to read the configuration\n    state instead of attempting to find the correct file manually.\n* `KBS2_STORE`: The path to the secret store.\n* `KBS2_SUBCOMMAND`: Always set to `1`. This can be used to determine whether a subcommand was run\nvia `kbs2` (e.g. `kbs2 foo`) versus directly (e.g. `kbs2-foo`).\n* `KBS2_MAJOR_VERSION`, `KBS2_MINOR_VERSION`, `KBS2_PATCH_VERSION`: The major, minor, and patch\nnumbers for the version of `kbs2` that executed this subcommand. Subcommands can use these numbers\nto enforce running under a minimum (or maximum) version of `kbs2`.\n\nThe [contrib/ext-cmds](contrib/ext-cmds/) directory contains several useful external commands.\n\n### Hooks\n\n`kbs2` exposes hook-points during the lifecycle of an invocation, allowing users to\ninject additional functionality or perform their own bookkeeping.\n\n#### The hook API\n\nAll hooks, whether pre- or post-, have the following behavior:\n\n* Hooks **do not** inherit `stdin` or `stdout` from the parent `kbs2` process\n* Hooks **do** inherit `stderr` from the parent process, and *may* use it to print anything\nthey please\n* Hooks **always** run from the `store` directory\n* Hooks are run with `KBS2_HOOK=1` in their environment and with `KBS2_CONFIG_DIR` set to the\nconfiguration directory that the original `kbs2` command was loaded with\n* An error exit from a hook (or failure to execute) causes the entire `kbs2` command to fail\n\nHooks *may* introduce additional behavior, so long as it does not conflict with the above.\nAny additional hook behavior is documented under that hook's configuration setting.\n\n#### Reentrancy\n\n`kbs2`'s hooks are non-reentrant by default.\n\nTo understand what that means, imagine the following hook setup:\n\n```toml\npre-hook = \"~/.config/kbs2/hooks/pre.sh\"\n```\n\n```bash\n# ~/.config/kbs2/hooks/pre.sh\n\nkbs2 some-other-command\n```\n\nand then:\n\n```console\n$ kbs2 list\n```\n\nIn this setting, most users would expect `pre.sh` to be run exactly once: on `kbs2 list`.\n\nHowever, naively, it *ought* to execute twice: once for `kbs2 list`, and again for\n`kbs2 some-other-command`. In other words, naively, hooks would *reenter* themselves whenever\nthey use `kbs2` internally.\n\nMost users find this confusing and would consider it an impediment to hook writing, so `kbs2`\ndoes **not** do this by default. However, **should** you wish for reentrant hooks, you have two\noptions:\n\n* You can set `reentrant-hooks` to `true` in the configuration. This will make *all* hooks\nreentrant \u0026mdash; it's all or nothing, intentionally.\n* You can `unset` or otherwise delete the `KBS2_HOOK` environment variable in your hook\nbefore running `kbs2` internally. This allows you to control which hooks cause reentrancy.\n**Beware**: `KBS2_HOOK` is an implementation detail! Unset it at your own risk!\n\n### Managing your key and master password\n\n#### Rewrapping and rekeying\n\n`kbs2` supports two basic options for managing the (wrapped) key that encrypts all records\nin the secret store: *rewrapping* and *rekeying*.\n\n*Rewrapping* means changing the password on your wrapped key. Rewrapping **does not**\nmodify the underlying key itself, which means that your individual records in the store\n**do not** change. Rewrapping is done with the [`kbs2 rewrap`](#kbs2-rewrap) command.\n\nYou **should** rewrap under the following (non-exhaustive) conditions:\n\n* You're doing a routine update of your master password\n* You believe that your master password has been disclosed, but **not** the underlying wrapped key\n\n*Rekeying* means changing the wrapped key itself, and consequently re-encrypting every record\nwith the new wrapped key. When rekeying you *can* choose the same master password as the old key.\nHowever, you *should* choose a new password. **Unlike** rewrapping, rekeying **does** change\nthe individual records in your store, and makes them no longer decryptable with your previous\nkey. Rekeying is done with the [`kbs2 rekey`](#kbs2-rekey) command.\n\nYou **should** rekey under the following (non-exhaustive) conditions:\n\n* You believe that your underlying wrapped key has been disclosed\n* You're sharing a `kbs2` to a new device, and you'd like that device to have its own wrapped key\n\nRekeying is a more drastic operation than rewrapping: it involves rewriting the keypair,\nthe `kbs2` config, and every record in the store. This means it comes with some technical caveats:\n\n* `kbs2 rekey` does not preserve the layout of your config file. Users should be mindful of this\nwhen rekeying.\n\n* `kbs2 rekey` makes a backup of the secret store by copying each record in the store to a\nbackup folder. Anything in the secret store that is not a record\n(like a metadata or revision control directory, or a hidden file) is **not** copied during backup.\nRekeying causes `kbs2` to write the newly encrypted records into the same store, so any non-record\nmembers of the store will remain unmodified.\n\n## Why another password manager?\n\nNo good reason. See the [history section](#history).\n\n## Technical details\n\n### Threat model\n\n`kbs2`'s threat model is similar to that of most password and secret managers. In particular:\n\n* `kbs2` does *not* attempt to defend against the `root` user *or* arbitrary code executed by the\ncurrent user.\n* `kbs2` tries to avoid operations that would result in secret material (i.e. the private key\nand the decrypted contents of records) being saved or cached on disk, but does *not* attempt to\npresent the consumers of secret material from doing so.\n* `kbs2`, by default, attempts to prevent offline private key extraction by encrypting the private\nkey at rest with a master password. `kbs2` does *not* attempt to prevent the user from mishandling\ntheir master password.\n\n### Cryptography\n\n`kbs2` does **not** implement any cryptography on its own \u0026mdash; it uses *only* the cryptographic\nprimitives supplied by an [age](https://github.com/FiloSottile/age) implementation. In particular,\n`kbs2` uses the [rage implementation](https://github.com/str4d/rage) of age.\n\nThe particulars of `kbs2`'s cryptographic usage are as follows:\n\n* Every `kbs2` configuration file specifies a symmetric keypair. The public key is\nstored in the `public-key` configuration setting, while the private key is stored in the file\nreferenced by the `keyfile` setting.\n* By default, `kbs2` \"wraps\" (i.e. encrypts) the private key with a master password. This makes\noffline key extraction attacks more difficult (although not impossible) and makes the consequences\nof wrapped private key disclosure less severe. Users *may* choose to use a non-wrapped key by\npassing `--insecure-not-wrapped` to `kbs2 init`.\n\n### Key unwrapping and persistence\n\nAs mentioned under [Threat Model](#threat-model) and [Cryptography](#cryptography), `kbs2` uses\na wrapped private key by default.\n\nWithout any persistence, wrapped key usage would be tedious: the user would have to re-enter\ntheir master password on each `kbs2` action, defeating the point of having a secret manager.\n\nTo avoid this, `kbs2` establishes persistence of the unwrapped key with an authentication agent:\nrunning `kbs2 agent` will start a daemon in the background, which subsequent `kbs2` invocations\ncan connect to (as needed) via a Unix domain socket. By default, running `kbs2 agent`\nwill prompt the user for the currently configured key's master password. Users can add additional\nunwrapped keys to their running agent by invoking [`kbs2 agent unwrap`](#kbs2-agent-unwrap).\n\n## Hacking\n\nHacking on `kbs2` is relatively straightforward. To build a fully functional development copy,\njust use `cargo build` in the repository root:\n\n```console\n$ cargo build\n$ ./target/debug/kbs2 --help\n```\n\nOf note: some functionality in the age crate has pathological performance in debug builds.\nIn particular, decryption and key unwrapping are known to be particularly slow.\n\nTo avoid this, use a release build:\n\n```console\n$ cargo build --release\n$ ./target/release/kbs2 --help\n```\n\n### Logging\n\n`kbs2` uses `log` and `env_logger` for logging. You can past `RUST_LOG=debug` in your environment\nto enable debug logging:\n\n```console\n$ RUST_LOG=debug ./target/release/kbs2 list -k login\n```\n\nSee the [`env_logger` documentation](https://docs.rs/env_logger/) for more possible `RUST_LOG` values.\n\n## History\n\nTL;DR: `kbs2` is short for \"[KBSecret](https://github.com/kbsecret/kbsecret) 2\".\n\nIn 2017, I wrote KBSecret as a general purpose secret manager for the Keybase ecosystem.\n\nKBSecret was written in Ruby and piggybacked off of Keybase + KBFS for encryption, storage,\nand synchronization. It was also *extremely* flexible, allowing user-defined record types, secret\nsharing between users and teams, and a variety of convenient and well-behaved CLI tools for\nintegration into my development ecosystem.\n\nUnfortunately, KBSecret was also *extremely* slow: it was written in\n[obnoxiously metaprogrammed Ruby](https://github.com/kbsecret/kbsecret/blob/20ac2bf/lib/kbsecret/config.rb#L175),\nrelied heavily on re-entrant CLIs, and was further capped by the latency and raw performance of KBFS\nitself.\n\nHaving a slow secret manager was fine for my purposes, but I\n[no longer trust](https://keybase.io/blog/keybase-joins-zoom) that Keybase (and KBFS) will continue\nto receive the work they require. I also no longer have the time to maintain KBSecret's (slowly)\ndeteriorating codebase.\n\n`kbs2` is my attempt to reproduce the best parts of KBSecret in a faster language. Apart from the\nname and some high-level design decisions, it shares nothing in common with the original KBSecret.\nIt's only named `kbs2` because I'm used to typing \"kbs\" in my terminal.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwoodruffw%2Fkbs2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwoodruffw%2Fkbs2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwoodruffw%2Fkbs2/lists"}