summaryrefslogtreecommitdiff
path: root/provider/posts/pwutil.md
blob: 17d3e496e95134373de9835b41add8520d384aa8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
---
title: A Tool to Manage a Set of YAML Objects Representing Account Information — pwutil
published: 2015-04-07
---

A long time ago I wrote a bunch of scripts (first in bash, then zsh, and later perl) to manage a, sometimes encrypted, file containing account information I get asked to create and remember on a daily basis—accounts for shopping websites spring to mind.

[pwutil](https://git.yggdrasil.li/pwutil) is the newest iteration in this line of bunches of scripts.

## Features

  * Support for embedding common operation in any kind of record keeping

    Thus support for almost any encryption known to man (with absolutely no online security), version control, and synchronisation
  * [Human read- and writeable](https://en.wikipedia.org/wiki/YAML) backstore
  * Machine parseable output
  * [Command Line Interface](https://en.wikipedia.org/wiki/Command-line_interface)-only
  * New accounts can be partially generated by user defined functions with out of the box support for [pwgen](http://sourceforge.net/projects/pwgen/) and SSH

## Usage

~~~
pwget [<searchTerm> …]
Looks up and returns all accounts which contain any <searchTerm> anywhere in their representation — case insensitive.

pwadd [[--gen-<generator> [<generatorArgument> …] …] --] <identifier> [<attributeKey> <attributeValue> …]
Adds an account to the store — does not overwrite.
~~~

## Documentation

I shall document the project in a partial and file-wise fashion—amendments available on request.

### Structure

~~~ {#DirTree}
pwutil
├── default.nix
├── PWAdd.hs
├── PWGet.hs
├── PWUtil
│   ├── Extra
│   │   ├── PWGen.hs
│   │   └── SSHCmd.hs
│   ├── Types.hs
│   └── Util.hs
├── pwutil.hs
├── PWUtil.hs
└── pwutil.nix
~~~

### `pwutil.nix`
is a [nix](https://nixos.org/nix) expression allowing easy installation using the nix package manager.
A `~/.nixpkgs/config.nix` allowing one to do so might look thus:

~~~
{
  packageOverrides = pkgs: {
    pwutil = pkgs.callPackage /path/to/pwutil.nix {};
  };
}
~~~

The derivation takes some arguments (write those in `{}` above):

`main ? null`
  ~ Overwrite `pwutil.hs` with a file path

`with<Package> ? false`
  ~ `<Package>` is one of Pwgen, or Ssh a the current time.
    If `true` wraps executables to have `$PATH` include `<Package>`.

### `Types.hs`

Introducing `PW` (much as [xmonad](https://xmonad.org) did with `X`) is an easy way to keep track of the `PWConfig` without resorting to function arguments.
`BackStore` is our (new and improved) way of encapsulating store access in a totally customisable way—`plain`, which is essential `readFile` and `writeFile` as provided by `ByteString`, is provided for convenience in `Util.hs`.
`PWConfig` most importantly contains a definition of generators (called by passing `--gen-…` to `pwadd`).

~~~ {#Types.hs .haskell}
module PWUtil.Types (
  PW(..),
  BackStore(..),
  PWConfig(..),
  Generator(..)
  ) where

import Control.Monad.State
import qualified Data.Map as M
import Data.Yaml
import Data.ByteString

type PW = StateT PWConfig IO

data BackStore = BackStore
                 { readContents :: PW ByteString
                 , writeContents :: ByteString -> PW ()
                 }

data PWConfig = PWConfig
                { generators :: M.Map String Generator
                , backstore :: BackStore
                }
                      
type Generator = [String] -> PW Value
~~~


### `pwutil.hs`

is, in a [xmonad](http://xmonad.org) kind of way, the configuration file—the shipped default is reproduced below as a template for custom configs.

~~~ {#pwutil.hs .haskell}
import PWUtil

import System.FilePath ((</>))
import System.Directory (getHomeDirectory)

main :: IO ()
main = do
  h <- getHomeDirectory
  runPW (emptyConfig { backstore = plain (h </> "accounts.yaml") }) pwutil
~~~