dynamic_config_server/config/
refusal.rs1use std::fmt;
9
10use crate::auth::MIN_TOKEN_LEN;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
18#[non_exhaustive]
19pub enum Refusal {
20 NoSections,
22 NoClients,
24 DuplicateSection {
26 application: String,
28 profile: String,
30 },
31 UnroutableSection {
34 application: String,
36 profile: String,
38 part: &'static str,
40 },
41 DuplicateClient {
43 name: String,
45 },
46 DuplicateToken,
48 WeakToken {
50 client: String,
52 },
53 AnonymousNotAllowed {
55 client: String,
57 },
58 SeveralAnonymousClients,
61 UnservedGrant {
63 client: String,
65 application: String,
67 },
68 ExposedBind {
70 bind: String,
72 },
73 UnparsableBind {
75 bind: String,
77 },
78 TlsUnsupported,
80 InsecureWithTls,
83 TlsPathMissing {
85 key: &'static str,
87 },
88 RevocationUnsupported,
91}
92
93impl fmt::Display for Refusal {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 match self {
96 Self::NoSections => {
97 f.write_str("no `sections` are configured: this server would serve nothing at all")
98 }
99 Self::NoClients => f.write_str(
100 "no `clients` are configured: nothing could ever be read. Add a client with \
101 a `token` and the `applications` it may read, or an anonymous one with \
102 `allow_anonymous = true`",
103 ),
104 Self::DuplicateSection {
105 application,
106 profile,
107 } => write!(
108 f,
109 "two `sections` claim `{application}`/`{profile}`; one application and \
110 profile is served by exactly one section"
111 ),
112 Self::UnroutableSection {
113 application,
114 profile,
115 part,
116 } => write!(
117 f,
118 "the section `{application}`/`{profile}` has a `{part}` no request can \
119 name: a path segment is up to 64 characters, starts with a letter or a \
120 digit, and carries only letters, digits, `.`, `_` and `-`. The server \
121 would start, report ready and answer `404` for that section forever"
122 ),
123 Self::DuplicateClient { name } => {
124 write!(f, "two `clients` are named `{name}`; names identify a caller in the audit log and must be unique")
125 }
126 Self::DuplicateToken => f.write_str(
127 "two `clients` share a `token`; the first listed would silently win every \
128 request and the audit log would name the wrong caller",
129 ),
130 Self::WeakToken { client } => write!(
131 f,
132 "the `token` for client `{client}` is shorter than {MIN_TOKEN_LEN} characters"
133 ),
134 Self::AnonymousNotAllowed { client } => write!(
135 f,
136 "client `{client}` has no `token`, which makes it the anonymous caller; set \
137 `allow_anonymous = true` to say that is intended, or give it a token"
138 ),
139 Self::SeveralAnonymousClients => f.write_str(
140 "more than one client has no `token`; there is one anonymous caller, so it \
141 can have only one set of grants",
142 ),
143 Self::UnservedGrant {
144 client,
145 application,
146 } => write!(
147 f,
148 "client `{client}` is granted `{application}`, which no section serves; a \
149 grant that matches nothing is a typo that reads as a working deployment"
150 ),
151 Self::ExposedBind { bind } => write!(
152 f,
153 "`bind` is `{bind}`, which is not loopback, and this server is terminating no \
154 TLS: that would put configuration — secrets included — on the network in the \
155 clear. Terminate TLS here with a `[server.tls]` section, or put a terminator \
156 in front of it and set `insecure = true` to say so, or bind loopback"
157 ),
158 Self::UnparsableBind { bind } => write!(
159 f,
160 "`bind` is `{bind}`, which is not a literal `address:port`; a hostname is \
161 refused rather than resolved"
162 ),
163 Self::TlsUnsupported => f.write_str(
164 "`[server.tls]` is configured, but this binary was built without the `tls` \
165 feature and contains no TLS at all. Rebuild it with `--features tls`, or \
166 remove `[server.tls]` and put a terminator in front",
167 ),
168 Self::InsecureWithTls => f.write_str(
169 "`insecure = true` is set and `[server.tls]` is configured. `insecure` \
170 acknowledges that this server's own socket is unencrypted, which is no longer \
171 true — remove it, so that removing the TLS section later refuses again \
172 instead of quietly serving in the clear",
173 ),
174 Self::TlsPathMissing { key } => {
175 write!(f, "`tls.{key}` is empty; it has to name a PEM file")
176 }
177 Self::RevocationUnsupported => f.write_str(
178 "`tls.crl` is configured, but this server checks no certificate revocation and \
179 will not pretend to. A CRL whose `nextUpdate` has passed is accepted silently \
180 by default, so the list would stop being true the moment it stopped being \
181 refreshed and nothing would report it; the one setting that refuses a stale \
182 list refuses every client along with it, which turns a publishing hiccup into \
183 an outage for every service at once. Remove the key. Issue short-lived client \
184 certificates, and revoke the `token` — delete the client's line and restart — \
185 which is the credential that actually authorises here",
186 ),
187 }
188 }
189}
190
191impl std::error::Error for Refusal {}