craft-0.0.0.1: src/Craft/SSH/AuthorizedKey.hs
module Craft.SSH.AuthorizedKey where
import Control.Lens
import qualified Data.Map.Strict as Map
import Data.Maybe (catMaybes)
import Text.Megaparsec
import Text.Megaparsec.String
import Craft hiding (try)
import qualified Craft.File as File
import Craft.SSH
import Craft.SSH.PublicKey as PK
data AuthorizedKey
= AuthorizedKey
{ _authkeyUser :: User
, _authkey :: PublicKey
}
deriving (Show, Eq)
makeLenses ''AuthorizedKey
instance Craftable AuthorizedKey AuthorizedKey where
watchCraft ak@(AuthorizedKey user pk) = do
pubKeys <- Map.elems . Map.insert (pk^.pubkeyValue) pk
. authkeysToMap
<$> get user
craft_ $ userDir user
w <- watchCraft_ $ userFile user
& strContent .~ (unlines $ map PK.toString pubKeys)
return (w, ak)
instance Destroyable AuthorizedKey where
watchDestroy (AuthorizedKey user pk) = do
pubKeysMap <- authkeysToMap <$> get user
let val = pk^.pubkeyValue
let newPubKeys = Map.elems $ Map.delete val pubKeysMap
craft_ $ userDir user
craft_ $ userFile user
& strContent .~ (unlines $ map PK.toString newPubKeys)
return $ case Map.lookup val pubKeysMap of
Nothing -> (Unchanged, Nothing)
Just x -> (Removed, Just (AuthorizedKey user x))
userFile :: User -> File
userFile user =
file ((user^.to userDir.path) </> $(mkRelFile "authorized_keys"))
& mode .~ Mode RW O O
& ownerAndGroup .~ user
get :: User -> Craft [AuthorizedKey]
get user = File.get (user ^. to userFile . path) >>= \case
Nothing -> return []
Just f -> map (AuthorizedKey user) <$> parseFile parsePublicKeys (f^.path)
authkeysToMap :: [AuthorizedKey] -> Map.Map String PublicKey
authkeysToMap = Map.fromList . map (((,)<$>_pubkeyValue<*>id) . _authkey)
parsePublicKeys :: Parser [PublicKey]
parsePublicKeys = do
keys <- (try (Just <$> parsePublicKey) <|> (space >> return Nothing)) `sepEndBy` eol
return $ catMaybes keys