diff options
Diffstat (limited to 'posts')
-rw-r--r-- | posts/pwutil.md | 77 |
1 files changed, 22 insertions, 55 deletions
diff --git a/posts/pwutil.md b/posts/pwutil.md index 69a780d..176ffdc 100644 --- a/posts/pwutil.md +++ b/posts/pwutil.md | |||
@@ -9,7 +9,8 @@ A long time ago I wrote a bunch of scripts (first in bash, then zsh, and later p | |||
9 | * Support for embedding common operation in any kind of record keeping | 9 | * Support for embedding common operation in any kind of record keeping |
10 | 10 | ||
11 | Thus support for almost any encryption known to man (with absolutely no online security), version control, and synchronisation | 11 | Thus support for almost any encryption known to man (with absolutely no online security), version control, and synchronisation |
12 | * [Human readable](https://en.wikipedia.org/wiki/YAML) backstore | 12 | * [Human read- and writeable](https://en.wikipedia.org/wiki/YAML) backstore |
13 | * Machine parseable output | ||
13 | * [Command Line Interface](https://en.wikipedia.org/wiki/Command-line_interface)-only | 14 | * [Command Line Interface](https://en.wikipedia.org/wiki/Command-line_interface)-only |
14 | * 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 | 15 | * 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 |
15 | 16 | ||
@@ -17,7 +18,7 @@ A long time ago I wrote a bunch of scripts (first in bash, then zsh, and later p | |||
17 | 18 | ||
18 | ~~~ | 19 | ~~~ |
19 | pwget [<searchTerm> …] | 20 | pwget [<searchTerm> …] |
20 | Looks up and returns all accounts whose identifier contains any <searchTerm> — case insensitive. | 21 | Looks up and returns all accounts which contain any <searchTerm> anywhere in their representation — case insensitive. |
21 | 22 | ||
22 | pwadd [[--gen-<generator> [<generatorArgument> …] …] --] <identifier> [<attributeKey> <attributeValue> …] | 23 | pwadd [[--gen-<generator> [<generatorArgument> …] …] --] <identifier> [<attributeKey> <attributeValue> …] |
23 | Adds an account to the store — does not overwrite. | 24 | Adds an account to the store — does not overwrite. |
@@ -35,7 +36,6 @@ pwutil | |||
35 | ├── PWAdd.hs | 36 | ├── PWAdd.hs |
36 | ├── PWGet.hs | 37 | ├── PWGet.hs |
37 | ├── PWUtil | 38 | ├── PWUtil |
38 | │ ├── Encfs.hs | ||
39 | │ ├── Extra | 39 | │ ├── Extra |
40 | │ │ ├── PWGen.hs | 40 | │ │ ├── PWGen.hs |
41 | │ │ └── SSHCmd.hs | 41 | │ │ └── SSHCmd.hs |
@@ -64,89 +64,56 @@ The derivation takes some arguments (write those in `{}` above): | |||
64 | ~ Overwrite `pwutil.hs` with a file path | 64 | ~ Overwrite `pwutil.hs` with a file path |
65 | 65 | ||
66 | `with<Package> ? false` | 66 | `with<Package> ? false` |
67 | ~ `<Package>` is one of Encfs, Pwgen, or Ssh a the current time. | 67 | ~ `<Package>` is one of Pwgen, or Ssh a the current time. |
68 | If `true` wraps executables to have `$PATH` include `<Package>`. | 68 | If `true` wraps executables to have `$PATH` include `<Package>`. |
69 | 69 | ||
70 | ### `Types.hs` | 70 | ### `Types.hs` |
71 | 71 | ||
72 | `PWLocation` describes the location of a file containing a YAML object mapping human readable identifiers to account information. | 72 | 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. |
73 | `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. | 73 | `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`. |
74 | 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. | 74 | `PWConfig` most importantly contains a definition of generators (called by passing `--gen-…` to `pwadd`). |
75 | `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). | ||
76 | 75 | ||
77 | ~~~ {#Types.hs .haskell .numberLines} | 76 | ~~~ {#Types.hs .haskell .numberLines} |
78 | module PWUtil.Types ( | 77 | module PWUtil.Types ( |
79 | PWLocation(..), | ||
80 | Encryption(..), | ||
81 | PW(..), | 78 | PW(..), |
79 | BackStore(..), | ||
82 | PWConfig(..), | 80 | PWConfig(..), |
83 | Generator(..) | 81 | Generator(..) |
84 | ) where | 82 | ) where |
85 | 83 | ||
86 | import System.IO (Handle(..), IOMode(..)) | ||
87 | import Control.Monad.State | 84 | import Control.Monad.State |
88 | import qualified Data.Map as M | 85 | import qualified Data.Map as M |
89 | import Data.Yaml | 86 | import Data.Yaml |
90 | 87 | import Data.ByteString | |
91 | data PWLocation = PWLocation | ||
92 | { path :: FilePath | ||
93 | , encryption :: Encryption | ||
94 | , create :: IO () | ||
95 | } | ||
96 | |||
97 | instance Show PWLocation where | ||
98 | show loc = show $ path loc | ||
99 | |||
100 | type Encryption = FilePath -> IOMode -> (Handle -> IO ()) -> IO () | ||
101 | 88 | ||
102 | type PW = StateT PWConfig IO | 89 | type PW = StateT PWConfig IO |
103 | 90 | ||
104 | data PWConfig = PWConfig | 91 | data BackStore = BackStore |
105 | { location :: PWLocation | 92 | { readContents :: PW ByteString |
106 | , generators :: M.Map String Generator | 93 | , writeContents :: ByteString -> PW () |
107 | } | 94 | } |
108 | 95 | ||
109 | type Generator = [String] -> IO Value | 96 | data PWConfig = PWConfig |
97 | { generators :: M.Map String Generator | ||
98 | , backstore :: BackStore | ||
99 | } | ||
100 | |||
101 | type Generator = [String] -> PW Value | ||
110 | ~~~ | 102 | ~~~ |
111 | 103 | ||
112 | 104 | ||
113 | ### `pwutil.hs` | 105 | ### `pwutil.hs` |
114 | 106 | ||
115 | is, in a [xmonad](http://xmonad.org) kind of way, the configuration file. | 107 | 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. |
116 | 108 | ||
117 | ~~~ {#pwutil.hs .haskell .numberLines} | 109 | ~~~ {#pwutil.hs .haskell .numberLines} |
118 | import PWUtil | 110 | import PWUtil |
119 | 111 | ||
120 | import System.FilePath ((</>)) | 112 | import System.FilePath ((</>)) |
121 | import qualified Data.Map as M | ||
122 | import System.Directory (getHomeDirectory) | 113 | import System.Directory (getHomeDirectory) |
123 | 114 | ||
124 | pWLocation :: IO PWLocation | ||
125 | pWLocation = do | ||
126 | h <- getHomeDirectory | ||
127 | return PWLocation { path = h </> "accounts.yaml" | ||
128 | , encryption = plain | ||
129 | , create = createFile $ h </> "accounts.yaml" | ||
130 | } | ||
131 | |||
132 | myGenerators :: M.Map String Generator | ||
133 | myGenerators = M.empty | ||
134 | |||
135 | main :: IO () | 115 | main :: IO () |
136 | main = do | 116 | main = do |
137 | myLocation <- pWLocation | 117 | h <- getHomeDirectory |
138 | runPW (PWConfig { location = myLocation, generators = myGenerators }) pwutil | 118 | runPW (emptyConfig { backstore = plain (h </> "accounts.yaml") }) pwutil |
139 | ~~~ | ||
140 | |||
141 | ### `Encfs.hs` | ||
142 | |||
143 | shall serve as an example for a module providing an encryption wrapper. | ||
144 | It exports | ||
145 | |||
146 | ~~~{.haskell} | ||
147 | encfs :: Encfs -> Encryption | ||
148 | encfs (Encfs backStore mountpoint) = … | ||
149 | ~~~ | 119 | ~~~ |
150 | |||
151 | Upon execution it checks whether `mountpoint` is already mounted. | ||
152 | If not it executes `encfs backStore mountpoint` interactively and calls `fusermount -u` after completion. | ||