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>
This commit is contained in:
parent
a22b5573ec
commit
99934d35b9
1 changed files with 85 additions and 0 deletions
85
contrib/oisafe2pstore/oisafe2pstore.hs
Normal file
85
contrib/oisafe2pstore/oisafe2pstore.hs
Normal file
|
@ -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
|
Loading…
Reference in a new issue