Android-Password-Store/contrib/oisafe2pstore/oisafe2pstore.hs
Eugene Crosser 99934d35b9 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>
2016-07-23 15:51:37 +03:00

85 lines
2.4 KiB
Haskell

{-
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