aboutsummaryrefslogtreecommitdiff
path: root/contrib/oisafe2pstore/oisafe2pstore.hs
diff options
context:
space:
mode:
authorEugene Crosser <crosser@average.org>2016-07-23 15:51:37 +0300
committerEugene Crosser <crosser@average.org>2016-07-23 15:51:37 +0300
commit99934d35b99fc2188c962a53cf7bc0f8b83fe58f (patch)
tree62a96f207d7fe9af99cc660b27757d817961c94c /contrib/oisafe2pstore/oisafe2pstore.hs
parenta22b5573ec4ed9412e5cd8a17f5fc1584d17de7f (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.hs85
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