summaryrefslogtreecommitdiff
path: root/posts/pwutil.md
blob: 61a3823d0f0ef3b81765ef01d8ae3f3b1c11be95 (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
123
124
125
126
127
128
129
130
131
132
% A Tool to Manage a Set of YAML Objects Representing Account Information — pwutil

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](git://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 readable](https://en.wikipedia.org/wiki/YAML) backstore
  * [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

## 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
│   ├── Encfs.hs
│   ├── 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:
~~~ {.numberLines}
{
  packageOverrides = pkgs: {
    pwutil = pkgs.callPackage /path/to/pwutil.nix {};
  };
}
~~~

### `Types.hs`

`PWLocation` describes the location of a file containing a YAML object mapping human readable identifiers to account information.
`encryption`, which has essentially the same signature as [`withFile`](http://hackage.haskell.org/package/base-4.8.0.0/docs/System-IO.html#v:withFile) wraps all access to the file.
This in an extremely powerful way to deal with any kind of encryption desired (currently I implemented automatic mounting of an [EncFs](http://en.wikipedia.org/wiki/EncFS) container and `plain`, which does nothing.
`create` is used to try and create the location once should access fail due to a file [not existing](http://hackage.haskell.org/package/base-4.8.0.0/docs/System-IO-Error.html#v:doesNotExistErrorType).

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

import System.IO (Handle(..), IOMode(..))
import Control.Monad.State
import qualified Data.Map as M
import Data.Yaml

data PWLocation = PWLocation
                  { path :: FilePath
                  , encryption :: Encryption
                  , create :: IO ()
                  }

instance Show PWLocation where
  show loc = show $ path loc

type Encryption = FilePath -> IOMode -> (Handle -> IO ()) -> IO ()

type PW = StateT PWConfig IO

data PWConfig = PWConfig
               { location :: PWLocation
               , generators :: M.Map String Generator
               }

type Generator = [String] -> IO Value
~~~


### `pwutil.hs`

is, in a [xmonad](http://xmonad.org) kind of way, the configuration file.

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

import System.FilePath ((</>))
import qualified Data.Map as M
import System.Directory (getHomeDirectory)

pWLocation :: IO PWLocation
pWLocation = do
  h <- getHomeDirectory
  return PWLocation { path = h </> "accounts.yaml"
                    , encryption = plain
                    , create = createFile $ h </> "accounts.yaml"
                    }

myGenerators :: M.Map String Generator
myGenerators = M.empty

main :: IO ()
main = do
  myLocation <- pWLocation
  runPW (PWConfig { location = myLocation, generators = myGenerators }) pwutil
~~~

### `Encfs.hs`

shall serve as an example for a module providing an encryption wrapper.
It exports

~~~{.haskell}
encfs :: Encfs -> Encryption
encfs (Encfs backStore mountpoint) = …
~~~

Upon execution it checks whether `mountpoint` is already mounted.
If not it executes `encfs backStore mountpoint` interactively and calls `fusermount -u` after completion.