summaryrefslogtreecommitdiff
path: root/src/Propellor/Types/PrivData.hs
blob: b66d65463141734ca00890c519f00b1aca1b0e64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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
	| PasswordGenSalt
	deriving (Read, Show, Ord, 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 = id
	describePrivDataSource _ = Nothing

instance IsPrivDataSource PrivDataSource where
	privDataField s = case s of
		PrivDataSourceFile f _ -> f
		PrivDataSourceFileFromCommand f _ _ -> f
		PrivDataSource f _ -> f
	describePrivDataSource s = Just $ case s of
		PrivDataSourceFile _ f -> "< " ++ f
		PrivDataSourceFileFromCommand _ f c ->
			"< " ++ f ++ " (created by running, for example, `" ++ c ++ "` )"
		PrivDataSource _ d -> "< (" ++ d ++ ")"

-- | 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 (Read, Show, Ord, Eq)

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

instance Show HostContext where
	show hc = show $ mkHostContext hc "<hostname>"

instance Ord HostContext where
	a <= b = show a <= show b

instance Eq HostContext where
	a == b = show a == show 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 = flip mkHostContext
	asHostContext = id

instance IsContext Context where
	asContext _ c = c
	asHostContext = HostContext . const

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

-- | Makes a HostContext that consists just of the hostname.
hostContext :: HostContext
hostContext = HostContext 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 s) = lines 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 s) = fromMaybe "" (headMaybe (lines s))

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

data SshKeyType = SshRsa | SshDsa | SshEcdsa | SshEd25519
	deriving (Read, Show, Ord, Eq, Enum, Bounded)

-- | Parameter that would be passed to ssh-keygen to generate key of this type
sshKeyTypeParam :: SshKeyType -> String
sshKeyTypeParam SshRsa = "RSA"
sshKeyTypeParam SshDsa = "DSA"
sshKeyTypeParam SshEcdsa = "ECDSA"
sshKeyTypeParam SshEd25519 = "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 (Read, Show, Ord, Eq, Bounded, Enum)