packages feed

keystore 0.6.1.1 → 0.6.2.0

raw patch · 4 files changed

+90/−58 lines, 4 files

Files

changelog view
@@ -91,3 +91,8 @@  0.6.1.1 Chris Dornan <chrisd@irisconnect.co.uk> 2014-09-28     * fix deploy example for GHC 7.6.3 (use System.Setenv)++0.6.2.0 Chris Dornan <chrisd@irisconnect.co.uk> 2014-10-19+    * add listKeys and keyName_ to Sections+    * add getKeyDataWithMode and rotate_ to Sections+    * rotate reports the keys it is rotating
keystore.cabal view
@@ -1,5 +1,5 @@ Name:                   keystore-Version:                0.6.1.1+Version:                0.6.2.0 Synopsis:               Managing stores of secret things Homepage:               http://github.com/cdornan/keystore Author:                 Chris Dornan
src/Data/KeyStore/Sections.hs view
@@ -10,16 +10,19 @@   , Sections(..)   , SectionType(..)   , KeyData(..)+  , KeyDataMode(..)   , KeyPredicate   , RetrieveDg(..)   , initialise   , rotate   , rotateIfChanged+  , rotate_   , retrieve   , signKeystore   , verifyKeystore   , noKeys   , allKeys+  , listKeys   , keyPrededicate   , keyHelp   , sectionHelp@@ -27,6 +30,7 @@   , publicKeySummary   , locateKeys   , keyName+  , keyName_   , passwordName   )   where@@ -75,48 +79,52 @@     , h -> s, k -> s     , s -> k, h -> k     where-  hostDeploySection :: h -> s                           -- ^ the deployment section: for a given host,+  hostDeploySection   :: h -> s                           -- ^ the deployment section: for a given host,                                                         -- the starting section for locating the keys                                                         -- during a deployment ('higher'/closer sections                                                         -- taking priority)-  sectionType       :: s -> SectionType                 -- ^ whether the section holds the top key for the+  sectionType         :: s -> SectionType                 -- ^ whether the section holds the top key for the                                                         -- keystore (i.e., keystore master key), the signing key                                                         -- for the keystore or is a normal section containing                                                         -- deployment keys-  superSections     :: s -> [s]                         -- ^ the sections that get a copy of the master+  superSections       :: s -> [s]                         -- ^ the sections that get a copy of the master                                                         -- for this section (making all of its keys                                                         -- available to them); N.B., the graph formed by this                                                         -- this relationship over the sections must be acyclic-  keyIsHostIndexed  :: k -> Maybe (h->Bool)             -- ^ if the key is host-indexed then the predicate+  keyIsHostIndexed    :: k -> Maybe (h->Bool)             -- ^ if the key is host-indexed then the predicate                                                         -- specifies the hosts that use this key-  keyIsInSection    :: k -> s -> Bool                   -- ^ specifies which sections a key is resident in-  getKeyData        :: Maybe h -> s -> k -> IO KeyData  -- ^ loads the data for a particular key-  sectionSettings   :: Maybe s -> IO Settings           -- ^ loads the setting for a given settings-  describeKey       :: k -> String                      -- ^ describes the key (for the ks help command)-  describeSection   :: s -> String                      -- ^ describes the section (for the ks help command)-  sectionPWEnvVar   :: s -> EnvVar                      -- ^ secifies the environment variable containing the+  keyIsInSection      :: k -> s -> Bool                   -- ^ specifies which sections a key is resident in+  getKeyData          :: Maybe h -> s -> k -> IO KeyData  -- ^ loads the data for a particular key+  getKeyDataWithMode  :: Maybe h -> s -> k -> IO (KeyDataMode,KeyData)+                                                          -- ^ loads the data for a particular key, returning mode+  sectionSettings     :: Maybe s -> IO Settings           -- ^ loads the setting for a given settings+  describeKey         :: k -> String                      -- ^ describes the key (for the ks help command)+  describeSection     :: s -> String                      -- ^ describes the section (for the ks help command)+  sectionPWEnvVar     :: s -> EnvVar                      -- ^ secifies the environment variable containing the                                                         -- ^ master password/provate key for for the given section -  sectionType           = const ST_keys+  sectionType                   = const ST_keys -  superSections         = const []+  superSections                 = const [] -  keyIsHostIndexed      = const Nothing+  keyIsHostIndexed              = const Nothing -  keyIsInSection        = const $ const True+  keyIsInSection                = const $ const True -  getKeyData Nothing  s = get_kd $ encode s-  getKeyData (Just h) _ = get_kd $ encode h+  getKeyData          mb s k    = snd <$> getKeyDataWithMode mb s k -  sectionSettings       = const $ return mempty+  getKeyDataWithMode Nothing  s = get_kd $ encode s+  getKeyDataWithMode (Just h) _ = get_kd $ encode h -  describeKey         k = "The '" ++ encode k ++ "' key."+  sectionSettings               = const $ return mempty -  describeSection     s = "The '" ++ encode s ++ "' Section."+  describeKey         k         = "The '" ++ encode k ++ "' key." -  sectionPWEnvVar       = EnvVar . T.pack . ("KEY_pw_" ++) . encode+  describeSection     s         = "The '" ++ encode s ++ "' Section." +  sectionPWEnvVar               = EnvVar . T.pack . ("KEY_pw_" ++) . encode + -- | Sections are used to hold the top (master) key for the keystore, -- its signing key, or deployment keys data SectionType@@ -138,6 +146,11 @@     }   deriving (Show,Eq) +data KeyDataMode+  = KDM_static+  | KDM_random+  deriving (Bounded,Enum,Eq,Ord,Show)+ -- | 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. type KeyPredicate h s k = Maybe h -> s -> k -> Bool@@ -174,22 +187,19 @@  -- | Rotate in a set of keys specified by the predicate. rotate :: Sections h s k => IC -> KeyPredicate h s k -> IO ()-rotate = rotate_ False+rotate ic = rotate_ ic Nothing 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+rotateIfChanged ic = rotate_ ic Nothing 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 ]+rotate_ :: Sections h s k => IC -> Maybe KeyDataMode -> Bool -> KeyPredicate h s k -> IO ()+rotate_ ic mb ch kp = reformat ic' $ sequence_ [ rotate' mb ch ic mb_h s k | (mb_h,s,k)<-listKeys kp ]   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             ]-     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.@@ -222,6 +232,13 @@ allKeys :: KeyPredicate h s k allKeys _ _ _ = True +-- | List all of the keys specified by a KeyPredicate+listKeys :: Sections h s k => KeyPredicate h s k -> [(Maybe h,s,k)]+listKeys kp = [ trp | trp@(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             ]+ -- | A utility for specifing a slice of the keys in the store, optionally specifying -- host section and key that should belong to the slice. (If the host is specified then -- the resulting predicate will only include host-indexed keys belonging to the@@ -324,8 +341,15 @@             Just hp | hp h      -> return $ Just h                     | otherwise -> Left RDG_no_such_host_key   s <- keySection h k-  return $ key_nme mb_h s k+  return $ keyName_ mb_h s k +-- | Basic function for generating a key name from the host (if it is+-- host indexex), section name and key id.+keyName_ :: Sections h s k => Maybe h -> s -> k -> Name+keyName_ mb_h s k = name' $ encode s ++ "/" ++ encode k ++ hst_sfx ++ "/"+  where+    hst_sfx = maybe "" (\h -> "/" ++ encode h) mb_h+ -- 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@@ -346,26 +370,32 @@ fmt :: Code a => (a->Bool) -> String fmt p  = unwords [ encode h | h<-[minBound..maxBound], p h ] -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+rotate' :: Sections h s k => Maybe KeyDataMode -> Bool -> IC -> Maybe h -> s -> k -> IO ()+rotate' mb ch ic mb_h s k = do+    (kdm,kd@KeyData{..}) <- getKeyDataWithMode mb_h s k+    -- if the KeyDataMode is specified but does not match the key's mode then squash the rotation+    case maybe True (==kdm) mb of       True  -> do-        -- if key has not changed, or the secret text is not available-        -- then squash the rotation-        mbkds <- map key2KeyData <$> locateKeys ic (mks k) g_nm-        case mbkds of-          Just kd':_ | kd==kd' -> return False    -- the key has not changes-          Nothing :_           -> return False    -- secret not accessible to compare-          _                    -> return True+        -- iff ch then compare the new value with the old+        ok <- case ch of+          True  -> do+            -- if key has not changed, or the secret text is not available+            -- then squash the rotation+            mbkds <- map key2KeyData <$> locateKeys ic (mks k) g_nm+            case mbkds of+              Just kd':_ | kd==kd' -> return False    -- the key has not changes+              Nothing :_           -> return False    -- secret not accessible to compare+              _                    -> return True+          False ->+            return True+        when ok $ do+          n_nm <- unique_nme ic g_nm+          putStrLn $ "rotating: " ++ _name n_nm+          createKey ic n_nm kd_comment kd_identity Nothing $ Just kd_secret       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+        return ()   where-    g_nm = key_nme mb_h s k+    g_nm = keyName_ mb_h s k      mks :: k -> SECTIONS h s k     mks = const SECTIONS@@ -439,11 +469,6 @@ backup_password :: Sections h s k => IC -> s -> s -> IO () backup_password ic s sv_s = secureKey ic (passwordName s) $ safeguard [sve_nme sv_s] -key_nme :: Sections h s k => Maybe h -> s -> k -> Name-key_nme mb_h s k = name' $ encode s ++ "/" ++ encode k ++ hst_sfx ++ "/"-  where-    hst_sfx = maybe "" (\h -> "/" ++ encode h) mb_h- sgn_nme :: Sections h s k => s -> Name sgn_nme s = name' $ encode s ++ "/keystore_signing_key" @@ -471,17 +496,19 @@ the_keystore :: CtxParams -> FilePath the_keystore = maybe "keystore.json" id . cp_store -get_kd :: Sections h s k => String -> k -> IO KeyData+get_kd :: Sections h s k => String -> k -> IO (KeyDataMode,KeyData) get_kd sd k = do   ide <- B.readFile $ fp "_id"   cmt <- B.readFile $ fp "_cmt"   sec <- B.readFile $ fp ""   return-    KeyData-      { kd_identity = Identity $ T.pack $ B.unpack ide-      , kd_comment  = Comment  $ T.pack $ B.unpack cmt-      , kd_secret   = sec-      }+    ( KDM_static+    , KeyData+        { kd_identity = Identity $ T.pack $ B.unpack ide+        , kd_comment  = Comment  $ T.pack $ B.unpack cmt+        , kd_secret   = sec+        }+    )   where     fp sfx = sd </> encode k ++ sfx 
src/Data/KeyStore/Version.hs view
@@ -6,4 +6,4 @@     (a,b,c,d) = versionTuple  versionTuple :: (Int,Int,Int,Int)-versionTuple = (0,6,1,1)+versionTuple = (0,6,2,0)