keystore 0.5.0.3 → 0.5.0.4
raw patch · 6 files changed
+67/−20 lines, 6 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Data.KeyStore.Sections: instance Eq KeyData
+ Data.KeyStore.Sections: instance Show KeyData
+ Data.KeyStore.Sections: rotateIfChanged :: Sections h s k => IC -> KeyPredicate h s k -> IO ()
Files
- changelog +4/−0
- examples/deploy/Deploy/Command.hs +7/−5
- examples/deploy/deploy.hs +2/−1
- keystore.cabal +1/−1
- src/Data/KeyStore/CLI.hs +1/−1
- src/Data/KeyStore/Sections.hs +52/−12
changelog view
@@ -62,3 +62,7 @@ 0.5.0.3 Chris Dornan <chrisd@irisconnect.co.uk> 2014-07-30 * fix key-formatting bug (gratuitious insertion of double '/'s before the version number)++0.5.0.4 Chris Dornan <chrisd@irisconnect.co.uk> 2014-08-24+ * improve diagnostics for internally used Sections.keySection+ * add roateIfChanged to Sections (squashes vacuous rotations)
examples/deploy/Deploy/Command.hs view
@@ -23,6 +23,7 @@ data Command = Create | Rotate (Maybe HostID) (Maybe SectionID) (Maybe KeyID)+ | RotateSmart (Maybe HostID) (Maybe SectionID) (Maybe KeyID) | Deploy (Maybe FilePath) HostID | Sign | Verify@@ -58,7 +59,8 @@ p_command = subparser $ command "create" pi_create- <> command "rotate" pi_rotate_key+ <> command "rotate" (pi_rotate_key False)+ <> command "rotate-smart" (pi_rotate_key True ) <> command "deploy" pi_deploy <> command "sign" pi_sign <> command "verify" pi_verify@@ -76,15 +78,15 @@ (helper <*> (pure Create)) (progDesc "create a new keystore") -pi_rotate_key :: ParserInfo Command-pi_rotate_key =+pi_rotate_key :: Bool -> ParserInfo Command+pi_rotate_key sm = h_info (helper <*>- (Rotate+ ((if sm then RotateSmart else Rotate) <$> optional p_host <*> optional p_section <*> optional p_key))- (progDesc "rotate a key")+ (progDesc $ if sm then "rotate keys, but only if they have changed" else "rotate keys") pi_deploy :: ParserInfo Command pi_deploy =
examples/deploy/deploy.hs view
@@ -40,7 +40,8 @@ _ -> verify_ks True ic_ro case cli_command of Create -> error "main: Initialise"- Rotate mbh mbs mbk -> rotate ic $ key_prededicate mbh mbs mbk+ Rotate mbh mbs mbk -> rotate ic $ key_prededicate mbh mbs mbk+ RotateSmart mbh mbs mbk -> rotateIfChanged ic $ key_prededicate mbh mbs mbk Deploy mb hst -> deploy ic_ro hst >>= write mb Sign -> sign_ks ic_ro Verify -> T.putStrLn "the keystore matches the signature"
keystore.cabal view
@@ -1,5 +1,5 @@ Name: keystore-Version: 0.5.0.3+Version: 0.5.0.4 Synopsis: Managing stores of secret things Homepage: http://github.com/cdornan/keystore Author: Chris Dornan
src/Data/KeyStore/CLI.hs view
@@ -18,7 +18,7 @@ version :: String-version = "0.5.0.3"+version = "0.5.0.4" cli :: IO () cli = parseCLI >>= command Nothing
src/Data/KeyStore/Sections.hs view
@@ -14,6 +14,7 @@ , RetrieveDg(..) , initialise , rotate+ , rotateIfChanged , retrieve , signKeystore , verifyKeystore@@ -39,6 +40,7 @@ import qualified Data.HashMap.Strict as HM import qualified Data.Vector as V import qualified Data.Map as Map+import Data.API.Types import Data.Maybe import Data.List import Data.Char@@ -134,6 +136,7 @@ , kd_comment :: Comment , kd_secret :: B.ByteString }+ deriving (Show,Eq) -- | One, many or all of the keys in a store may be rotated at a time. -- we use one of these to specify which keys are to be rotated.@@ -169,9 +172,20 @@ mks :: Sections h s k => KeyPredicate h s k -> IC -> s -> IO () mks = const mk_section --- | Rotate in a set of keys spwecified by the predicate.+-- | Rotate in a set of keys specified by the predicate. rotate :: Sections h s k => IC -> KeyPredicate h s k -> IO ()-rotate ic kp = reformat ic' $ sequence_ [ rotate' ic mb_h s k | (mb_h,s,k)<-host_keys++non_host_keys, kp mb_h s k ]+rotate = rotate_ False++-- | Rotate in a set of keys specified by the predicate, rotating each key only+-- if it has changed: NB the check is contingent on the secret text being+-- accessible; if the secret text is not accessible then the rotation will happen.+rotateIfChanged :: Sections h s k => IC -> KeyPredicate h s k -> IO ()+rotateIfChanged = rotate_ True++-- | Rotate in a set of keys specified by the predicate with the first argument+-- controlling whether to squash duplicate rotations+rotate_ :: Sections h s k => Bool -> IC -> KeyPredicate h s k -> IO ()+rotate_ ch ic kp = reformat ic' $ sequence_ [ rotate' ch ic mb_h s k | (mb_h,s,k)<-host_keys++non_host_keys, kp mb_h s k ] where host_keys = [ (Just h ,s,k) | k<-[minBound..maxBound], Just isp<-[keyIsHostIndexed k], h<-[minBound..maxBound], isp h, let s = key_section h k ] non_host_keys = [ (Nothing,s,k) | k<-[minBound..maxBound], Nothing <-[keyIsHostIndexed k], s<-[minBound..maxBound], keyIsInSection k s ]@@ -179,7 +193,7 @@ ic' = kp_RFT kp ic -- | Retrieve the keys for a given host from the store. Note that the whole history for the given key is returned.--- Note also that the secret text may not be present if it si not accessible (depnding upon hwich section passwords+-- Note also that the secret text may not be present if it is not accessible (depnding upon hwich section passwords -- are correctly bound in the process environment). Note also that the 'Retrieve' diagnostic should not fail if a -- coherent model has been ddefined for 'Sections'. retrieve :: Sections h s k => IC -> h -> k -> IO (Retrieve [Key])@@ -312,11 +326,11 @@ s <- keySection h k return $ key_nme mb_h s k --- a wrapper on keySection used internally in functional contezxtx+-- a wrapper on keySection used internally in functional contexts key_section :: Sections h s k => h -> k -> s key_section h k = either oops id $ keySection h k where- oops = error "key_section"+ oops dg = error $ "key_section: " ++ encode h ++ ": " ++ encode k ++ ": " ++ show dg -- | Rerurn the section that a host sores a given key in, returning a -- failure diagnostic if the host does not keep such a key in the given@@ -327,17 +341,33 @@ -- | The name of the key that stores the password for a given sections. passwordName :: Sections h s k => s -> Name-passwordName s = name' $ "/pw/" ++ encode s+passwordName s = name' $ "/pw/" ++ encode s fmt :: Code a => (a->Bool) -> String fmt p = unwords [ encode h | h<-[minBound..maxBound], p h ] -rotate' :: Sections h s k => IC -> Maybe h -> s -> k -> IO ()-rotate' ic mb_h s k = do- KeyData{..} <- getKeyData mb_h s k- nm <- unique_nme ic $ key_nme mb_h s k- createKey ic nm kd_comment kd_identity Nothing (Just kd_secret)+rotate' :: Sections h s k => Bool -> IC -> Maybe h -> s -> k -> IO ()+rotate' ch ic mb_h s k = do+ kd@KeyData{..} <- getKeyData mb_h s k+ -- iff ch then compare the new value with the old+ ok <- case ch of+ True -> do+ -- if key has not changed then squash the rotation+ mbkds <- map key2KeyData <$> locateKeys ic (mks k) g_nm+ case mbkds of+ Just kd':_ | kd==kd' -> return False+ _ -> return True+ False ->+ return True+ when ok $ do+ n_nm <- unique_nme ic g_nm+ createKey ic n_nm kd_comment kd_identity Nothing $ Just kd_secret+ where+ g_nm = key_nme mb_h s k + mks :: k -> SECTIONS h s k+ mks = const SECTIONS+ lower_sections :: Sections h s k => s -> [s] lower_sections s0 = s0 : concat@@ -456,7 +486,7 @@ -------------------------------------------------------------------------------- ----- Regormating the KeyStore Names to Allow Prefixes (#3)+-- Reformating the KeyStore Names to Allow Prefixes (#3) -- -------------------------------------------------------------------------------- @@ -659,6 +689,16 @@ False -> Nothing --------------------------------------------------------------------------------++key2KeyData :: Key -> Maybe KeyData+key2KeyData Key{..} = f <$> _key_clear_text+ where+ f (ClearText(Binary bs)) =+ KeyData+ { kd_identity = _key_identity+ , kd_comment = _key_comment+ , kd_secret = bs+ } name' :: String -> Name name' = either (error.show) id . name