---
# System prepended metadata

title: Password manager

---

# Password manager

## Introduction

[`pass`](https://www.passwordstore.org/) is an amazing tool which can be used to store and manage passwords, very easy to use and minimal dependencies, pretty much just gpg2 and git which is present in almost all developer's environments, pretty cross platform and a good ecosystem of plugins for non-cli usecases.

## Motivations
There are some things I would like to see and is not very simple/ergonomic to build in pass. For example

#### Ability to specify backends for the password store 
Right now, `pass` stores the password on the filesystem in a nested directory strucutre. There are some formats that may make sense for some use cases, 
* `sqlite3` file like other password managers/browsers
* A different filesystem implementation (it's already possible but say for example, but if we are using `encryptfs`, the additional encryption envelope may be redundant).

#### Using a different backup method
The default is a `git` repo, but it could be a 
* remote filesystem/ftp server
* s3 bucket
* anything else connected over a network.

#### Using a different cipher or encryption engines
`pass` explicitly uses `gpg2`. We would want to be able to use 
* other symmetric ciphers
* other tools like [`age`](https://github.com/FiloSottile/age) or just plain old openssl.

#### Ability to rotate encryption key or migrate encryption engines
The `gpg` key has an expiration, or better said, it's good to have an expiration key and there seems nothing which allows rotation of all secrets.

We would also want to have the ability to move from say gpg2 to AES or just delegate all of it to `age` with minimal effort.

We would still want to retain the plugin based design or pass which is just awesome and how it handles plugins.

## Sample Usage

Simple CRUD operations
```bash=
$ pass add "location:username" --description "optional description"
Enter Password: 
Re-enter Password: 

$ pass read "location:username"
Description: optional description
Password copied to your clipboard, will be cleared in 45s

$ pass update "location:username" --description "if you need to change"
Old Password: 
New Password: 
Re-enter Password: 

$ pass delete "location:username"
Description: if you need to change
Do you really want to delete password for "username" [y/N]: 

$ pass copy "location1:username1" "location2:username2"
$ pass mv "location1:username1" "location2:username2"
```
Optional arguments for each case
```bash=
$ pass add --namespace "personal" "location:username"
Enter Password:
Re-enter Password:
```
There are some assumptions
* The namespace by default is "default"
* The encryption engine can only be set at init phase
* The storage engine can only be set at init phase

```bash=
$ pass init
Enter default namespace (Press return for "default"):
Select Encryption Engines
[1] openssl aes (128 bit CTR mode) v0.0.1
[2] gnupg2 v2.3.1
[3] age v1.0.0
Input: 3

# Invoke the age plugin to setup

Select Storage Engine
[1] git v1.0.0
[2] ftp v1.2.3
[3] s3 v0.1.0
[4] http file server v0.0.1
[5] google drive v4.3.2
Input: 1

# invoke the git plugin to setup

Detected existing source at ~/.pass/data, migrating...
Enter decryption password: 
Migrated 53 passwords!

Config written at ~/.pass/config.json
```

Sync usage
```bash=
$ pass sync
```



## Plugin Spec

### Init Interface
The plugin should support the following arg
```bash=
~/.pass/plugins/plugin_name init
```
The plugin can handle their init and store their state if required in the folder `~/.pass/config/plugin_name/`.

### Plugin informational Interface
The plugin should be able to respond to 
```bash=
./plugin_name --desc
./plugin_name --version
```
and display information about itself (to be presented during init). The plugin should also be able to 
```bash=
./plugin_name --help
```
and display the help information as it may have different mechanisms for performing it's operation.

### Encryption Interface
Since we are going to use a wide variety of tools for encryption, there needs to be an interface that this tool will call.

```
$ pass add --namespace default "location:username"
Enter Password: 
Re-enter Password: 
```
Pass would lookup the plugin which will be used for encryption from the `init` stage and then call an equivalent of

```bash=
~/.pass/plugins/encrypt/openssl \
    "namespace" \
    "location" \
    "username" \
    $(echo -ne "password"|base64) --encrypt
```
The plugin shall dump the encrypted password in the following form with atleast the following fields.
```json=
{
    "plugin": {
        "name": "openssl",
        "version": "0.0.1",
        "build": "git-commit-id"
    },
    "metadata": {
        "timestamp": "2021-12-04Z01:02:03",
        "username": "user",
        "hostname": "my-test-machine"
    },
    "data": {
        "description": "this is a password for example.com",
        "location": "example.com",
        "username": "username",
        "password": "Zm9vYmFyCg=="
    }
}
```
the destination of the file would be 
```
~/.pass/data/namespace/location/username.json
```
while decryption
```bash=
$ pass read --namespace "default" "location:username"
```
The tool would look up the plugin responsible by constructing the file `~/.pass/data/namespace/location/username.json` and then reading the JSON file, it would find the plugin and then send the values.

```bash=
~/.pass/plugins/encrypt/openssl \
    "namespace" \
    "location" \
    "username" --decrypt --version "0.0.1"
```
Note: it's sending `--version` to allow the plugin to be able to ensure or fail due to compatibility issues.

### Storage Interface
The storage plugins should be able to store/retrieve/dump passwords. The underlying storage and schema is upto the plugin to handle.
```bash=
$ pass sync
```
The tool will lookup the storage plugin and then run, 
```bash=
./pass/plugins/storage/git ~/.pass/data
```
Just pass the root location where all the data is stored and the plugin should handle how it's going to publish the data.

Note: Any additional arguments that were not parsed by the tool will be passed as it is to the plugin.

### Passthrough plugins
For additional functionality, there is a mode in `pass` that acts as a transparent interfae and sends the I/O as is, that's simple, 
```bash=
$ pass plugin --foo bar --baz qux ... 
```
The plugin will be invoked as is with additional settings, eg setting the working directory as `~/.pass` for eaiser lookups.
```bash=
cd ~/.pass
~/.pass/plugins/ext/plugin --foo bar --baz qux ...
```