    {-# LANGUAGE DeriveDataTypeable, TypeFamilies #-}

    module Propellor.Property.Ssh (
    	installed,
    	restarted,
    	PubKeyText,
    	SshKeyType(..),
    	-- * Daemon configuration
    	sshdConfig,
    	ConfigKeyword,
    	setSshdConfigBool,
    	setSshdConfig,
    	RootLogin(..),
    	permitRootLogin,
    	passwordAuthentication,
    	noPasswords,
    	listenPort,
    	-- * Host keys
    	randomHostKeys,
    	hostKeys,
    	hostKey,
    	hostPubKey,
    	getHostPubKey,
    	-- * User keys and configuration
    	userKeys,
    	userKeyAt,
    	knownHost,
    	unknownHost,
    	authorizedKeysFrom,
    	unauthorizedKeysFrom,
    	authorizedKeys,
    	authorizedKey,
    	hasAuthorizedKeys,
    	getUserPubKeys,
    ) where

    import Propellor.Base
    import qualified Propellor.Property.File as File
    import qualified Propellor.Property.Service as Service
    import qualified Propellor.Property.Apt as Apt
    import Propellor.Property.User
    import Propellor.Types.Info

    import System.Posix.User
    import System.Posix.Files
    import qualified Data.Map as M
    import qualified Data.Set as S
    import qualified Data.Semigroup as Sem
    import Data.List

    installed :: Property UnixLike
    installed :: Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    installed = PubKeyText
    "ssh installed" PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall i.
    IsProp (Property i) =>
    PubKeyText -> Property i -> Property i
    ==> (Property DebianLike
    aptinstall Property DebianLike
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} ka kb (c :: k) (a :: ka) (b :: kb).
    (HasCallStack, SingKind 'KProxy, SingKind 'KProxy,
     DemoteRep 'KProxy ~ [MetaType], DemoteRep 'KProxy ~ [MetaType],
     SingI c) =>
    Property (MetaTypes a)
    -> Property (MetaTypes b) -> Property (MetaTypes c)
    `pickOS` Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    unsupportedOS)
      where
    	aptinstall :: Property DebianLike
    	aptinstall :: Property DebianLike
    aptinstall = [PubKeyText] -> Property DebianLike
    Apt.installed [PubKeyText
    "ssh"]

    restarted :: Property DebianLike
    restarted :: Property DebianLike
    restarted = PubKeyText -> Property DebianLike
    Service.restarted PubKeyText
    "ssh"

    sshBool :: Bool -> String
    sshBool :: Bool -> PubKeyText
    sshBool Bool
    True = PubKeyText
    "yes"
    sshBool Bool
    False = PubKeyText
    "no"

    sshdConfig :: FilePath
    sshdConfig :: PubKeyText
    sshdConfig = PubKeyText
    "/etc/ssh/sshd_config"

    type ConfigKeyword = String

    setSshdConfigBool :: ConfigKeyword -> Bool -> Property DebianLike
    setSshdConfigBool :: PubKeyText -> Bool -> Property DebianLike
    setSshdConfigBool PubKeyText
    setting Bool
    allowed = PubKeyText -> PubKeyText -> Property DebianLike
    setSshdConfig PubKeyText
    setting (Bool -> PubKeyText
    sshBool Bool
    allowed)

    setSshdConfig :: ConfigKeyword -> String -> Property DebianLike
    setSshdConfig :: PubKeyText -> PubKeyText -> Property DebianLike
    setSshdConfig PubKeyText
    setting PubKeyText
    v = PubKeyText
    -> ([PubKeyText] -> [PubKeyText])
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall c.
    (FileContent c, Eq c) =>
    PubKeyText
    -> (c -> c)
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.fileProperty PubKeyText
    desc [PubKeyText] -> [PubKeyText]
    f PubKeyText
    sshdConfig
    	Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property DebianLike
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
         (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    restarted
      where
    	desc :: PubKeyText
    desc = [PubKeyText] -> PubKeyText
    unwords [ PubKeyText
    "ssh config:", PubKeyText
    setting, PubKeyText
    v ]
    	cfgline :: PubKeyText
    cfgline = PubKeyText
    setting PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    v
    	wantedline :: PubKeyText -> Bool
    wantedline PubKeyText
    s
    		| PubKeyText
    s PubKeyText -> PubKeyText -> Bool
    forall a. Eq a => a -> a -> Bool
    == PubKeyText
    cfgline = Bool
    True
    		| (PubKeyText
    setting PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " ") PubKeyText -> PubKeyText -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` PubKeyText
    s = Bool
    False
    		| Bool
    otherwise = Bool
    True
    	f :: [PubKeyText] -> [PubKeyText]
    f [PubKeyText]
    ls
    		| PubKeyText
    cfgline PubKeyText -> [PubKeyText] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [PubKeyText]
    ls = (PubKeyText -> Bool) -> [PubKeyText] -> [PubKeyText]
    forall a. (a -> Bool) -> [a] -> [a]
    filter PubKeyText -> Bool
    wantedline [PubKeyText]
    ls
    		| Bool
    otherwise = (PubKeyText -> Bool) -> [PubKeyText] -> [PubKeyText]
    forall a. (a -> Bool) -> [a] -> [a]
    filter PubKeyText -> Bool
    wantedline [PubKeyText]
    ls [PubKeyText] -> [PubKeyText] -> [PubKeyText]
    forall a. [a] -> [a] -> [a]
    ++ [PubKeyText
    cfgline]

    data RootLogin
    	= RootLogin Bool  -- ^ allow or prevent root login
    	| WithoutPassword -- ^ disable password authentication for root, while allowing other authentication methods
    	| ForcedCommandsOnly -- ^ allow root login with public-key authentication, but only if a forced command has been specified for the public key

    permitRootLogin :: RootLogin -> Property DebianLike
    permitRootLogin :: RootLogin -> Property DebianLike
    permitRootLogin (RootLogin Bool
    b) = PubKeyText -> Bool -> Property DebianLike
    setSshdConfigBool PubKeyText
    "PermitRootLogin" Bool
    b
    permitRootLogin RootLogin
    WithoutPassword = PubKeyText -> PubKeyText -> Property DebianLike
    setSshdConfig PubKeyText
    "PermitRootLogin" PubKeyText
    "without-password"
    permitRootLogin RootLogin
    ForcedCommandsOnly = PubKeyText -> PubKeyText -> Property DebianLike
    setSshdConfig PubKeyText
    "PermitRootLogin" PubKeyText
    "forced-commands-only"

    passwordAuthentication :: Bool -> Property DebianLike
    passwordAuthentication :: Bool -> Property DebianLike
    passwordAuthentication = PubKeyText -> Bool -> Property DebianLike
    setSshdConfigBool PubKeyText
    "PasswordAuthentication"

    -- | Configure ssh to not allow password logins.
    --
    -- To prevent lock-out, this is done only once root's
    -- authorized_keys is in place.
    noPasswords :: Property DebianLike
    noPasswords :: Property DebianLike
    noPasswords = IO Bool -> Property DebianLike -> Property DebianLike
    forall (p :: * -> *) i (m :: * -> *).
    (Checkable p i, LiftPropellor m) =>
    m Bool -> p i -> Property i
    check (User -> IO Bool
    hasAuthorizedKeys (PubKeyText -> User
    User PubKeyText
    "root")) (Property DebianLike -> Property DebianLike)
    -> Property DebianLike -> Property DebianLike
    forall a b. (a -> b) -> a -> b
    $
    	Bool -> Property DebianLike
    passwordAuthentication Bool
    False

    dotDir :: User -> IO FilePath
    dotDir :: User -> IO PubKeyText
    dotDir User
    user = do
    	h <- User -> IO PubKeyText
    homedir User
    user
    	return $ h </> ".ssh"

    dotFile :: FilePath -> User -> IO FilePath
    dotFile :: PubKeyText -> User -> IO PubKeyText
    dotFile PubKeyText
    f User
    user = do
    	d <- User -> IO PubKeyText
    dotDir User
    user
    	return $ d </> f

    -- | Makes the ssh server listen on a given port, in addition to any other
    -- ports it is configured to listen on.
    --
    -- Revert to prevent it listening on a particular port.
    listenPort :: Port -> RevertableProperty DebianLike DebianLike
    listenPort :: Port -> RevertableProperty DebianLike DebianLike
    listenPort Port
    port = CombinedType
      (Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
      (Property DebianLike)
    Property DebianLike
    enable Property DebianLike
    -> Property DebianLike -> RevertableProperty DebianLike DebianLike
    forall setupmetatypes undometatypes.
    Property setupmetatypes
    -> Property undometatypes
    -> RevertableProperty setupmetatypes undometatypes
    <!> CombinedType
      (Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
      (Property DebianLike)
    Property DebianLike
    disable
      where
    	portline :: PubKeyText
    portline = PubKeyText
    "Port " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ Port -> PubKeyText
    forall t. ConfigurableValue t => t -> PubKeyText
    val Port
    port
    	enable :: CombinedType
      (Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
      (Property DebianLike)
    enable = PubKeyText
    sshdConfig PubKeyText
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    `File.containsLine` PubKeyText
    portline
    		Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall p. IsProp p => p -> PubKeyText -> p
    `describe` (PubKeyText
    "ssh listening on " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    portline)
    		Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property DebianLike
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
         (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    restarted
    	disable :: CombinedType
      (Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
      (Property DebianLike)
    disable = PubKeyText
    sshdConfig PubKeyText
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    `File.lacksLine` PubKeyText
    portline
    		Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall p. IsProp p => p -> PubKeyText -> p
    `describe` (PubKeyText
    "ssh not listening on " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    portline)
    		Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property DebianLike
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
         (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    restarted

    hasAuthorizedKeys :: User -> IO Bool
    hasAuthorizedKeys :: User -> IO Bool
    hasAuthorizedKeys = PubKeyText -> IO Bool
    go (PubKeyText -> IO Bool)
    -> (User -> IO PubKeyText) -> User -> IO Bool
    forall (m :: * -> *) b c a.
    Monad m =>
    (b -> m c) -> (a -> m b) -> a -> m c
    <=< PubKeyText -> User -> IO PubKeyText
    dotFile PubKeyText
    "authorized_keys"
      where
    	go :: PubKeyText -> IO Bool
    go PubKeyText
    f = Bool -> Bool
    not (Bool -> Bool) -> (PubKeyText -> Bool) -> PubKeyText -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PubKeyText -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (PubKeyText -> Bool) -> IO PubKeyText -> IO Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> PubKeyText -> IO PubKeyText -> IO PubKeyText
    forall (m :: * -> *) a. MonadCatch m => a -> m a -> m a
    catchDefaultIO PubKeyText
    "" (PubKeyText -> IO PubKeyText
    readFile PubKeyText
    f)

    -- | Blows away existing host keys and make new ones.
    -- Useful for systems installed from an image that might reuse host keys.
    -- A flag file is used to only ever do this once.
    randomHostKeys :: Property DebianLike
    randomHostKeys :: Property DebianLike
    randomHostKeys = Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall i. Property i -> PubKeyText -> Property i
    flagFile Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    prop PubKeyText
    "/etc/ssh/.unique_host_keys"
    	Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property DebianLike
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
         (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    restarted
      where
    	prop :: Property UnixLike
    	prop :: Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    prop = PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    "ssh random host keys" ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w -> do
    		Propellor Bool -> Propellor ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (Propellor Bool -> Propellor ()) -> Propellor Bool -> Propellor ()
    forall a b. (a -> b) -> a -> b
    $ IO Bool -> Propellor Bool
    forall a. IO a -> Propellor a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Bool -> Propellor Bool) -> IO Bool -> Propellor Bool
    forall a b. (a -> b) -> a -> b
    $ PubKeyText -> [CommandParam] -> IO Bool
    boolSystem PubKeyText
    "sh"
    			[ PubKeyText -> CommandParam
    Param PubKeyText
    "-c"
    			, PubKeyText -> CommandParam
    Param PubKeyText
    "rm -f /etc/ssh/ssh_host_*"
    			]
    		OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w (Property
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $ [PubKeyText]
    -> UncheckedProperty
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    scriptProperty [ PubKeyText
    "DPKG_MAINTSCRIPT_NAME=postinst DPKG_MAINTSCRIPT_PACKAGE=openssh-server /var/lib/dpkg/info/openssh-server.postinst configure" ]
    			UncheckedProperty
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Result
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall (p :: * -> *) i.
    Checkable p i =>
    p i -> Result -> Property i
    `assume` Result
    MadeChange

    -- | The text of a ssh public key, for example, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB3BJ2GqZiTR2LEoDXyYFgh/BduWefjdKXAsAtzS9zeI"
    type PubKeyText = String

    -- | Installs the specified list of ssh host keys.
    --
    -- The corresponding private keys come from the privdata.
    --
    -- Any host keys that are not in the list are removed from the host.
    hostKeys :: IsContext c => c -> [(SshKeyType, PubKeyText)] -> Property (HasInfo + DebianLike)
    hostKeys :: forall c.
    IsContext c =>
    c -> [(SshKeyType, PubKeyText)] -> Property (HasInfo + DebianLike)
    hostKeys c
    ctx [(SshKeyType, PubKeyText)]
    l = Property
      (MetaTypes
         '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    Property (HasInfo + DebianLike)
    go Property
      (MetaTypes
         '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    -> Property DebianLike
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
         (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` Property DebianLike
    cleanup
      where
    	desc :: PubKeyText
    desc = PubKeyText
    "ssh host keys configured " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ [SshKeyType] -> PubKeyText
    typelist (((SshKeyType, PubKeyText) -> SshKeyType)
    -> [(SshKeyType, PubKeyText)] -> [SshKeyType]
    forall a b. (a -> b) -> [a] -> [b]
    map (SshKeyType, PubKeyText) -> SshKeyType
    forall a b. (a, b) -> a
    fst [(SshKeyType, PubKeyText)]
    l)
    	go :: Property (HasInfo + DebianLike)
    	go :: Property (HasInfo + DebianLike)
    go = PubKeyText
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    propertyList PubKeyText
    desc (Props
       (MetaTypes
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
     -> Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    forall a b. (a -> b) -> a -> b
    $ [Property
       (MetaTypes
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])]
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    forall {k} (metatypes :: k).
    [Property (MetaTypes metatypes)] -> Props (MetaTypes metatypes)
    toProps ([Property
        (MetaTypes
           '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])]
     -> Props
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
    -> [Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])]
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
    forall a b. (a -> b) -> a -> b
    $ [Maybe
       (Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))]
    -> [Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])]
    forall a. [Maybe a] -> [a]
    catMaybes ([Maybe
        (Property
           (MetaTypes
              '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))]
     -> [Property
           (MetaTypes
              '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])])
    -> [Maybe
          (Property
             (MetaTypes
                '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))]
    -> [Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])]
    forall a b. (a -> b) -> a -> b
    $
    		((SshKeyType, PubKeyText)
     -> Maybe
          (Property
             (MetaTypes
                '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])))
    -> [(SshKeyType, PubKeyText)]
    -> [Maybe
          (Property
             (MetaTypes
                '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))]
    forall a b. (a -> b) -> [a] -> [b]
    map (\(SshKeyType
    t, PubKeyText
    pub) -> Property (HasInfo + DebianLike)
    -> Maybe (Property (HasInfo + DebianLike))
    forall a. a -> Maybe a
    Just (Property (HasInfo + DebianLike)
     -> Maybe (Property (HasInfo + DebianLike)))
    -> Property (HasInfo + DebianLike)
    -> Maybe (Property (HasInfo + DebianLike))
    forall a b. (a -> b) -> a -> b
    $ c -> SshKeyType -> PubKeyText -> Property (HasInfo + DebianLike)
    forall c.
    IsContext c =>
    c -> SshKeyType -> PubKeyText -> Property (HasInfo + DebianLike)
    hostKey c
    ctx SshKeyType
    t PubKeyText
    pub) [(SshKeyType, PubKeyText)]
    l
    	typelist :: [SshKeyType] -> PubKeyText
    typelist [SshKeyType]
    tl = PubKeyText
    "(" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ [PubKeyText] -> PubKeyText
    unwords ((SshKeyType -> PubKeyText) -> [SshKeyType] -> [PubKeyText]
    forall a b. (a -> b) -> [a] -> [b]
    map SshKeyType -> PubKeyText
    fromKeyType [SshKeyType]
    tl) PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    ")"
    	alltypes :: [SshKeyType]
    alltypes = [SshKeyType
    forall a. Bounded a => a
    minBound..SshKeyType
    forall a. Bounded a => a
    maxBound]
    	staletypes :: [SshKeyType]
    staletypes = let have :: [SshKeyType]
    have = ((SshKeyType, PubKeyText) -> SshKeyType)
    -> [(SshKeyType, PubKeyText)] -> [SshKeyType]
    forall a b. (a -> b) -> [a] -> [b]
    map (SshKeyType, PubKeyText) -> SshKeyType
    forall a b. (a, b) -> a
    fst [(SshKeyType, PubKeyText)]
    l in (SshKeyType -> Bool) -> [SshKeyType] -> [SshKeyType]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (SshKeyType -> [SshKeyType] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [SshKeyType]
    have) [SshKeyType]
    alltypes
    	removestale :: Bool -> [Property DebianLike]
    	removestale :: Bool -> [Property DebianLike]
    removestale Bool
    b = (SshKeyType -> Property DebianLike)
    -> [SshKeyType] -> [Property DebianLike]
    forall a b. (a -> b) -> [a] -> [b]
    map (Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property DebianLike
    forall (untightened :: [MetaType]) (tightened :: [MetaType]).
    (TightenTargetsAllowed untightened tightened, SingI tightened) =>
    Property (MetaTypes untightened) -> Property (MetaTypes tightened)
    forall (p :: * -> *) (untightened :: [MetaType])
           (tightened :: [MetaType]).
    (TightenTargets p, TightenTargetsAllowed untightened tightened,
     SingI tightened) =>
    p (MetaTypes untightened) -> p (MetaTypes tightened)
    tightenTargets (Property
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Property DebianLike)
    -> (SshKeyType
        -> Property
             (MetaTypes
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> SshKeyType
    -> Property DebianLike
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.notPresent (PubKeyText
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (SshKeyType -> PubKeyText)
    -> SshKeyType
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (SshKeyType -> Bool -> PubKeyText)
    -> Bool -> SshKeyType -> PubKeyText
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip SshKeyType -> Bool -> PubKeyText
    keyFile Bool
    b) [SshKeyType]
    staletypes
    	cleanup :: Property DebianLike
    	cleanup :: Property DebianLike
    cleanup
    		| [SshKeyType] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [SshKeyType]
    staletypes Bool -> Bool -> Bool
    || [(SshKeyType, PubKeyText)] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [(SshKeyType, PubKeyText)]
    l = Property DebianLike
    forall {k} (t :: k). SingI t => Property (MetaTypes t)
    doNothing
    		| Bool
    otherwise =
    			PubKeyText -> Props DebianLike -> Property DebianLike
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties (PubKeyText
    "any other ssh host keys removed " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ [SshKeyType] -> PubKeyText
    typelist [SshKeyType]
    staletypes)
    				([Property DebianLike] -> Props DebianLike
    forall {k} (metatypes :: k).
    [Property (MetaTypes metatypes)] -> Props (MetaTypes metatypes)
    toProps ([Property DebianLike] -> Props DebianLike)
    -> [Property DebianLike] -> Props DebianLike
    forall a b. (a -> b) -> a -> b
    $ Bool -> [Property DebianLike]
    removestale Bool
    True [Property DebianLike]
    -> [Property DebianLike] -> [Property DebianLike]
    forall a. [a] -> [a] -> [a]
    ++ Bool -> [Property DebianLike]
    removestale Bool
    False)
    				Property DebianLike
    -> Property DebianLike
    -> CombinedType (Property DebianLike) (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    restarted

    -- | Installs a single ssh host key of a particular type.
    --
    -- The public key is provided to this function;
    -- the private key comes from the privdata;
    hostKey :: IsContext c => c -> SshKeyType -> PubKeyText -> Property (HasInfo + DebianLike)
    hostKey :: forall c.
    IsContext c =>
    c -> SshKeyType -> PubKeyText -> Property (HasInfo + DebianLike)
    hostKey c
    context SshKeyType
    keytype PubKeyText
    pub = Property
      (MetaTypes
         (Combine
            (Combine
               (Combine
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                  '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    go Property
      (MetaTypes
         (Combine
            (Combine
               (Combine
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                  '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property DebianLike
    -> CombinedType
         (Property
            (MetaTypes
               (Combine
                  (Combine
                     (Combine
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                        '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])))
         (Property DebianLike)
    forall x y. Combines x y => x -> y -> CombinedType x y
    `onChange` Property DebianLike
    restarted
      where
    	go :: Property
      (MetaTypes
         (Combine
            (Combine
               (Combine
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                  '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    go = PubKeyText
    -> Props
         (MetaTypes
            (Combine
               (Combine
                  (Combine
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                     '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (MetaTypes
            (Combine
               (Combine
                  (Combine
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                     '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties PubKeyText
    desc (Props
       (MetaTypes
          (Combine
             (Combine
                (Combine
                   '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                      'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                   '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                      'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
     -> Property
          (MetaTypes
             (Combine
                (Combine
                   (Combine
                      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                      '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                   '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                      'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])))
    -> Props
         (MetaTypes
            (Combine
               (Combine
                  (Combine
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                     '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (MetaTypes
            (Combine
               (Combine
                  (Combine
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                     '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall a b. (a -> b) -> a -> b
    $ Props
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    props
    		Props
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Props
         (Sing
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall {a} p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & SshKeyType
    -> PubKeyText
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    hostPubKey SshKeyType
    keytype PubKeyText
    pub
    		Props
      (Sing
         (Combine
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Props
         (Sing
            (Combine
               (Combine
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                  '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall {a} p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    installpub
    		Props
      (Sing
         (Combine
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Props
         (MetaTypes
            (Combine
               (Combine
                  (Combine
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                     '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall {a} p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property
      (MetaTypes
         '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    Property
      (HasInfo
       + MetaTypes
           '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
              'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    installpriv
    	desc :: PubKeyText
    desc = PubKeyText
    "ssh host key configured (" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ SshKeyType -> PubKeyText
    fromKeyType SshKeyType
    keytype PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    ")"
    	keysrc :: PubKeyText -> PrivDataField -> PrivDataSource
    keysrc PubKeyText
    ext PrivDataField
    field = PrivDataField -> PubKeyText -> PubKeyText -> PrivDataSource
    PrivDataSourceFileFromCommand PrivDataField
    field (PubKeyText
    "sshkey"PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++PubKeyText
    ext)
    		(PubKeyText
    "ssh-keygen -t " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ SshKeyType -> PubKeyText
    sshKeyTypeParam SshKeyType
    keytype PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " -f sshkey")
    	installpub :: Property UnixLike
    	installpub :: Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    installpub = (PubKeyText
     -> [PubKeyText]
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Bool
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    keywriter PubKeyText
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.hasContent Bool
    True (PubKeyText -> [PubKeyText]
    lines PubKeyText
    pub)
    	installpriv :: Property (HasInfo + UnixLike)
    	installpriv :: Property
      (HasInfo
       + MetaTypes
           '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
              'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    installpriv = PrivDataSource
    -> c
    -> (((PrivData -> Propellor Result) -> Propellor Result)
        -> Property
             (HasInfo
              + MetaTypes
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall c s metatypes.
    (IsContext c, IsPrivDataSource s,
     IncludesInfo metatypes ~ 'True) =>
    s
    -> c
    -> (((PrivData -> Propellor Result) -> Propellor Result)
        -> Property metatypes)
    -> Property metatypes
    withPrivData (PubKeyText -> PrivDataField -> PrivDataSource
    keysrc PubKeyText
    "" (SshKeyType -> PubKeyText -> PrivDataField
    SshPrivKey SshKeyType
    keytype PubKeyText
    "")) c
    context ((((PrivData -> Propellor Result) -> Propellor Result)
      -> Property
           (HasInfo
            + MetaTypes
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
     -> Property
          (HasInfo
           + MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (((PrivData -> Propellor Result) -> Propellor Result)
        -> Property
             (HasInfo
              + MetaTypes
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \(PrivData -> Propellor Result) -> Propellor Result
    getkey ->
    		PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    desc ((OuterMetaTypesWitness
        '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w -> (PrivData -> Propellor Result) -> Propellor Result
    getkey ((PrivData -> Propellor Result) -> Propellor Result)
    -> (PrivData -> Propellor Result) -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $
    			OuterMetaTypesWitness
      '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w
    				(Property
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Propellor Result)
    -> (PrivData
        -> Property
             (MetaTypes
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> PrivData
    -> Propellor Result
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (PubKeyText
     -> [PubKeyText]
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Bool
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    keywriter PubKeyText
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.hasContentProtected Bool
    False
    				([PubKeyText]
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (PrivData -> [PubKeyText])
    -> PrivData
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PrivData -> [PubKeyText]
    privDataLines
    	keywriter :: (PubKeyText
     -> [PubKeyText]
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Bool
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    keywriter PubKeyText
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    p Bool
    ispub [PubKeyText]
    keylines = do
    		let f :: PubKeyText
    f = SshKeyType -> Bool -> PubKeyText
    keyFile SshKeyType
    keytype Bool
    ispub
    		PubKeyText
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    p PubKeyText
    f ([PubKeyText] -> [PubKeyText]
    keyFileContent [PubKeyText]
    keylines)

    -- Make sure that there is a newline at the end;
    -- ssh requires this for some types of private keys.
    keyFileContent :: [String] -> [File.Line]
    keyFileContent :: [PubKeyText] -> [PubKeyText]
    keyFileContent [PubKeyText]
    keylines = [PubKeyText]
    keylines [PubKeyText] -> [PubKeyText] -> [PubKeyText]
    forall a. [a] -> [a] -> [a]
    ++ [PubKeyText
    ""]

    keyFile :: SshKeyType -> Bool -> FilePath
    keyFile :: SshKeyType -> Bool -> PubKeyText
    keyFile SshKeyType
    keytype Bool
    ispub = PubKeyText
    "/etc/ssh/ssh_host_" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ SshKeyType -> PubKeyText
    fromKeyType SshKeyType
    keytype PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    "_key" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    ext
      where
    	ext :: PubKeyText
    ext = if Bool
    ispub then PubKeyText
    ".pub" else PubKeyText
    ""

    -- | Indicates the host key that is used by a Host, but does not actually
    -- configure the host to use it. Normally this does not need to be used;
    -- use 'hostKey' instead.
    hostPubKey :: SshKeyType -> PubKeyText -> Property (HasInfo + UnixLike)
    hostPubKey :: SshKeyType
    -> PubKeyText
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    hostPubKey SshKeyType
    t = PubKeyText
    -> HostKeyInfo
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall v.
    IsInfo v =>
    PubKeyText
    -> v
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    pureInfoProperty PubKeyText
    "ssh pubkey known" (HostKeyInfo
     -> Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (PubKeyText -> HostKeyInfo)
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Map SshKeyType PubKeyText -> HostKeyInfo
    HostKeyInfo (Map SshKeyType PubKeyText -> HostKeyInfo)
    -> (PubKeyText -> Map SshKeyType PubKeyText)
    -> PubKeyText
    -> HostKeyInfo
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SshKeyType -> PubKeyText -> Map SshKeyType PubKeyText
    forall k a. k -> a -> Map k a
    M.singleton SshKeyType
    t

    getHostPubKey :: Propellor (M.Map SshKeyType PubKeyText)
    getHostPubKey :: Propellor (Map SshKeyType PubKeyText)
    getHostPubKey = HostKeyInfo -> Map SshKeyType PubKeyText
    fromHostKeyInfo (HostKeyInfo -> Map SshKeyType PubKeyText)
    -> Propellor HostKeyInfo -> Propellor (Map SshKeyType PubKeyText)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Propellor HostKeyInfo
    forall v. IsInfo v => Propellor v
    askInfo

    newtype HostKeyInfo = HostKeyInfo
    	{ HostKeyInfo -> Map SshKeyType PubKeyText
    fromHostKeyInfo :: M.Map SshKeyType PubKeyText }
    	deriving (HostKeyInfo -> HostKeyInfo -> Bool
    (HostKeyInfo -> HostKeyInfo -> Bool)
    -> (HostKeyInfo -> HostKeyInfo -> Bool) -> Eq HostKeyInfo
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: HostKeyInfo -> HostKeyInfo -> Bool
    == :: HostKeyInfo -> HostKeyInfo -> Bool
    $c/= :: HostKeyInfo -> HostKeyInfo -> Bool
    /= :: HostKeyInfo -> HostKeyInfo -> Bool
    Eq, Eq HostKeyInfo
    Eq HostKeyInfo =>
    (HostKeyInfo -> HostKeyInfo -> Ordering)
    -> (HostKeyInfo -> HostKeyInfo -> Bool)
    -> (HostKeyInfo -> HostKeyInfo -> Bool)
    -> (HostKeyInfo -> HostKeyInfo -> Bool)
    -> (HostKeyInfo -> HostKeyInfo -> Bool)
    -> (HostKeyInfo -> HostKeyInfo -> HostKeyInfo)
    -> (HostKeyInfo -> HostKeyInfo -> HostKeyInfo)
    -> Ord HostKeyInfo
    HostKeyInfo -> HostKeyInfo -> Bool
    HostKeyInfo -> HostKeyInfo -> Ordering
    HostKeyInfo -> HostKeyInfo -> HostKeyInfo
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: HostKeyInfo -> HostKeyInfo -> Ordering
    compare :: HostKeyInfo -> HostKeyInfo -> Ordering
    $c< :: HostKeyInfo -> HostKeyInfo -> Bool
    < :: HostKeyInfo -> HostKeyInfo -> Bool
    $c<= :: HostKeyInfo -> HostKeyInfo -> Bool
    <= :: HostKeyInfo -> HostKeyInfo -> Bool
    $c> :: HostKeyInfo -> HostKeyInfo -> Bool
    > :: HostKeyInfo -> HostKeyInfo -> Bool
    $c>= :: HostKeyInfo -> HostKeyInfo -> Bool
    >= :: HostKeyInfo -> HostKeyInfo -> Bool
    $cmax :: HostKeyInfo -> HostKeyInfo -> HostKeyInfo
    max :: HostKeyInfo -> HostKeyInfo -> HostKeyInfo
    $cmin :: HostKeyInfo -> HostKeyInfo -> HostKeyInfo
    min :: HostKeyInfo -> HostKeyInfo -> HostKeyInfo
    Ord, Typeable, Int -> HostKeyInfo -> PubKeyText -> PubKeyText
    [HostKeyInfo] -> PubKeyText -> PubKeyText
    HostKeyInfo -> PubKeyText
    (Int -> HostKeyInfo -> PubKeyText -> PubKeyText)
    -> (HostKeyInfo -> PubKeyText)
    -> ([HostKeyInfo] -> PubKeyText -> PubKeyText)
    -> Show HostKeyInfo
    forall a.
    (Int -> a -> PubKeyText -> PubKeyText)
    -> (a -> PubKeyText) -> ([a] -> PubKeyText -> PubKeyText) -> Show a
    $cshowsPrec :: Int -> HostKeyInfo -> PubKeyText -> PubKeyText
    showsPrec :: Int -> HostKeyInfo -> PubKeyText -> PubKeyText
    $cshow :: HostKeyInfo -> PubKeyText
    show :: HostKeyInfo -> PubKeyText
    $cshowList :: [HostKeyInfo] -> PubKeyText -> PubKeyText
    showList :: [HostKeyInfo] -> PubKeyText -> PubKeyText
    Show)

    instance IsInfo HostKeyInfo where
    	propagateInfo :: HostKeyInfo -> PropagateInfo
    propagateInfo HostKeyInfo
    _ = Bool -> PropagateInfo
    PropagateInfo Bool
    False

    instance Sem.Semigroup HostKeyInfo where
    	HostKeyInfo Map SshKeyType PubKeyText
    old <> :: HostKeyInfo -> HostKeyInfo -> HostKeyInfo
    <> HostKeyInfo Map SshKeyType PubKeyText
    new =
    		-- new first because union prefers values from the first
    		-- parameter when there is a duplicate key
    		Map SshKeyType PubKeyText -> HostKeyInfo
    HostKeyInfo (Map SshKeyType PubKeyText
    new Map SshKeyType PubKeyText
    -> Map SshKeyType PubKeyText -> Map SshKeyType PubKeyText
    forall k a. Ord k => Map k a -> Map k a -> Map k a
    `M.union` Map SshKeyType PubKeyText
    old)

    instance Monoid HostKeyInfo where
    	mempty :: HostKeyInfo
    mempty = Map SshKeyType PubKeyText -> HostKeyInfo
    HostKeyInfo Map SshKeyType PubKeyText
    forall k a. Map k a
    M.empty
    	mappend :: HostKeyInfo -> HostKeyInfo -> HostKeyInfo
    mappend = HostKeyInfo -> HostKeyInfo -> HostKeyInfo
    forall a. Semigroup a => a -> a -> a
    (Sem.<>)

    userPubKeys :: User -> [(SshKeyType, PubKeyText)] -> Property (HasInfo + UnixLike)
    userPubKeys :: User
    -> [(SshKeyType, PubKeyText)]
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    userPubKeys u :: User
    u@(User PubKeyText
    n) [(SshKeyType, PubKeyText)]
    l = PubKeyText
    -> UserKeyInfo
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall v.
    IsInfo v =>
    PubKeyText
    -> v
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    pureInfoProperty (PubKeyText
    "ssh pubkey for " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    n) (UserKeyInfo
     -> Property
          (HasInfo
           + MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> UserKeyInfo
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $
    	Map User (Set (SshKeyType, PubKeyText)) -> UserKeyInfo
    UserKeyInfo (User
    -> Set (SshKeyType, PubKeyText)
    -> Map User (Set (SshKeyType, PubKeyText))
    forall k a. k -> a -> Map k a
    M.singleton User
    u ([(SshKeyType, PubKeyText)] -> Set (SshKeyType, PubKeyText)
    forall a. Ord a => [a] -> Set a
    S.fromList [(SshKeyType, PubKeyText)]
    l))

    getUserPubKeys :: User -> Propellor [(SshKeyType, PubKeyText)]
    getUserPubKeys :: User -> Propellor [(SshKeyType, PubKeyText)]
    getUserPubKeys User
    u = [(SshKeyType, PubKeyText)]
    -> (Set (SshKeyType, PubKeyText) -> [(SshKeyType, PubKeyText)])
    -> Maybe (Set (SshKeyType, PubKeyText))
    -> [(SshKeyType, PubKeyText)]
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe [] Set (SshKeyType, PubKeyText) -> [(SshKeyType, PubKeyText)]
    forall a. Set a -> [a]
    S.toList (Maybe (Set (SshKeyType, PubKeyText))
     -> [(SshKeyType, PubKeyText)])
    -> (UserKeyInfo -> Maybe (Set (SshKeyType, PubKeyText)))
    -> UserKeyInfo
    -> [(SshKeyType, PubKeyText)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . User
    -> Map User (Set (SshKeyType, PubKeyText))
    -> Maybe (Set (SshKeyType, PubKeyText))
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup User
    u (Map User (Set (SshKeyType, PubKeyText))
     -> Maybe (Set (SshKeyType, PubKeyText)))
    -> (UserKeyInfo -> Map User (Set (SshKeyType, PubKeyText)))
    -> UserKeyInfo
    -> Maybe (Set (SshKeyType, PubKeyText))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . UserKeyInfo -> Map User (Set (SshKeyType, PubKeyText))
    fromUserKeyInfo (UserKeyInfo -> [(SshKeyType, PubKeyText)])
    -> Propellor UserKeyInfo -> Propellor [(SshKeyType, PubKeyText)]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Propellor UserKeyInfo
    forall v. IsInfo v => Propellor v
    askInfo

    newtype UserKeyInfo = UserKeyInfo
    	{ UserKeyInfo -> Map User (Set (SshKeyType, PubKeyText))
    fromUserKeyInfo :: M.Map User (S.Set (SshKeyType, PubKeyText)) }
    	deriving (UserKeyInfo -> UserKeyInfo -> Bool
    (UserKeyInfo -> UserKeyInfo -> Bool)
    -> (UserKeyInfo -> UserKeyInfo -> Bool) -> Eq UserKeyInfo
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: UserKeyInfo -> UserKeyInfo -> Bool
    == :: UserKeyInfo -> UserKeyInfo -> Bool
    $c/= :: UserKeyInfo -> UserKeyInfo -> Bool
    /= :: UserKeyInfo -> UserKeyInfo -> Bool
    Eq, Eq UserKeyInfo
    Eq UserKeyInfo =>
    (UserKeyInfo -> UserKeyInfo -> Ordering)
    -> (UserKeyInfo -> UserKeyInfo -> Bool)
    -> (UserKeyInfo -> UserKeyInfo -> Bool)
    -> (UserKeyInfo -> UserKeyInfo -> Bool)
    -> (UserKeyInfo -> UserKeyInfo -> Bool)
    -> (UserKeyInfo -> UserKeyInfo -> UserKeyInfo)
    -> (UserKeyInfo -> UserKeyInfo -> UserKeyInfo)
    -> Ord UserKeyInfo
    UserKeyInfo -> UserKeyInfo -> Bool
    UserKeyInfo -> UserKeyInfo -> Ordering
    UserKeyInfo -> UserKeyInfo -> UserKeyInfo
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: UserKeyInfo -> UserKeyInfo -> Ordering
    compare :: UserKeyInfo -> UserKeyInfo -> Ordering
    $c< :: UserKeyInfo -> UserKeyInfo -> Bool
    < :: UserKeyInfo -> UserKeyInfo -> Bool
    $c<= :: UserKeyInfo -> UserKeyInfo -> Bool
    <= :: UserKeyInfo -> UserKeyInfo -> Bool
    $c> :: UserKeyInfo -> UserKeyInfo -> Bool
    > :: UserKeyInfo -> UserKeyInfo -> Bool
    $c>= :: UserKeyInfo -> UserKeyInfo -> Bool
    >= :: UserKeyInfo -> UserKeyInfo -> Bool
    $cmax :: UserKeyInfo -> UserKeyInfo -> UserKeyInfo
    max :: UserKeyInfo -> UserKeyInfo -> UserKeyInfo
    $cmin :: UserKeyInfo -> UserKeyInfo -> UserKeyInfo
    min :: UserKeyInfo -> UserKeyInfo -> UserKeyInfo
    Ord, Typeable, Int -> UserKeyInfo -> PubKeyText -> PubKeyText
    [UserKeyInfo] -> PubKeyText -> PubKeyText
    UserKeyInfo -> PubKeyText
    (Int -> UserKeyInfo -> PubKeyText -> PubKeyText)
    -> (UserKeyInfo -> PubKeyText)
    -> ([UserKeyInfo] -> PubKeyText -> PubKeyText)
    -> Show UserKeyInfo
    forall a.
    (Int -> a -> PubKeyText -> PubKeyText)
    -> (a -> PubKeyText) -> ([a] -> PubKeyText -> PubKeyText) -> Show a
    $cshowsPrec :: Int -> UserKeyInfo -> PubKeyText -> PubKeyText
    showsPrec :: Int -> UserKeyInfo -> PubKeyText -> PubKeyText
    $cshow :: UserKeyInfo -> PubKeyText
    show :: UserKeyInfo -> PubKeyText
    $cshowList :: [UserKeyInfo] -> PubKeyText -> PubKeyText
    showList :: [UserKeyInfo] -> PubKeyText -> PubKeyText
    Show)

    instance IsInfo UserKeyInfo where
    	propagateInfo :: UserKeyInfo -> PropagateInfo
    propagateInfo UserKeyInfo
    _ = Bool -> PropagateInfo
    PropagateInfo Bool
    False

    instance Sem.Semigroup UserKeyInfo where
    	UserKeyInfo Map User (Set (SshKeyType, PubKeyText))
    old <> :: UserKeyInfo -> UserKeyInfo -> UserKeyInfo
    <> UserKeyInfo Map User (Set (SshKeyType, PubKeyText))
    new =
    		Map User (Set (SshKeyType, PubKeyText)) -> UserKeyInfo
    UserKeyInfo ((Set (SshKeyType, PubKeyText)
     -> Set (SshKeyType, PubKeyText) -> Set (SshKeyType, PubKeyText))
    -> Map User (Set (SshKeyType, PubKeyText))
    -> Map User (Set (SshKeyType, PubKeyText))
    -> Map User (Set (SshKeyType, PubKeyText))
    forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
    M.unionWith Set (SshKeyType, PubKeyText)
    -> Set (SshKeyType, PubKeyText) -> Set (SshKeyType, PubKeyText)
    forall a. Ord a => Set a -> Set a -> Set a
    S.union Map User (Set (SshKeyType, PubKeyText))
    old Map User (Set (SshKeyType, PubKeyText))
    new)

    instance Monoid UserKeyInfo where
    	mempty :: UserKeyInfo
    mempty = Map User (Set (SshKeyType, PubKeyText)) -> UserKeyInfo
    UserKeyInfo Map User (Set (SshKeyType, PubKeyText))
    forall k a. Map k a
    M.empty
    	mappend :: UserKeyInfo -> UserKeyInfo -> UserKeyInfo
    mappend = UserKeyInfo -> UserKeyInfo -> UserKeyInfo
    forall a. Semigroup a => a -> a -> a
    (Sem.<>)

    -- | Sets up a user with the specified public keys, and the corresponding
    -- private keys from the privdata.
    --
    -- The public keys are added to the Info, so other properties like
    -- `authorizedKeysFrom` can use them.
    userKeys :: IsContext c => User -> c -> [(SshKeyType, PubKeyText)] -> Property (HasInfo + UnixLike)
    userKeys :: forall c.
    IsContext c =>
    User
    -> c
    -> [(SshKeyType, PubKeyText)]
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    userKeys user :: User
    user@(User PubKeyText
    name) c
    context [(SshKeyType, PubKeyText)]
    ks = PubKeyText
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties PubKeyText
    desc (Props
       (MetaTypes
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ [Property
       (MetaTypes
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    [Property (MetaTypes metatypes)] -> Props (MetaTypes metatypes)
    toProps ([Property
        (MetaTypes
           '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
              'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
     -> Props
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> [Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $
    	User
    -> [(SshKeyType, PubKeyText)]
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    userPubKeys User
    user [(SshKeyType, PubKeyText)]
    ks Property
      (MetaTypes
         '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> [Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    -> [Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    forall a. a -> [a] -> [a]
    : ((SshKeyType, PubKeyText)
     -> Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> [(SshKeyType, PubKeyText)]
    -> [Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    forall a b. (a -> b) -> [a] -> [b]
    map (Maybe PubKeyText
    -> User
    -> c
    -> (SshKeyType, PubKeyText)
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall c.
    IsContext c =>
    Maybe PubKeyText
    -> User
    -> c
    -> (SshKeyType, PubKeyText)
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    userKeyAt Maybe PubKeyText
    forall a. Maybe a
    Nothing User
    user c
    context) [(SshKeyType, PubKeyText)]
    ks
      where
    	desc :: PubKeyText
    desc = [PubKeyText] -> PubKeyText
    unwords
    		[ PubKeyText
    name
    		, PubKeyText
    "has ssh key"
    		, PubKeyText
    "(" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ [PubKeyText] -> PubKeyText
    unwords (((SshKeyType, PubKeyText) -> PubKeyText)
    -> [(SshKeyType, PubKeyText)] -> [PubKeyText]
    forall a b. (a -> b) -> [a] -> [b]
    map (SshKeyType -> PubKeyText
    fromKeyType (SshKeyType -> PubKeyText)
    -> ((SshKeyType, PubKeyText) -> SshKeyType)
    -> (SshKeyType, PubKeyText)
    -> PubKeyText
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (SshKeyType, PubKeyText) -> SshKeyType
    forall a b. (a, b) -> a
    fst) [(SshKeyType, PubKeyText)]
    ks) PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    ")"
    		]

    -- | Sets up a user with the specified pubic key, and a private
    -- key from the privdata.
    --
    -- A FilePath can be specified to write the key to somewhere other than
    -- the default locations. Allows a user to have multiple keys for
    -- different roles.
    --
    -- When the FilePath is relative, is put inside the User's
    -- ~/.ssh/ directory.
    userKeyAt :: IsContext c => Maybe FilePath -> User -> c -> (SshKeyType, PubKeyText) -> Property (HasInfo + UnixLike)
    userKeyAt :: forall c.
    IsContext c =>
    Maybe PubKeyText
    -> User
    -> c
    -> (SshKeyType, PubKeyText)
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    userKeyAt Maybe PubKeyText
    dest user :: User
    user@(User PubKeyText
    u) c
    context (SshKeyType
    keytype, PubKeyText
    pubkeytext) =
    	PubKeyText
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties PubKeyText
    desc (Props
       (MetaTypes
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Props
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ Props
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    props
    		Props
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Props
         (MetaTypes
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall {a} p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    pubkey
    		Props
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Props
         (Sing
            (Combine
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
               '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall {a} p (y :: [a]) (x :: [a]).
    (IsProp p, MetaTypes y ~ GetMetaTypes p,
     CheckCombinableNote x y (NoteFor ('Text "&"))) =>
    Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
    & Property
      (MetaTypes
         '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    Property
      (HasInfo
       + MetaTypes
           '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
              'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    privkey
      where
    	desc :: PubKeyText
    desc = [PubKeyText] -> PubKeyText
    unwords ([PubKeyText] -> PubKeyText) -> [PubKeyText] -> PubKeyText
    forall a b. (a -> b) -> a -> b
    $ [Maybe PubKeyText] -> [PubKeyText]
    forall a. [Maybe a] -> [a]
    catMaybes
    		[ PubKeyText -> Maybe PubKeyText
    forall a. a -> Maybe a
    Just PubKeyText
    u
    		, PubKeyText -> Maybe PubKeyText
    forall a. a -> Maybe a
    Just PubKeyText
    "has ssh key"
    		, Maybe PubKeyText
    dest
    		, PubKeyText -> Maybe PubKeyText
    forall a. a -> Maybe a
    Just (PubKeyText -> Maybe PubKeyText) -> PubKeyText -> Maybe PubKeyText
    forall a b. (a -> b) -> a -> b
    $ PubKeyText
    "(" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ SshKeyType -> PubKeyText
    fromKeyType SshKeyType
    keytype PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    ")"
    		]
    	pubkey :: Property UnixLike
    	pubkey :: Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    pubkey = PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    desc ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w ->
    		OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> Property
         (MetaTypes
            (Combine
               (Combine
                  (Combine
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w (Property
       (MetaTypes
          (Combine
             (Combine
                (Combine
                   '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                      'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                   '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                      'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
     -> Propellor Result)
    -> Propellor
         (Property
            (MetaTypes
               (Combine
                  (Combine
                     (Combine
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])))
    -> Propellor Result
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (PubKeyText
     -> [PubKeyText]
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> PubKeyText
    -> [PubKeyText]
    -> Propellor
         (Property
            (MetaTypes
               (Combine
                  (Combine
                     (Combine
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])))
    installprop PubKeyText
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.hasContent PubKeyText
    ".pub" [PubKeyText
    pubkeytext]
    	privkey :: Property (HasInfo + UnixLike)
    	privkey :: Property
      (HasInfo
       + MetaTypes
           '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
              'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    privkey = PrivDataField
    -> c
    -> (((PrivData -> Propellor Result) -> Propellor Result)
        -> Property
             (MetaTypes
                '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall c s metatypes.
    (IsContext c, IsPrivDataSource s,
     IncludesInfo metatypes ~ 'True) =>
    s
    -> c
    -> (((PrivData -> Propellor Result) -> Propellor Result)
        -> Property metatypes)
    -> Property metatypes
    withPrivData (SshKeyType -> PubKeyText -> PrivDataField
    SshPrivKey SshKeyType
    keytype PubKeyText
    u) c
    context ((PrivData -> Propellor Result) -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    ((PrivData -> Propellor Result) -> Propellor Result)
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    privkey'
    	privkey' :: ((PrivData -> Propellor Result) -> Propellor Result) -> Property (HasInfo + UnixLike)
    	privkey' :: ((PrivData -> Propellor Result) -> Propellor Result)
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    privkey' (PrivData -> Propellor Result) -> Propellor Result
    getkey = PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    desc ((OuterMetaTypesWitness
        '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w -> (PrivData -> Propellor Result) -> Propellor Result
    getkey ((PrivData -> Propellor Result) -> Propellor Result)
    -> (PrivData -> Propellor Result) -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $ \PrivData
    k ->
    		OuterMetaTypesWitness
      '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> Property
         (MetaTypes
            (Combine
               (Combine
                  (Combine
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w
    			(Property
       (MetaTypes
          (Combine
             (Combine
                (Combine
                   '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                      'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                   '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                      'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
     -> Propellor Result)
    -> Propellor
         (Property
            (MetaTypes
               (Combine
                  (Combine
                     (Combine
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])))
    -> Propellor Result
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (PubKeyText
     -> [PubKeyText]
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> PubKeyText
    -> [PubKeyText]
    -> Propellor
         (Property
            (MetaTypes
               (Combine
                  (Combine
                     (Combine
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])))
    installprop PubKeyText
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.hasContentProtected PubKeyText
    "" (PrivData -> [PubKeyText]
    privDataLines PrivData
    k)
    	installprop :: (PubKeyText
     -> [PubKeyText]
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> PubKeyText
    -> [PubKeyText]
    -> Propellor
         (Property
            (MetaTypes
               (Combine
                  (Combine
                     (Combine
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
                        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                     '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                        'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])))
    installprop PubKeyText
    -> [PubKeyText]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    writer PubKeyText
    ext [PubKeyText]
    key = do
    		f <- IO PubKeyText -> Propellor PubKeyText
    forall a. IO a -> Propellor a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO PubKeyText -> Propellor PubKeyText)
    -> IO PubKeyText -> Propellor PubKeyText
    forall a b. (a -> b) -> a -> b
    $ PubKeyText -> IO PubKeyText
    keyfile PubKeyText
    ext
    		return $ combineProperties desc $ props
    			& File.dirExists (takeDirectory f)
    			& writer f (keyFileContent key)
    			& File.ownerGroup f user (userGroup user)
    			& File.ownerGroup (takeDirectory f) user (userGroup user)
    	keyfile :: PubKeyText -> IO PubKeyText
    keyfile PubKeyText
    ext = case Maybe PubKeyText
    dest of
    		Maybe PubKeyText
    Nothing -> PubKeyText -> IO PubKeyText
    relhomessh (PubKeyText -> IO PubKeyText) -> PubKeyText -> IO PubKeyText
    forall a b. (a -> b) -> a -> b
    $ PubKeyText
    "id_" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ SshKeyType -> PubKeyText
    fromKeyType SshKeyType
    keytype PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    ext
    		Just PubKeyText
    f
    			| PubKeyText -> Bool
    isRelative PubKeyText
    f -> PubKeyText -> IO PubKeyText
    relhomessh (PubKeyText
    f PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    ext)
    			| Bool
    otherwise -> PubKeyText -> IO PubKeyText
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (PubKeyText
    f PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    ext)
    	relhomessh :: PubKeyText -> IO PubKeyText
    relhomessh PubKeyText
    f = do
    		home <- UserEntry -> PubKeyText
    homeDirectory (UserEntry -> PubKeyText) -> IO UserEntry -> IO PubKeyText
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> PubKeyText -> IO UserEntry
    getUserEntryForName PubKeyText
    u
    		return $ home </> ".ssh" </> f

    fromKeyType :: SshKeyType -> String
    fromKeyType :: SshKeyType -> PubKeyText
    fromKeyType SshKeyType
    SshRsa = PubKeyText
    "rsa"
    fromKeyType SshKeyType
    SshDsa = PubKeyText
    "dsa"
    fromKeyType SshKeyType
    SshEcdsa = PubKeyText
    "ecdsa"
    fromKeyType SshKeyType
    SshEd25519 = PubKeyText
    "ed25519"

    -- | Puts some host's ssh public key(s), as set using `hostPubKey`
    -- or `hostKey` into the known_hosts file for a user.
    knownHost :: [Host] -> HostName -> User -> Property UnixLike
    knownHost :: [Host]
    -> PubKeyText
    -> User
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    knownHost [Host]
    hosts PubKeyText
    hn user :: User
    user@(User PubKeyText
    u) = PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    desc ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w ->
    	OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> [PubKeyText] -> Propellor Result
    go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w ([PubKeyText] -> Propellor Result)
    -> Propellor [PubKeyText] -> Propellor Result
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< [Host] -> PubKeyText -> Propellor [PubKeyText]
    knownHostLines [Host]
    hosts PubKeyText
    hn
      where
    	desc :: PubKeyText
    desc = PubKeyText
    u PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " knows ssh key for " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    hn

    	go :: OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> [PubKeyText] -> Propellor Result
    go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    _ [] = do
    		PubKeyText -> Propellor ()
    forall (m :: * -> *). MonadIO m => PubKeyText -> m ()
    warningMessage (PubKeyText -> Propellor ()) -> PubKeyText -> Propellor ()
    forall a b. (a -> b) -> a -> b
    $ PubKeyText
    "no configured ssh host keys for " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    hn
    		Result -> Propellor Result
    forall a. a -> Propellor a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Result
    FailedChange
    	go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w [PubKeyText]
    ls = do
    		f <- IO PubKeyText -> Propellor PubKeyText
    forall a. IO a -> Propellor a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO PubKeyText -> Propellor PubKeyText)
    -> IO PubKeyText -> Propellor PubKeyText
    forall a b. (a -> b) -> a -> b
    $ PubKeyText -> User -> IO PubKeyText
    dotFile PubKeyText
    "known_hosts" User
    user
    		ensureProperty w $ modKnownHost user f $
    			f `File.containsLines` ls
    				`requires` File.dirExists (takeDirectory f)

    -- | Reverts `knownHost`
    unknownHost :: [Host] -> HostName -> User -> Property UnixLike
    unknownHost :: [Host]
    -> PubKeyText
    -> User
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    unknownHost [Host]
    hosts PubKeyText
    hn user :: User
    user@(User PubKeyText
    u) = PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    desc ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w ->
    	OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> [PubKeyText] -> Propellor Result
    go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w ([PubKeyText] -> Propellor Result)
    -> Propellor [PubKeyText] -> Propellor Result
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< [Host] -> PubKeyText -> Propellor [PubKeyText]
    knownHostLines [Host]
    hosts PubKeyText
    hn
      where
    	desc :: PubKeyText
    desc = PubKeyText
    u PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " does not know ssh key for " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    hn

    	go :: OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> [PubKeyText] -> Propellor Result
    go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    _ [] = Result -> Propellor Result
    forall a. a -> Propellor a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Result
    NoChange
    	go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w [PubKeyText]
    ls = do
    		f <- IO PubKeyText -> Propellor PubKeyText
    forall a. IO a -> Propellor a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO PubKeyText -> Propellor PubKeyText)
    -> IO PubKeyText -> Propellor PubKeyText
    forall a b. (a -> b) -> a -> b
    $ PubKeyText -> User -> IO PubKeyText
    dotFile PubKeyText
    "known_hosts" User
    user
    		ifM (liftIO $ doesFileExist f)
    			( ensureProperty w $ modKnownHost user f $
    				f `File.lacksLines` ls
    			, return NoChange
    			)

    knownHostLines :: [Host] -> HostName -> Propellor [File.Line]
    knownHostLines :: [Host] -> PubKeyText -> Propellor [PubKeyText]
    knownHostLines [Host]
    hosts PubKeyText
    hn = Maybe (Map SshKeyType PubKeyText) -> [PubKeyText]
    keylines (Maybe (Map SshKeyType PubKeyText) -> [PubKeyText])
    -> Propellor (Maybe (Map SshKeyType PubKeyText))
    -> Propellor [PubKeyText]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [Host]
    -> PubKeyText
    -> Propellor (Map SshKeyType PubKeyText)
    -> Propellor (Maybe (Map SshKeyType PubKeyText))
    forall a.
    [Host] -> PubKeyText -> Propellor a -> Propellor (Maybe a)
    fromHost [Host]
    hosts PubKeyText
    hn Propellor (Map SshKeyType PubKeyText)
    getHostPubKey
      where
    	keylines :: Maybe (Map SshKeyType PubKeyText) -> [PubKeyText]
    keylines (Just Map SshKeyType PubKeyText
    m) = (PubKeyText -> PubKeyText) -> [PubKeyText] -> [PubKeyText]
    forall a b. (a -> b) -> [a] -> [b]
    map (\PubKeyText
    k -> PubKeyText
    hn PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    k) (Map SshKeyType PubKeyText -> [PubKeyText]
    forall k a. Map k a -> [a]
    M.elems Map SshKeyType PubKeyText
    m)
    	keylines Maybe (Map SshKeyType PubKeyText)
    Nothing = []

    modKnownHost :: User -> FilePath -> Property UnixLike -> Property UnixLike
    modKnownHost :: User
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    modKnownHost User
    user PubKeyText
    f Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    p = Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    p
    	Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` PubKeyText
    -> User
    -> Group
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.ownerGroup PubKeyText
    f User
    user (User -> Group
    userGroup User
    user)
    	Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` PubKeyText
    -> User
    -> Group
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.ownerGroup (PubKeyText -> PubKeyText
    takeDirectory PubKeyText
    f) User
    user (User -> Group
    userGroup User
    user)

    -- | Ensures that a local user's authorized_keys contains lines allowing
    -- logins from a remote user on the specified Host.
    --
    -- The ssh keys of the remote user can be set using `userKeys`
    --
    -- Any other lines in the authorized_keys file are preserved as-is.
    authorizedKeysFrom :: User -> (User, Host) -> Property UnixLike
    localuser :: User
    localuser@(User PubKeyText
    ln) authorizedKeysFrom :: User
    -> (User, Host)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    `authorizedKeysFrom` (remoteuser :: User
    remoteuser@(User PubKeyText
    rn), Host
    remotehost) =
    	PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    desc (\OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w -> OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> [PubKeyText] -> Propellor Result
    go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w ([PubKeyText] -> Propellor Result)
    -> Propellor [PubKeyText] -> Propellor Result
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< User -> Host -> Propellor [PubKeyText]
    authorizedKeyLines User
    remoteuser Host
    remotehost)
      where
    	remote :: PubKeyText
    remote = PubKeyText
    rn PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    "@" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ Host -> PubKeyText
    hostName Host
    remotehost
    	desc :: PubKeyText
    desc = PubKeyText
    ln PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " authorized_keys from " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    remote

    	go :: OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> [PubKeyText] -> Propellor Result
    go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    _ [] = do
    		PubKeyText -> Propellor ()
    forall (m :: * -> *). MonadIO m => PubKeyText -> m ()
    warningMessage (PubKeyText -> Propellor ()) -> PubKeyText -> Propellor ()
    forall a b. (a -> b) -> a -> b
    $ PubKeyText
    "no configured ssh user keys for " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    remote
    		Result -> Propellor Result
    forall a. a -> Propellor a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Result
    FailedChange
    	go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w [PubKeyText]
    ls = OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w (Property
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $ PubKeyText
    -> Props
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties PubKeyText
    desc (Props
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Props
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ [Property
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    -> Props
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    [Property (MetaTypes metatypes)] -> Props (MetaTypes metatypes)
    toProps ([Property
        (MetaTypes
           '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
              'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
     -> Props
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> [Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    -> Props
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $
    		(PubKeyText
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> [PubKeyText]
    -> [Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    forall a b. (a -> b) -> [a] -> [b]
    map (RevertableProperty
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall setupmetatypes undometatypes.
    RevertableProperty setupmetatypes undometatypes
    -> Property setupmetatypes
    setupRevertableProperty (RevertableProperty
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (PubKeyText
        -> RevertableProperty
             (MetaTypes
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
             (MetaTypes
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . User
    -> PubKeyText
    -> RevertableProperty
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    authorizedKey User
    localuser) [PubKeyText]
    ls

    -- | Reverts `authorizedKeysFrom`
    unauthorizedKeysFrom :: User -> (User, Host) -> Property UnixLike
    localuser :: User
    localuser@(User PubKeyText
    ln) unauthorizedKeysFrom :: User
    -> (User, Host)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    `unauthorizedKeysFrom` (remoteuser :: User
    remoteuser@(User PubKeyText
    rn), Host
    remotehost) =
    	PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    desc (\OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w -> OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> [PubKeyText] -> Propellor Result
    go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w ([PubKeyText] -> Propellor Result)
    -> Propellor [PubKeyText] -> Propellor Result
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< User -> Host -> Propellor [PubKeyText]
    authorizedKeyLines User
    remoteuser Host
    remotehost)
      where
    	remote :: PubKeyText
    remote = PubKeyText
    rn PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    "@" PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ Host -> PubKeyText
    hostName Host
    remotehost
    	desc :: PubKeyText
    desc = PubKeyText
    ln PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " unauthorized_keys from " PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    remote

    	go :: OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> [PubKeyText] -> Propellor Result
    go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    _ [] = Result -> Propellor Result
    forall a. a -> Propellor a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Result
    NoChange
    	go OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w [PubKeyText]
    ls = OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Propellor Result
    forall (inner :: [MetaType]) (outer :: [MetaType]).
    EnsurePropertyAllowed inner outer =>
    OuterMetaTypesWitness outer
    -> Property (MetaTypes inner) -> Propellor Result
    ensureProperty OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w (Property
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $ PubKeyText
    -> Props
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
    combineProperties PubKeyText
    desc (Props
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Props
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ [Property
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    -> Props
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    [Property (MetaTypes metatypes)] -> Props (MetaTypes metatypes)
    toProps ([Property
        (MetaTypes
           '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
              'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
     -> Props
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> [Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    -> Props
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $
    		(PubKeyText
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> [PubKeyText]
    -> [Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
    forall a b. (a -> b) -> [a] -> [b]
    map (RevertableProperty
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall setupmetatypes undometatypes.
    RevertableProperty setupmetatypes undometatypes
    -> Property undometatypes
    undoRevertableProperty (RevertableProperty
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
       (MetaTypes
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (PubKeyText
        -> RevertableProperty
             (MetaTypes
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
             (MetaTypes
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> PubKeyText
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . User
    -> PubKeyText
    -> RevertableProperty
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    authorizedKey User
    localuser) [PubKeyText]
    ls

    authorizedKeyLines :: User -> Host -> Propellor [File.Line]
    authorizedKeyLines :: User -> Host -> Propellor [PubKeyText]
    authorizedKeyLines User
    remoteuser Host
    remotehost =
    	((SshKeyType, PubKeyText) -> PubKeyText)
    -> [(SshKeyType, PubKeyText)] -> [PubKeyText]
    forall a b. (a -> b) -> [a] -> [b]
    map (SshKeyType, PubKeyText) -> PubKeyText
    forall a b. (a, b) -> b
    snd ([(SshKeyType, PubKeyText)] -> [PubKeyText])
    -> Propellor [(SshKeyType, PubKeyText)] -> Propellor [PubKeyText]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Host
    -> Propellor [(SshKeyType, PubKeyText)]
    -> Propellor [(SshKeyType, PubKeyText)]
    forall a. Host -> Propellor a -> Propellor a
    fromHost' Host
    remotehost (User -> Propellor [(SshKeyType, PubKeyText)]
    getUserPubKeys User
    remoteuser)

    -- | Makes a user have authorized_keys from the PrivData
    --
    -- This removes any other lines from the file.
    authorizedKeys :: IsContext c => User -> c -> Property (HasInfo + UnixLike)
    authorizedKeys :: forall c.
    IsContext c =>
    User
    -> c
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    authorizedKeys user :: User
    user@(User PubKeyText
    u) c
    context = PrivDataField
    -> c
    -> (((PrivData -> Propellor Result) -> Propellor Result)
        -> Property
             (HasInfo
              + MetaTypes
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall c s metatypes.
    (IsContext c, IsPrivDataSource s,
     IncludesInfo metatypes ~ 'True) =>
    s
    -> c
    -> (((PrivData -> Propellor Result) -> Propellor Result)
        -> Property metatypes)
    -> Property metatypes
    withPrivData (PubKeyText -> PrivDataField
    SshAuthorizedKeys PubKeyText
    u) c
    context ((((PrivData -> Propellor Result) -> Propellor Result)
      -> Property
           (HasInfo
            + MetaTypes
                '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                   'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
     -> Property
          (HasInfo
           + MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (((PrivData -> Propellor Result) -> Propellor Result)
        -> Property
             (HasInfo
              + MetaTypes
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (HasInfo
          + MetaTypes
              '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                 'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \(PrivData -> Propellor Result) -> Propellor Result
    get ->
    	PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' PubKeyText
    desc ((OuterMetaTypesWitness
        '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w -> (PrivData -> Propellor Result) -> Propellor Result
    get ((PrivData -> Propellor Result) -> Propellor Result)
    -> (PrivData -> Propellor Result) -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $ \PrivData
    v -> do
    		f <- IO PubKeyText -> Propellor PubKeyText
    forall a. IO a -> Propellor a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO PubKeyText -> Propellor PubKeyText)
    -> IO PubKeyText -> Propellor PubKeyText
    forall a b. (a -> b) -> a -> b
    $ PubKeyText -> User -> IO PubKeyText
    dotFile PubKeyText
    "authorized_keys" User
    user
    		ensureProperty w $ combineProperties desc $ props
    			& File.hasContentProtected f (keyFileContent (privDataLines v))
    			& File.ownerGroup f user (userGroup user)
    			& File.ownerGroup (takeDirectory f) user (userGroup user)
      where
    	desc :: PubKeyText
    desc = PubKeyText
    u PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " has authorized_keys"

    -- | Ensures that a user's authorized_keys contains a line.
    -- Any other lines in the file are preserved as-is.
    authorizedKey :: User -> String -> RevertableProperty UnixLike UnixLike
    authorizedKey :: User
    -> PubKeyText
    -> RevertableProperty
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    authorizedKey user :: User
    user@(User PubKeyText
    u) PubKeyText
    l = Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    add Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> RevertableProperty
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall setupmetatypes undometatypes.
    Property setupmetatypes
    -> Property undometatypes
    -> RevertableProperty setupmetatypes undometatypes
    <!> Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    remove
      where
    	add :: Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    add = PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' (PubKeyText
    u PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " has authorized_keys") ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w -> do
    		f <- IO PubKeyText -> Propellor PubKeyText
    forall a. IO a -> Propellor a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO PubKeyText -> Propellor PubKeyText)
    -> IO PubKeyText -> Propellor PubKeyText
    forall a b. (a -> b) -> a -> b
    $ PubKeyText -> User -> IO PubKeyText
    dotFile PubKeyText
    "authorized_keys" User
    user
    		ensureProperty w $ modAuthorizedKey f user $
    			f `File.containsLine` l
    				`requires` File.dirExists (takeDirectory f)
    	remove :: Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    remove = PubKeyText
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall {k} (metatypes :: k).
    SingI metatypes =>
    PubKeyText
    -> (OuterMetaTypesWitness metatypes -> Propellor Result)
    -> Property (MetaTypes metatypes)
    property' (PubKeyText
    u PubKeyText -> PubKeyText -> PubKeyText
    forall a. [a] -> [a] -> [a]
    ++ PubKeyText
    " lacks authorized_keys") ((OuterMetaTypesWitness
        '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
           'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
      -> Propellor Result)
     -> Property
          (MetaTypes
             '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> (OuterMetaTypesWitness
          '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
             'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
        -> Propellor Result)
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    forall a b. (a -> b) -> a -> b
    $ \OuterMetaTypesWitness
      '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
         'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
    w -> do
    		f <- IO PubKeyText -> Propellor PubKeyText
    forall a. IO a -> Propellor a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO PubKeyText -> Propellor PubKeyText)
    -> IO PubKeyText -> Propellor PubKeyText
    forall a b. (a -> b) -> a -> b
    $ PubKeyText -> User -> IO PubKeyText
    dotFile PubKeyText
    "authorized_keys" User
    user
    		ifM (liftIO $ doesFileExist f)
    			( ensureProperty w $ modAuthorizedKey f user $
    				f `File.lacksLine` l
    			, return NoChange
    			)

    modAuthorizedKey :: FilePath -> User -> Property UnixLike -> Property UnixLike
    modAuthorizedKey :: PubKeyText
    -> User
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    modAuthorizedKey PubKeyText
    f User
    user Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    p = Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    p
    	Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` PubKeyText
    -> FileMode
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.mode PubKeyText
    f ([FileMode] -> FileMode
    combineModes [FileMode
    ownerWriteMode, FileMode
    ownerReadMode])
    	Property
      (MetaTypes
         '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
            'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> CombinedType
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` PubKeyText
    -> User
    -> Group
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.ownerGroup PubKeyText
    f User
    user (User -> Group
    userGroup User
    user)
    	CombinedType
      (Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
      (Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    -> CombinedType
         (CombinedType
            (Property
               (MetaTypes
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
            (Property
               (MetaTypes
                  '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                     'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])))
         (Property
            (MetaTypes
               '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
                  'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
    forall x y. Combines x y => x -> y -> CombinedType x y
    `before` PubKeyText
    -> User
    -> Group
    -> Property
         (MetaTypes
            '[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
               'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
    File.ownerGroup (PubKeyText -> PubKeyText
    takeDirectory PubKeyText
    f) User
    user (User -> Group
    userGroup User
    user)