keystore 0.6.3.1 → 0.7.0.0
raw patch · 4 files changed
+118/−67 lines, 4 filesdep ~aesondep ~timePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, time
API changes (from Hackage documentation)
+ Data.KeyStore.PasswordManager: getStore :: PW p => PMConfig p -> IO PasswordStore
- Data.KeyStore.PasswordManager: PMCD_delete_password_plus :: PasswordName -> PMCommand p
+ Data.KeyStore.PasswordManager: PMCD_delete_password_plus :: (Maybe PasswordName) -> PMCommand p
- Data.KeyStore.PasswordManager: PMCD_import :: FilePath -> (Maybe PasswordText) -> PMCommand p
+ Data.KeyStore.PasswordManager: PMCD_import :: Bool -> FilePath -> (Maybe PasswordText) -> PMCommand p
- Data.KeyStore.PasswordManager: deletePasswordPlus :: PW p => PMConfig p -> PasswordName -> IO ()
+ Data.KeyStore.PasswordManager: deletePasswordPlus :: PW p => PMConfig p -> Maybe PasswordName -> IO ()
Files
- changelog +8/−0
- keystore.cabal +1/−1
- src/Data/KeyStore/PasswordManager.hs +108/−65
- src/Data/KeyStore/Version.hs +1/−1
changelog view
@@ -102,3 +102,11 @@ 0.6.3.1 Chris Dornan <chrisd@irisconnect.co.uk> 2014-11-07 * export 'login' and 'PMCommand' constructors from PasswordManager++0.7.0.0 Chris Dornan <chrisd@irisconnect.co.uk> 2014-11-08+ * PM: add getStore (for debugging)+ * PM: fix a curious regression in in the CLI parser+ (possibly triggered by the upgrade of a dependent package)+ * PM: add delete-all-plus-passwords+ * PM: add filter-plus-passwords+ * PM: add --exclude-plus-passwords switch to import
keystore.cabal view
@@ -1,5 +1,5 @@ Name: keystore-Version: 0.6.3.1+Version: 0.7.0.0 Synopsis: Managing stores of secret things Homepage: http://github.com/cdornan/keystore Author: Chris Dornan
src/Data/KeyStore/PasswordManager.hs view
@@ -51,6 +51,8 @@ , passwordManager' , PMCommand(..) , pmCommandParser+ -- debugging+ , getStore ) where import Data.KeyStore.Types.PasswordStoreModel@@ -276,13 +278,25 @@ -- | import the contents of another keystore into the current keystore import_ :: PW p => PMConfig p -> FilePath -> Maybe PasswordText -> IO ()-import_ pmc fp mb = wrap pmc $ \ps -> do- pwt <- maybe (get_pw True pmc) return mb- mb_ps <- passwordValid' pmc fp pwt- case mb_ps of- Nothing -> error "*** Password Invalid ***\n"- Just ps' -> return $ Just $ merge_ps ps ps'+import_ = import__ False +-- | import the contents of another keystore into the current keystore+import__ :: PW p => Bool -> PMConfig p -> FilePath -> Maybe PasswordText -> IO ()+import__ x_pps pmc fp0 mb = wrap pmc $ \ps -> do+ fp <- tilde fp0+ ok <- doesFileExist fp+ when (not ok) $ error "*** password store not found ***"+ pwt <- maybe (get_pw True pmc) return mb+ mb_ps <- passwordValid' pmc fp pwt+ case mb_ps of+ Nothing -> error "*** Password Invalid ***\n"+ Just ps' -> return $ Just $ merge_ps x_pps ps ps'+ where+ tilde ('~':t@('/':_)) = do+ mb_hm <- E.lookupEnv "HOME"+ return $ (fromMaybe "/" mb_hm) ++ t+ tilde fp = return fp+ -- | loads a password into the store; if this is a session password and the -- boolean ss is True then the session will be reset to this password also; -- if no 'PasswordText' is specified then one will be read from stdin@@ -405,8 +419,9 @@ deletePassword pmc p = wrap pmc $ \ps -> return $ Just $ L.over ps_map (Map.delete (pwName p)) ps -- | delete a password from the store-deletePasswordPlus :: PW p => PMConfig p -> PasswordName -> IO ()-deletePasswordPlus pmc pnm = wrap pmc $ \ps -> return $ Just $ L.over ps_map (Map.delete (plussify pnm)) ps+deletePasswordPlus :: PW p => PMConfig p -> Maybe PasswordName -> IO ()+deletePasswordPlus pmc Nothing = wrap pmc $ \ps -> return $ Just $ L.over ps_map (Map.filter is_static_pw) ps+deletePasswordPlus pmc (Just pnm) = wrap pmc $ \ps -> return $ Just $ L.over ps_map (Map.delete (plussify pnm)) ps -- | delete a session from the store deleteSession :: PW p => PMConfig p -> Maybe p -> SessionName -> IO ()@@ -785,6 +800,9 @@ mb <- f pws maybe (return ()) (save_ps pmc aek) mb +getStore :: PW p => PMConfig p -> IO PasswordStore+getStore pmc = enquire pmc return+ enquire :: PW p => PMConfig p -> (PasswordStore -> IO a) -> IO a enquire pmc f = do aek <- get_key pmc@@ -826,8 +844,8 @@ -- the second passwords store, except the store's creation time, which is -- taken from the first store; any sessions are also merged with the -- sessions in the second store taking precedence-merge_ps :: PasswordStore -> PasswordStore -> PasswordStore-merge_ps ps ps' =+merge_ps :: Bool -> PasswordStore -> PasswordStore -> PasswordStore+merge_ps x_pps ps ps0' = PasswordStore { _ps_comment = _ps_comment ps' , _ps_map = Map.unionWith f (_ps_map ps) (_ps_map ps')@@ -836,6 +854,15 @@ where f pw pw' = L.over pw_sessions (flip Map.union $ _pw_sessions pw) pw' + ps' = case x_pps of+ True -> L.over ps_map (Map.filter is_static_pw) ps0'+ False -> ps0'++is_static_pw :: Password -> Bool+is_static_pw Password{..} = case T.unpack $ _PasswordName _pw_name of+ '+':_ -> False+ _ -> True+ random_bytes :: Octets -> (Binary->a) -> IO a random_bytes sz f = f . Binary . fst . generateCPRNG (_Octets sz) <$> newCPRNG @@ -880,14 +907,14 @@ -- The Command Line Parser -- --- | run a password manager command abstracy syntax command+-- | run a password manager command passwordManager' :: PW p => PMConfig p -> PMCommand p -> IO () passwordManager' pmc pmcd = case pmcd of PMCD_version -> putStrLn version PMCD_setup nl mb_t -> setup pmc nl mb_t PMCD_login y mb_t -> login pmc y mb_t- PMCD_import fp mb_t -> import_ pmc fp mb_t+ PMCD_import x_pps fp mb_t -> import__ x_pps pmc fp mb_t PMCD_load p mb_t -> load pmc p mb_t PMCD_load_plus pnm mb_t -> loadPlus pmc pnm mb_t PMCD_comment cmt -> psComment pmc cmt@@ -914,24 +941,24 @@ = PMCD_version | PMCD_setup Bool (Maybe PasswordText) | PMCD_login Bool (Maybe PasswordText)- | PMCD_import FilePath (Maybe PasswordText)+ | PMCD_import Bool FilePath (Maybe PasswordText) | PMCD_load p (Maybe PasswordText) | PMCD_load_plus PasswordName (Maybe PasswordText)- | PMCD_comment PasswordStoreComment+ | PMCD_comment PasswordStoreComment | PMCD_prime Bool p | PMCD_prime_all Bool- | PMCD_select (Maybe p) SessionName- | PMCD_delete_password p- | PMCD_delete_password_plus PasswordName- | PMCD_delete_session (Maybe p) SessionName+ | PMCD_select (Maybe p) SessionName+ | PMCD_delete_password p+ | PMCD_delete_password_plus (Maybe PasswordName)+ | PMCD_delete_session (Maybe p) SessionName | PMCD_status Bool | PMCD_prompt | PMCD_passwords Bool | PMCD_passwords_plus Bool | PMCD_session Bool- | PMCD_sessions Bool (Maybe p)+ | PMCD_sessions Bool (Maybe p) | PMCD_info Bool p- | PMCD_info_plus Bool PasswordName+ | PMCD_info_plus Bool PasswordName | PMCD_dump Bool | PMCD_collect | PMCD_sample_script@@ -952,28 +979,29 @@ pmCommandParser :: PW p => PMConfig p -> Parser (PMCommand p) pmCommandParser pmc = subparser $ f $ g- $ command "version" pi_version- <> command "setup" (pi_setup pmc)- <> command "login" (pi_login pmc)- <> command "import" (pi_import pmc)- <> command "load" (pi_load pmc)- <> command "comment" pi_comment- <> command "prime" pi_prime- <> command "prime-all" pi_prime_all- <> command "select" pi_select- <> command "delete-password" (pi_delete_password pmc)- <> command "delete-session" pi_delete_session- <> command "status" pi_status- <> command "prompt" pi_prompt- <> command "passwords" pi_passwords- <> command "passwords-plus" pi_passwords_plus- <> command "session" pi_session- <> command "sessions" pi_sessions- <> command "info" (pi_info pmc)- <> command "collect" pi_collect+ $ command "version" pi_version+ <> command "setup" (pi_setup pmc)+ <> command "login" (pi_login pmc)+ <> command "import" (pi_import pmc)+ <> command "load" (pi_load pmc)+ <> command "comment" pi_comment+ <> command "prime" pi_prime+ <> command "prime-all" pi_prime_all+ <> command "select" pi_select+ <> command "delete-password" (pi_delete_password pmc)+ <> command "delete-all-plus-passwords" pi_delete_all_plus_passwords+ <> command "delete-session" pi_delete_session+ <> command "status" pi_status+ <> command "prompt" pi_prompt+ <> command "passwords" pi_passwords+ <> command "passwords-plus" pi_passwords_plus+ <> command "session" pi_session+ <> command "sessions" pi_sessions+ <> command "info" (pi_info pmc)+ <> command "collect" pi_collect where- s = command "sample-load-script" pi_sample_script- d = command "dump" pi_dump+ s = command "sample-load-script" pi_sample_script+ d = command "dump" pi_dump f = case _pmc_sample_script pmc of Nothing -> id@@ -1004,7 +1032,7 @@ pi_import :: PW p => PMConfig p -> ParserInfo (PMCommand p) pi_import pmc = h_info- (helper <*> (PMCD_import <$> p_store_fp <*> optional (p_password_text True pmc)))+ (helper <*> (PMCD_import <$> p_x_pps <*> p_store_fp <*> optional (p_password_text True pmc))) (progDesc "import the contents of another store") pi_load :: PW p => PMConfig p -> ParserInfo (PMCommand p)@@ -1043,6 +1071,12 @@ (helper <*> p_delete_password pmc) (progDesc "delete a password from the store") +pi_delete_all_plus_passwords :: ParserInfo (PMCommand p)+pi_delete_all_plus_passwords =+ h_info+ (helper <*> pure (PMCD_delete_password_plus Nothing))+ (progDesc "delete all dynamic (plus) passwords forom the store")+ pi_delete_session :: PW p => ParserInfo (PMCommand p) pi_delete_session = h_info@@ -1113,25 +1147,23 @@ p_load_command, p_delete_password, p_info :: PW p => PMConfig p -> Parser (PMCommand p) -p_load_command pmc =- (PMCD_load_plus <$> p_pl_pw pmc <*> optional (p_password_text False pmc) <|>- PMCD_load <$> p_pw_id <*> optional (p_password_text False pmc) ) <* optional p_load_comment+p_load_command pmc = f <$> p_pw pmc <*> optional (p_password_text False pmc) <* optional p_load_comment+ where+ f ei op_p = either (flip PMCD_load op_p) (flip PMCD_load_plus op_p) ei -p_delete_password pmc =- PMCD_delete_password_plus <$> p_pl_pw pmc <|>- PMCD_delete_password <$> p_pw_id+p_delete_password pmc = either PMCD_delete_password (PMCD_delete_password_plus . Just) <$> p_pw pmc -p_info pmc = f <$> p_secret_sw <*> ((Left <$> p_pl_pw pmc) <|> (Right <$> p_pw_id))+p_info pmc = f <$> p_secret_sw <*> p_pw pmc where- f s_sw (Left pnm) = PMCD_info_plus s_sw pnm- f s_sw (Right p ) = PMCD_info s_sw p+ f s_sw (Left p ) = PMCD_info s_sw p+ f s_sw (Right pnm) = PMCD_info_plus s_sw pnm -- switches p_brief_sw :: Parser Bool p_brief_sw = switch- (short 'b' <>+ (short 'b' <> long "brief" <> help "list the identifiers only") @@ -1156,6 +1188,13 @@ long "quiet" <> help "don't print anything but report with error codes (0=>logged in)") +p_secret_sw :: Parser Bool+p_secret_sw =+ switch+ (short 's' <>+ long "secret" <>+ help "show the secret password")+ p_sessions_sw :: Parser Bool p_sessions_sw = switch@@ -1169,6 +1208,13 @@ long "unprime" <> help "clear the prime status") +p_x_pps :: Parser Bool+p_x_pps =+ switch+ (short 'x' <>+ long "exclude-plus-passwords" <>+ help "exclude the dynamic (plus) passwords")+ -- options p_pw_id_opt :: PW p => Parser p@@ -1199,27 +1245,24 @@ $ metavar "PASSWORD-TEXT" <> help "the text of the password" +p_pw :: PW p => PMConfig p -> Parser (Either p PasswordName)+p_pw pmc =+ argument (eitherReader $ maybe (Left "bad password syntax") Right . prs)+ $ metavar "PASSWORD"+ <> help "a static or dynamic (+) password name"+ where+ prs s =+ Left <$> (parsePwName $ PasswordName $ T.pack s) <|>+ Right <$> (parse_plus_pw pmc s)+ p_pw_id :: PW p => Parser p p_pw_id = argument (eitherReader $ maybe (fail "bad password syntax") return . parsePwName . PasswordName . T.pack) $ metavar "PASSWORD-ID" <> help "a password ID" -p_pl_pw :: PW p => PMConfig p -> Parser PasswordName-p_pl_pw pmc =- argument (eitherReader $ maybe (fail "bad +password syntax") return . parse_plus_pw pmc)- $ metavar "+PASSWORD"- <> help "a dynamic (plus) password name"- p_ps_comment :: Parser PasswordStoreComment p_ps_comment = PasswordStoreComment . T.pack <$> p_comment--p_secret_sw :: Parser Bool-p_secret_sw =- switch- (short 's' <>- long "secret" <>- help "show the secret password") p_session_name :: Parser SessionName p_session_name =
src/Data/KeyStore/Version.hs view
@@ -6,4 +6,4 @@ (a,b,c,d) = versionTuple versionTuple :: (Int,Int,Int,Int)-versionTuple = (0,6,3,1)+versionTuple = (0,7,0,0)