import Types import Pretty import Parser import Data.List (isInfixOf) import System.FilePath (takeBaseName) import System.Process (readProcess, callCommand) -- 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] keychainList = do raw <- readProcess "security" ["list-keychains"] "" case runParser parseKeychainList raw of Just list -> return list Nothing -> error "failed to parse active keychains list" getKeychain :: IO Keychain getKeychain = do paths <- filter ((/="System") . takeBaseName) <$> keychainList raw <- readProcess "security" ("dump-keychain" : "-d" : paths) "" case runParser parseKeychain raw of Just items -> return items Nothing -> error "failed to parse keychain" sendClipboard :: String -> IO () sendClipboard text = callCommand $ "echo " ++ (show text) ++ " | pbcopy" main :: IO () main = do res <- fuzzy "gog.com" <$> getKeychain sendClipboard (content (head res)) pprint res