2015-07-07 21:00:34 +02:00
|
|
|
{-# LANGUAGE RecordWildCards #-}
|
|
|
|
|
2015-07-07 14:55:02 +02:00
|
|
|
import Types
|
|
|
|
import Pretty
|
|
|
|
import Parser
|
|
|
|
|
2015-07-07 21:00:34 +02:00
|
|
|
import Control.Monad (when)
|
2015-07-07 14:55:02 +02:00
|
|
|
import Data.List (isInfixOf)
|
|
|
|
import System.FilePath (takeBaseName)
|
|
|
|
import System.Process (readProcess, callCommand)
|
2015-07-07 21:00:34 +02:00
|
|
|
import System.Console.ArgParser
|
2015-07-07 14:55:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
-- Search functions --
|
|
|
|
|
|
|
|
byServer :: String -> Keychain -> [Item]
|
|
|
|
byServer s = byAttrib (Left "srv", Str s)
|
|
|
|
|
|
|
|
byAccount :: String -> Keychain -> [Item]
|
|
|
|
byAccount a = byAttrib (Left "acct", Str a)
|
|
|
|
|
|
|
|
byAttrib :: Attrib -> Keychain -> [Item]
|
|
|
|
byAttrib a = filter (elem a . attrs)
|
|
|
|
|
|
|
|
attrib :: Name -> Item -> Maybe Value
|
|
|
|
attrib a = lookup a . attrs
|
|
|
|
|
|
|
|
fuzzy :: String -> Keychain -> [Item]
|
|
|
|
fuzzy x = filter (any (isInfixOf x) . strings)
|
|
|
|
where
|
|
|
|
strings = map unvalue . attrs
|
|
|
|
unvalue (_, Str s) = s
|
|
|
|
unvalue _ = ""
|
|
|
|
|
|
|
|
|
|
|
|
-- Keychain access --
|
|
|
|
|
|
|
|
keychainList :: IO [FilePath]
|
2015-07-07 20:59:53 +02:00
|
|
|
keychainList = do
|
|
|
|
raw <- readProcess "security" ["list-keychains"] ""
|
|
|
|
case runParser parseKeychainList raw of
|
|
|
|
Just list -> return list
|
|
|
|
Nothing -> error "failed to parse active keychains list"
|
2015-07-07 14:55:02 +02:00
|
|
|
|
|
|
|
getKeychain :: IO Keychain
|
|
|
|
getKeychain = do
|
|
|
|
paths <- filter ((/="System") . takeBaseName) <$> keychainList
|
2015-07-07 20:59:53 +02:00
|
|
|
raw <- readProcess "security" ("dump-keychain" : "-d" : paths) ""
|
|
|
|
case runParser parseKeychain raw of
|
|
|
|
Just items -> return items
|
|
|
|
Nothing -> error "failed to parse keychain"
|
2015-07-07 14:55:02 +02:00
|
|
|
|
|
|
|
sendClipboard :: String -> IO ()
|
|
|
|
sendClipboard text =
|
|
|
|
callCommand $ "echo " ++ (show text) ++ " | pbcopy"
|
|
|
|
|
|
|
|
|
2015-07-07 21:00:34 +02:00
|
|
|
-- CLI arguments --
|
|
|
|
|
|
|
|
data ProgArgs = ProgArgs
|
|
|
|
{ searchTerm :: String
|
|
|
|
, keychain :: FilePath
|
|
|
|
, exactMatches :: String
|
|
|
|
, resultsLimit :: Int
|
|
|
|
, contentOnly :: Bool
|
|
|
|
, noClipboard :: Bool
|
|
|
|
} deriving (Show)
|
|
|
|
|
|
|
|
parser :: ParserSpec ProgArgs
|
|
|
|
parser = ProgArgs
|
|
|
|
`parsedBy` reqPos "term" `Descr` "Keychain search term"
|
|
|
|
`andBy` optFlag "" "keychain" `Descr` "Use a specific keychain"
|
|
|
|
`andBy` optFlag "" "exact" `Descr` "Only return exact matches"
|
|
|
|
`andBy` optFlag 10 "limit" `Descr` "Set upper results limit"
|
|
|
|
`andBy` boolFlag "content" `Descr` "Print only the items content"
|
|
|
|
`andBy` boolFlag "clipboard" `Descr` "Disable clipboard paste"
|
|
|
|
|
|
|
|
interface :: IO (CmdLnInterface ProgArgs)
|
|
|
|
interface =
|
|
|
|
(`setAppDescr` "Quickly access the OSX keychain") <$>
|
|
|
|
(`setAppEpilog` "TODO") <$>
|
|
|
|
mkApp parser
|
|
|
|
|
2015-07-07 14:55:02 +02:00
|
|
|
main :: IO ()
|
2015-07-07 21:00:34 +02:00
|
|
|
main = interface >>= (`runApp` search)
|
|
|
|
|
|
|
|
|
|
|
|
search :: ProgArgs -> IO ()
|
|
|
|
search ProgArgs {..} = do
|
2015-07-07 14:55:02 +02:00
|
|
|
res <- fuzzy "gog.com" <$> getKeychain
|
|
|
|
pprint res
|
2015-07-07 21:00:34 +02:00
|
|
|
when (not noClipboard) (sendClipboard (content $ head res))
|
2015-07-07 14:55:02 +02:00
|
|
|
|
|
|
|
|