diff options
author | Eugene Crosser <crosser@average.org> | 2016-07-23 15:51:37 +0300 |
---|---|---|
committer | Eugene Crosser <crosser@average.org> | 2016-07-23 15:51:37 +0300 |
commit | 99934d35b99fc2188c962a53cf7bc0f8b83fe58f (patch) | |
tree | 62a96f207d7fe9af99cc660b27757d817961c94c /contrib/oisafe2pstore/oisafe2pstore.hs | |
parent | a22b5573ec4ed9412e5cd8a17f5fc1584d17de7f (diff) |
oisafe2pstore.hs: script to migrate from OI Safe
Quick and dirty Haskell script that converts OI Safe export CSV
format into the password-store repository format. After conversion,
you will need to `git add` the newly generated files, commit and
push them to the server. Then pull or sync on the Android device.
Signed-off-by: Eugene Crosser <crosser@average.org>
Diffstat (limited to 'contrib/oisafe2pstore/oisafe2pstore.hs')
-rw-r--r-- | contrib/oisafe2pstore/oisafe2pstore.hs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/contrib/oisafe2pstore/oisafe2pstore.hs b/contrib/oisafe2pstore/oisafe2pstore.hs new file mode 100644 index 00000000..0417fc0a --- /dev/null +++ b/contrib/oisafe2pstore/oisafe2pstore.hs @@ -0,0 +1,85 @@ +{- + oisafe2psore - Quick and dirty script to convert OI Safe export CSV + into the password-store tree format. + + Copyright 2016 Eugene Crosser + + License: BSD, Apache or GPLv3 - chose whatever suits you. + + You will need to adjust paths to the GnuPG program and the CSV + file produced by OI Safe. Also fill in the PGP key I.D. + Description becomes the file name. '*' in the Description is + converted to '+', '/' - to '-'. If this is not sufficient, + adjust the function `sanitize`. +-} + +{-# LANGUAGE OverloadedStrings #-} + +module Main where + +--import Data.Text hiding (head, tail, reverse, length, map) +import Control.Monad +import Text.CSV +import System.Directory +import System.Process +import System.Exit + +--gpg = "/usr/local/bin/gpg2" +gpg = "/usr/bin/gpg2" + +keyid = "01234567" -- !!!Fill in the real I.D. here!!! + +data Entry = Entry { fCategory :: String + , fDescription :: String + , fWebsite :: String + , fUsername :: String + , fPassword :: String + , fNotes :: String + }; + +instance Show Entry where + show e = fPassword e + ++ nonempty "User" (fUsername e) + ++ nonempty "Website" (fWebsite e) + ++ nonempty "Notes" (fNotes e) + where + nonempty :: String -> String -> String + nonempty l v = if length v > 0 then "\n" ++ l ++ ": " ++ v else "" + +pathOf e = (sanitize (fCategory e), sanitize (fDescription e)) + +sanitize = map substsafe + where + substsafe '/' = '-' + substsafe '*' = '+' + substsafe x = x + +record2entry :: Record -> Maybe Entry +record2entry [fCat,fDesc,fWeb,fUser,fPass,fNote,_] = + Just (Entry { fCategory = fCat + , fDescription = fDesc + , fWebsite = fWeb + , fUsername = fUser + , fPassword = fPass + , fNotes = fNote + }) +record2entry _ = Nothing + +main = parseCSVFromFile "oisafe.csv" + >>= either (error . show) ((mapM_ makeEntry) . tail) + +makeEntry :: Record -> IO () +makeEntry = buildFile . record2entry + +buildFile :: Maybe Entry -> IO () +buildFile Nothing = return () +buildFile (Just e) = do + let + (sub, file) = pathOf e + dir = "password-store/" ++ sub + path = dir ++ "/" ++ file ++ ".gpg" + cont = show e + (rc, stdout, stderr) <- readProcessWithExitCode gpg ["-ae", "-r", keyid] cont + when (rc /= ExitSuccess) $ error $ "gpg rc " ++ (show rc) ++ " message " ++ stderr + createDirectoryIfMissing True dir + writeFile path stdout |