skeleton (empty) → 0.1.0.0
raw patch · 5 files changed
+154/−0 lines, 5 filesdep +argparserdep +attoparsecdep +basesetup-changed
Dependencies added: argparser, attoparsec, base, bytestring, filepath, hex, posix-escape, process, time
Files
- LICENSE +3/−0
- README.md +15/−0
- Setup.hs +2/−0
- skeleton.cabal +35/−0
- src/Main.hs +99/−0
+ LICENSE view
@@ -0,0 +1,3 @@+Dual licensed under the MIT and GPL licenses:+http://www.opensource.org/licenses/mit-license.php+http://www.gnu.org/licenses/gpl.html
+ README.md view
@@ -0,0 +1,15 @@+# Skeleton+## Quickly access the OSX keychain++skeleton is a command line tool used to quickly access passwords+stored in the OSX keychain. You can search by account, server+name or any other available attribute and get a list of fuzzy+matched result. The first match is be copied to the clipbdoard.++### Usage+Run skeleton -h for help++### License+Dual licensed under the MIT and GPL licenses: +http://www.opensource.org/licenses/mit-license.php +http://www.gnu.org/licenses/gpl.html
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ skeleton.cabal view
@@ -0,0 +1,35 @@+name: skeleton+version: 0.1.0.0+synopsis: a tool to access the OSX keychain+description:+ + skeleton is a command line tool used to quickly access passwords+ stored in the OSX keychain. You can search by account, server+ name or any other available attribute and get a list of fuzzy+ matched result. The first match is be copied to the clipbdoard.++license: MIT+license-file: LICENSE+author: rnhmjoj+maintainer: micheleguerinirocco@me.com+copyright: (C) Michele Guerini Rocco+category: Utility+build-type: Simple+extra-source-files: README.md, LICENSE+cabal-version: >=1.10++source-repository head+ type: git+ location: https://github.com/rnhmjoj/skeleton++executable skeleton+ main-is: Main.hs+ hs-source-dirs: src+ default-language: Haskell2010+ other-extensions: OverloadedStrings, RecordWildCards,+ ViewPatterns, FlexibleInstances,+ TypeSynonymInstances+ build-depends: base >=4.8 && <= 5.0, filepath, process,+ attoparsec, bytestring, hex, time,+ argparser, posix-escape+ ghc-options: -O2
+ src/Main.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE RecordWildCards #-}++import Skeleton.Types+import Skeleton.Pretty+import Skeleton.Parser++import Control.Monad (when)+import Data.List (isInfixOf)+import System.FilePath (takeBaseName)+import System.Process (readProcess, callCommand)+import System.Posix.Escape (escape)+import System.Console.ArgParser+++-- Search functions --++byAttrib :: Attrib -> Keychain -> [Item]+byAttrib a = filter (elem 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 $ filter ((/="System") . takeBaseName) list+ Nothing -> error "failed to parse active keychains list"++getKeychain :: [FilePath] -> IO Keychain+getKeychain paths = do+ 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 " ++ (escape text) ++ " | pbcopy"+++-- 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 (default: all except System)"+ `andBy` optFlag "" "exact" `Descr` "Return exact matches with the given class"+ `andBy` optFlag 10 "limit" `Descr` "Set upper results limit (default: 10, 0: unlimited)"+ `andBy` boolFlag "content" `Descr` "Print only the items content"+ `andBy` boolFlag "noclipboard" `Descr` "Disable paste to clipboard"++interface :: IO (CmdLnInterface ProgArgs)+interface =+ (`setAppDescr` "Quickly access the OSX keychain") <$>+ (`setAppEpilog` "The skeleton key") <$>+ mkApp parser++main :: IO ()+main = interface >>= (`runApp` search)+++-- Program --++search :: ProgArgs -> IO ()+search ProgArgs {..} = do+ paths <- if null keychain + then keychainList+ else return [keychain]+ items <- getKeychain paths+ let select = if resultsLimit == 0+ then id+ else take resultsLimit+ let res = if null exactMatches+ then select (fuzzy searchTerm items)+ else select (byAttrib (Left exactMatches, Str searchTerm) items)+ if null res+ then putStrLn "No results found"+ else do+ if contentOnly+ then mapM_ putStrLn (map content res)+ else pprint res+ when (not noClipboard) (sendClipboard (content $ head res))