module Propellor.Types.PrivData where

import Propellor.Types.OS
import Utility.PartialPrelude
import Utility.FileSystemEncoding

import Data.Maybe
import qualified Data.ByteString.Lazy as L

-- | Note that removing or changing constructors or changing types will
-- break the serialized privdata files, so don't do that!
-- It's fine to add new constructors.
data PrivDataField
	= DockerAuthentication
	| SshPubKey SshKeyType UserName -- ^ Not used anymore, but retained to avoid breaking serialization of old files
	| SshPrivKey SshKeyType UserName -- ^ For host key, use empty UserName
	| SshAuthorizedKeys UserName
	| Password UserName
	| CryptPassword UserName
	| PrivFile FilePath
	| GpgKey
	| DnsSec DnsSecKey
	deriving (ReadPrec [PrivDataField]
ReadPrec PrivDataField
Int -> ReadS PrivDataField
ReadS [PrivDataField]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [PrivDataField]
$creadListPrec :: ReadPrec [PrivDataField]
readPrec :: ReadPrec PrivDataField
$creadPrec :: ReadPrec PrivDataField
readList :: ReadS [PrivDataField]
$creadList :: ReadS [PrivDataField]
readsPrec :: Int -> ReadS PrivDataField
$creadsPrec :: Int -> ReadS PrivDataField
Read, Int -> PrivDataField -> ShowS
[PrivDataField] -> ShowS
PrivDataField -> UserName
forall a.
(Int -> a -> ShowS) -> (a -> UserName) -> ([a] -> ShowS) -> Show a
showList :: [PrivDataField] -> ShowS
$cshowList :: [PrivDataField] -> ShowS
show :: PrivDataField -> UserName
$cshow :: PrivDataField -> UserName
showsPrec :: Int -> PrivDataField -> ShowS
$cshowsPrec :: Int -> PrivDataField -> ShowS
Show, Eq PrivDataField
PrivDataField -> PrivDataField -> Bool
PrivDataField -> PrivDataField -> Ordering
PrivDataField -> PrivDataField -> PrivDataField
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
min :: PrivDataField -> PrivDataField -> PrivDataField
$cmin :: PrivDataField -> PrivDataField -> PrivDataField
max :: PrivDataField -> PrivDataField -> PrivDataField
$cmax :: PrivDataField -> PrivDataField -> PrivDataField
>= :: PrivDataField -> PrivDataField -> Bool
$c>= :: PrivDataField -> PrivDataField -> Bool
> :: PrivDataField -> PrivDataField -> Bool
$c> :: PrivDataField -> PrivDataField -> Bool
<= :: PrivDataField -> PrivDataField -> Bool
$c<= :: PrivDataField -> PrivDataField -> Bool
< :: PrivDataField -> PrivDataField -> Bool
$c< :: PrivDataField -> PrivDataField -> Bool
compare :: PrivDataField -> PrivDataField -> Ordering
$ccompare :: PrivDataField -> PrivDataField -> Ordering
Ord, PrivDataField -> PrivDataField -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PrivDataField -> PrivDataField -> Bool
$c/= :: PrivDataField -> PrivDataField -> Bool
== :: PrivDataField -> PrivDataField -> Bool
$c== :: PrivDataField -> PrivDataField -> Bool
Eq)

-- | Combines a PrivDataField with a description of how to generate
-- its value.
data PrivDataSource
	= PrivDataSourceFile PrivDataField FilePath
	| PrivDataSourceFileFromCommand PrivDataField FilePath String
	| PrivDataSource PrivDataField String

type PrivDataSourceDesc = String

class IsPrivDataSource s where
	privDataField :: s -> PrivDataField
	describePrivDataSource :: s -> Maybe PrivDataSourceDesc

instance IsPrivDataSource PrivDataField where
	privDataField :: PrivDataField -> PrivDataField
privDataField = forall a. a -> a
id
	describePrivDataSource :: PrivDataField -> Maybe UserName
describePrivDataSource PrivDataField
_ = forall a. Maybe a
Nothing

instance IsPrivDataSource PrivDataSource where
	privDataField :: PrivDataSource -> PrivDataField
privDataField PrivDataSource
s = case PrivDataSource
s of
		PrivDataSourceFile PrivDataField
f UserName
_ -> PrivDataField
f
		PrivDataSourceFileFromCommand PrivDataField
f UserName
_ UserName
_ -> PrivDataField
f
		PrivDataSource PrivDataField
f UserName
_ -> PrivDataField
f
	describePrivDataSource :: PrivDataSource -> Maybe UserName
describePrivDataSource PrivDataSource
s = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ case PrivDataSource
s of
		PrivDataSourceFile PrivDataField
_ UserName
f -> UserName
"< " forall a. [a] -> [a] -> [a]
++ UserName
f
		PrivDataSourceFileFromCommand PrivDataField
_ UserName
f UserName
c ->
			UserName
"< " forall a. [a] -> [a] -> [a]
++ UserName
f forall a. [a] -> [a] -> [a]
++ UserName
" (created by running, for example, `" forall a. [a] -> [a] -> [a]
++ UserName
c forall a. [a] -> [a] -> [a]
++ UserName
"` )"
		PrivDataSource PrivDataField
_ UserName
d -> UserName
"< (" forall a. [a] -> [a] -> [a]
++ UserName
d forall a. [a] -> [a] -> [a]
++ UserName
")"

-- | A context in which a PrivDataField is used.
--
-- Often this will be a domain name. For example, 
-- Context "www.example.com" could be used for the SSL cert
-- for the web server serving that domain. Multiple hosts might
-- use that privdata.
--
-- This appears in serialized privdata files.
newtype Context = Context String
	deriving (ReadPrec [Context]
ReadPrec Context
Int -> ReadS Context
ReadS [Context]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Context]
$creadListPrec :: ReadPrec [Context]
readPrec :: ReadPrec Context
$creadPrec :: ReadPrec Context
readList :: ReadS [Context]
$creadList :: ReadS [Context]
readsPrec :: Int -> ReadS Context
$creadsPrec :: Int -> ReadS Context
Read, Int -> Context -> ShowS
[Context] -> ShowS
Context -> UserName
forall a.
(Int -> a -> ShowS) -> (a -> UserName) -> ([a] -> ShowS) -> Show a
showList :: [Context] -> ShowS
$cshowList :: [Context] -> ShowS
show :: Context -> UserName
$cshow :: Context -> UserName
showsPrec :: Int -> Context -> ShowS
$cshowsPrec :: Int -> Context -> ShowS
Show, Eq Context
Context -> Context -> Bool
Context -> Context -> Ordering
Context -> Context -> Context
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
min :: Context -> Context -> Context
$cmin :: Context -> Context -> Context
max :: Context -> Context -> Context
$cmax :: Context -> Context -> Context
>= :: Context -> Context -> Bool
$c>= :: Context -> Context -> Bool
> :: Context -> Context -> Bool
$c> :: Context -> Context -> Bool
<= :: Context -> Context -> Bool
$c<= :: Context -> Context -> Bool
< :: Context -> Context -> Bool
$c< :: Context -> Context -> Bool
compare :: Context -> Context -> Ordering
$ccompare :: Context -> Context -> Ordering
Ord, Context -> Context -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Context -> Context -> Bool
$c/= :: Context -> Context -> Bool
== :: Context -> Context -> Bool
$c== :: Context -> Context -> Bool
Eq)

-- | A context that may vary depending on the HostName where it's used.
newtype HostContext = HostContext { HostContext -> UserName -> Context
mkHostContext :: HostName -> Context }

instance Show HostContext where
	show :: HostContext -> UserName
show HostContext
hc = forall a. Show a => a -> UserName
show forall a b. (a -> b) -> a -> b
$ HostContext -> UserName -> Context
mkHostContext HostContext
hc UserName
"<hostname>"

instance Ord HostContext where
	HostContext
a <= :: HostContext -> HostContext -> Bool
<= HostContext
b = forall a. Show a => a -> UserName
show HostContext
a forall a. Ord a => a -> a -> Bool
<= forall a. Show a => a -> UserName
show HostContext
b

instance Eq HostContext where
	HostContext
a == :: HostContext -> HostContext -> Bool
== HostContext
b = forall a. Show a => a -> UserName
show HostContext
a forall a. Eq a => a -> a -> Bool
== forall a. Show a => a -> UserName
show HostContext
b

-- | Class of things that can be used as a Context.
class IsContext c where
	asContext :: HostName -> c -> Context
	asHostContext :: c -> HostContext

instance IsContext HostContext where
	asContext :: UserName -> HostContext -> Context
asContext = forall a b c. (a -> b -> c) -> b -> a -> c
flip HostContext -> UserName -> Context
mkHostContext
	asHostContext :: HostContext -> HostContext
asHostContext = forall a. a -> a
id

instance IsContext Context where
	asContext :: UserName -> Context -> Context
asContext UserName
_ Context
c = Context
c
	asHostContext :: Context -> HostContext
asHostContext = (UserName -> Context) -> HostContext
HostContext forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> b -> a
const

-- | Use when a PrivDataField is not dependent on any paricular context.
anyContext :: Context
anyContext :: Context
anyContext = UserName -> Context
Context UserName
"any"

-- | Makes a HostContext that consists just of the hostname.
hostContext :: HostContext
hostContext :: HostContext
hostContext = (UserName -> Context) -> HostContext
HostContext UserName -> Context
Context

-- | Contains the actual private data.
--
-- Note that this may contain exta newlines at the end, or they may have
-- been stripped off, depending on how the user entered the privdata,
-- and which version of propellor stored it. Use the accessor functions
-- below to avoid newline problems.
newtype PrivData = PrivData String

-- | When PrivData is the content of a file, this is the lines thereof.
privDataLines :: PrivData -> [String]
privDataLines :: PrivData -> [UserName]
privDataLines (PrivData UserName
s) = UserName -> [UserName]
lines UserName
s

-- | When the PrivData is a single value, like a password, this extracts
-- it. Note that if multiple lines are present in the PrivData, only
-- the first is returned; there is never a newline in the String.
privDataVal :: PrivData -> String
privDataVal :: PrivData -> UserName
privDataVal (PrivData UserName
s) = forall a. a -> Maybe a -> a
fromMaybe UserName
"" (forall a. [a] -> Maybe a
headMaybe (UserName -> [UserName]
lines UserName
s))

-- | Use to get ByteString out of PrivData.
privDataByteString :: PrivData -> L.ByteString
privDataByteString :: PrivData -> ByteString
privDataByteString (PrivData UserName
s) = UserName -> ByteString
encodeBS UserName
s

data SshKeyType = SshRsa | SshDsa | SshEcdsa | SshEd25519
	deriving (ReadPrec [SshKeyType]
ReadPrec SshKeyType
Int -> ReadS SshKeyType
ReadS [SshKeyType]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [SshKeyType]
$creadListPrec :: ReadPrec [SshKeyType]
readPrec :: ReadPrec SshKeyType
$creadPrec :: ReadPrec SshKeyType
readList :: ReadS [SshKeyType]
$creadList :: ReadS [SshKeyType]
readsPrec :: Int -> ReadS SshKeyType
$creadsPrec :: Int -> ReadS SshKeyType
Read, Int -> SshKeyType -> ShowS
[SshKeyType] -> ShowS
SshKeyType -> UserName
forall a.
(Int -> a -> ShowS) -> (a -> UserName) -> ([a] -> ShowS) -> Show a
showList :: [SshKeyType] -> ShowS
$cshowList :: [SshKeyType] -> ShowS
show :: SshKeyType -> UserName
$cshow :: SshKeyType -> UserName
showsPrec :: Int -> SshKeyType -> ShowS
$cshowsPrec :: Int -> SshKeyType -> ShowS
Show, Eq SshKeyType
SshKeyType -> SshKeyType -> Bool
SshKeyType -> SshKeyType -> Ordering
SshKeyType -> SshKeyType -> SshKeyType
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
min :: SshKeyType -> SshKeyType -> SshKeyType
$cmin :: SshKeyType -> SshKeyType -> SshKeyType
max :: SshKeyType -> SshKeyType -> SshKeyType
$cmax :: SshKeyType -> SshKeyType -> SshKeyType
>= :: SshKeyType -> SshKeyType -> Bool
$c>= :: SshKeyType -> SshKeyType -> Bool
> :: SshKeyType -> SshKeyType -> Bool
$c> :: SshKeyType -> SshKeyType -> Bool
<= :: SshKeyType -> SshKeyType -> Bool
$c<= :: SshKeyType -> SshKeyType -> Bool
< :: SshKeyType -> SshKeyType -> Bool
$c< :: SshKeyType -> SshKeyType -> Bool
compare :: SshKeyType -> SshKeyType -> Ordering
$ccompare :: SshKeyType -> SshKeyType -> Ordering
Ord, SshKeyType -> SshKeyType -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SshKeyType -> SshKeyType -> Bool
$c/= :: SshKeyType -> SshKeyType -> Bool
== :: SshKeyType -> SshKeyType -> Bool
$c== :: SshKeyType -> SshKeyType -> Bool
Eq, Int -> SshKeyType
SshKeyType -> Int
SshKeyType -> [SshKeyType]
SshKeyType -> SshKeyType
SshKeyType -> SshKeyType -> [SshKeyType]
SshKeyType -> SshKeyType -> SshKeyType -> [SshKeyType]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: SshKeyType -> SshKeyType -> SshKeyType -> [SshKeyType]
$cenumFromThenTo :: SshKeyType -> SshKeyType -> SshKeyType -> [SshKeyType]
enumFromTo :: SshKeyType -> SshKeyType -> [SshKeyType]
$cenumFromTo :: SshKeyType -> SshKeyType -> [SshKeyType]
enumFromThen :: SshKeyType -> SshKeyType -> [SshKeyType]
$cenumFromThen :: SshKeyType -> SshKeyType -> [SshKeyType]
enumFrom :: SshKeyType -> [SshKeyType]
$cenumFrom :: SshKeyType -> [SshKeyType]
fromEnum :: SshKeyType -> Int
$cfromEnum :: SshKeyType -> Int
toEnum :: Int -> SshKeyType
$ctoEnum :: Int -> SshKeyType
pred :: SshKeyType -> SshKeyType
$cpred :: SshKeyType -> SshKeyType
succ :: SshKeyType -> SshKeyType
$csucc :: SshKeyType -> SshKeyType
Enum, SshKeyType
forall a. a -> a -> Bounded a
maxBound :: SshKeyType
$cmaxBound :: SshKeyType
minBound :: SshKeyType
$cminBound :: SshKeyType
Bounded)

-- | Parameter that would be passed to ssh-keygen to generate key of this type
sshKeyTypeParam :: SshKeyType -> String
sshKeyTypeParam :: SshKeyType -> UserName
sshKeyTypeParam SshKeyType
SshRsa = UserName
"RSA"
sshKeyTypeParam SshKeyType
SshDsa = UserName
"DSA"
sshKeyTypeParam SshKeyType
SshEcdsa = UserName
"ECDSA"
sshKeyTypeParam SshKeyType
SshEd25519 = UserName
"ED25519"

data DnsSecKey
	= PubZSK -- ^ DNSSEC Zone Signing Key (public)
	| PrivZSK -- ^ DNSSEC Zone Signing Key (private)
	| PubKSK -- ^ DNSSEC Key Signing Key (public)
	| PrivKSK -- ^ DNSSEC Key Signing Key (private)
	deriving (ReadPrec [DnsSecKey]
ReadPrec DnsSecKey
Int -> ReadS DnsSecKey
ReadS [DnsSecKey]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [DnsSecKey]
$creadListPrec :: ReadPrec [DnsSecKey]
readPrec :: ReadPrec DnsSecKey
$creadPrec :: ReadPrec DnsSecKey
readList :: ReadS [DnsSecKey]
$creadList :: ReadS [DnsSecKey]
readsPrec :: Int -> ReadS DnsSecKey
$creadsPrec :: Int -> ReadS DnsSecKey
Read, Int -> DnsSecKey -> ShowS
[DnsSecKey] -> ShowS
DnsSecKey -> UserName
forall a.
(Int -> a -> ShowS) -> (a -> UserName) -> ([a] -> ShowS) -> Show a
showList :: [DnsSecKey] -> ShowS
$cshowList :: [DnsSecKey] -> ShowS
show :: DnsSecKey -> UserName
$cshow :: DnsSecKey -> UserName
showsPrec :: Int -> DnsSecKey -> ShowS
$cshowsPrec :: Int -> DnsSecKey -> ShowS
Show, Eq DnsSecKey
DnsSecKey -> DnsSecKey -> Bool
DnsSecKey -> DnsSecKey -> Ordering
DnsSecKey -> DnsSecKey -> DnsSecKey
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
min :: DnsSecKey -> DnsSecKey -> DnsSecKey
$cmin :: DnsSecKey -> DnsSecKey -> DnsSecKey
max :: DnsSecKey -> DnsSecKey -> DnsSecKey
$cmax :: DnsSecKey -> DnsSecKey -> DnsSecKey
>= :: DnsSecKey -> DnsSecKey -> Bool
$c>= :: DnsSecKey -> DnsSecKey -> Bool
> :: DnsSecKey -> DnsSecKey -> Bool
$c> :: DnsSecKey -> DnsSecKey -> Bool
<= :: DnsSecKey -> DnsSecKey -> Bool
$c<= :: DnsSecKey -> DnsSecKey -> Bool
< :: DnsSecKey -> DnsSecKey -> Bool
$c< :: DnsSecKey -> DnsSecKey -> Bool
compare :: DnsSecKey -> DnsSecKey -> Ordering
$ccompare :: DnsSecKey -> DnsSecKey -> Ordering
Ord, DnsSecKey -> DnsSecKey -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DnsSecKey -> DnsSecKey -> Bool
$c/= :: DnsSecKey -> DnsSecKey -> Bool
== :: DnsSecKey -> DnsSecKey -> Bool
$c== :: DnsSecKey -> DnsSecKey -> Bool
Eq, DnsSecKey
forall a. a -> a -> Bounded a
maxBound :: DnsSecKey
$cmaxBound :: DnsSecKey
minBound :: DnsSecKey
$cminBound :: DnsSecKey
Bounded, Int -> DnsSecKey
DnsSecKey -> Int
DnsSecKey -> [DnsSecKey]
DnsSecKey -> DnsSecKey
DnsSecKey -> DnsSecKey -> [DnsSecKey]
DnsSecKey -> DnsSecKey -> DnsSecKey -> [DnsSecKey]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: DnsSecKey -> DnsSecKey -> DnsSecKey -> [DnsSecKey]
$cenumFromThenTo :: DnsSecKey -> DnsSecKey -> DnsSecKey -> [DnsSecKey]
enumFromTo :: DnsSecKey -> DnsSecKey -> [DnsSecKey]
$cenumFromTo :: DnsSecKey -> DnsSecKey -> [DnsSecKey]
enumFromThen :: DnsSecKey -> DnsSecKey -> [DnsSecKey]
$cenumFromThen :: DnsSecKey -> DnsSecKey -> [DnsSecKey]
enumFrom :: DnsSecKey -> [DnsSecKey]
$cenumFrom :: DnsSecKey -> [DnsSecKey]
fromEnum :: DnsSecKey -> Int
$cfromEnum :: DnsSecKey -> Int
toEnum :: Int -> DnsSecKey
$ctoEnum :: Int -> DnsSecKey
pred :: DnsSecKey -> DnsSecKey
$cpred :: DnsSecKey -> DnsSecKey
succ :: DnsSecKey -> DnsSecKey
$csucc :: DnsSecKey -> DnsSecKey
Enum)