summaryrefslogtreecommitdiff
path: root/posts
diff options
context:
space:
mode:
Diffstat (limited to 'posts')
-rw-r--r--posts/pwutil.md77
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~~~
19pwget [<searchTerm> …] 20pwget [<searchTerm> …]
20Looks up and returns all accounts whose identifier contains any <searchTerm> — case insensitive. 21Looks up and returns all accounts which contain any <searchTerm> anywhere in their representation — case insensitive.
21 22
22pwadd [[--gen-<generator> [<generatorArgument> …] …] --] <identifier> [<attributeKey> <attributeValue> …] 23pwadd [[--gen-<generator> [<generatorArgument> …] …] --] <identifier> [<attributeKey> <attributeValue> …]
23Adds an account to the store — does not overwrite. 24Adds 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. 72Introducing `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`.
74This 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}
78module PWUtil.Types ( 77module 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
86import System.IO (Handle(..), IOMode(..))
87import Control.Monad.State 84import Control.Monad.State
88import qualified Data.Map as M 85import qualified Data.Map as M
89import Data.Yaml 86import Data.Yaml
90 87import Data.ByteString
91data PWLocation = PWLocation
92 { path :: FilePath
93 , encryption :: Encryption
94 , create :: IO ()
95 }
96
97instance Show PWLocation where
98 show loc = show $ path loc
99
100type Encryption = FilePath -> IOMode -> (Handle -> IO ()) -> IO ()
101 88
102type PW = StateT PWConfig IO 89type PW = StateT PWConfig IO
103 90
104data PWConfig = PWConfig 91data BackStore = BackStore
105 { location :: PWLocation 92 { readContents :: PW ByteString
106 , generators :: M.Map String Generator 93 , writeContents :: ByteString -> PW ()
107 } 94 }
108 95
109type Generator = [String] -> IO Value 96data PWConfig = PWConfig
97 { generators :: M.Map String Generator
98 , backstore :: BackStore
99 }
100
101type Generator = [String] -> PW Value
110~~~ 102~~~
111 103
112 104
113### `pwutil.hs` 105### `pwutil.hs`
114 106
115is, in a [xmonad](http://xmonad.org) kind of way, the configuration file. 107is, 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}
118import PWUtil 110import PWUtil
119 111
120import System.FilePath ((</>)) 112import System.FilePath ((</>))
121import qualified Data.Map as M
122import System.Directory (getHomeDirectory) 113import System.Directory (getHomeDirectory)
123 114
124pWLocation :: IO PWLocation
125pWLocation = do
126 h <- getHomeDirectory
127 return PWLocation { path = h </> "accounts.yaml"
128 , encryption = plain
129 , create = createFile $ h </> "accounts.yaml"
130 }
131
132myGenerators :: M.Map String Generator
133myGenerators = M.empty
134
135main :: IO () 115main :: IO ()
136main = do 116main = 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
143shall serve as an example for a module providing an encryption wrapper.
144It exports
145
146~~~{.haskell}
147encfs :: Encfs -> Encryption
148encfs (Encfs backStore mountpoint) = …
149~~~ 119~~~
150
151Upon execution it checks whether `mountpoint` is already mounted.
152If not it executes `encfs backStore mountpoint` interactively and calls `fusermount -u` after completion.