| @@ -163,6 +163,7 @@ password_file = "/etc/gitbay/imap.pass" # one line, mode 0600, owned by gitbayd |
| 163 | 163 | mailbox = "INBOX" # default |
| 164 | 164 | poll_interval = "1m" # default; at least 10s |
| 165 | 165 | reply_address = "reply@gitbay.example" |
| 166 | require_dkim = true # recommended; see below |
| 166 | 167 | trusted_authserv_id = "mx.example.org" # the mail host's Authentication-Results id |
| 167 | 168 | #+end_src |
| 168 | 169 | |
| @@ -192,9 +193,48 @@ trusted_authserv_id = "mx.example.org" # the mail host's Authentication-Result |
| 192 | 193 | server that sends more than about 11 MiB, or more than a thousand |
| 193 | 194 | untagged responses, for one command has its connection closed; one |
| 194 | 195 | poll handles at most ten thousand messages. |
| 195 | | - =trusted_authserv_id= is required on any instance reachable from the |
| 196 | | internet. It names the authserv-id the mail host writes at the start |
| 197 | | of its =Authentication-Results= header (Gmail's is =mx.google.com=). |
| 196 | - Whatever the settings, a message is refused when a header field name |
| 197 | is not RFC 5322 =ftext= (=From : x=, a space or a non-ASCII byte in a |
| 198 | name), when it does not have exactly one =From=, or when it has more |
| 199 | than one =To=, =Cc=, =Message-ID=, =Content-Type= or |
| 200 | =Content-Transfer-Encoding=. |
| 201 | - =require_dkim= (default false) should be on for any instance |
| 202 | reachable from the internet. With it, a reply is posted only when |
| 203 | gitbayd itself verifies one of its DKIM signatures (RFC 6376) with a |
| 204 | =d== in relaxed alignment with the From domain (the same |
| 205 | organizational domain by the public suffix list; =d=github.io= aligns |
| 206 | with nothing) and an =h== that covers =From=, the =To= or =Cc= holding |
| 207 | the reply address, =Content-Type=, and =Message-ID= when the message |
| 208 | has one. A =Content-Transfer-Encoding= outside =h== is accepted only |
| 209 | when it is =7bit=, =8bit= or =binary=, which leave the decoded body as |
| 210 | it is; Thunderbird, for one, does not sign it. An unsigned |
| 211 | =quoted-printable= or =base64= is refused. The reply |
| 212 | address is read only from =To= or =Cc=: a reply that reached the |
| 213 | mailbox by Bcc, with the address only in =Delivered-To=, is refused |
| 214 | ("reply address not in To or Cc"). It needs nothing from the mail |
| 215 | host, so it works where the host adds no =Authentication-Results=. |
| 216 | rsa-sha256 (keys of 1024 bits or more) and ed25519-sha256 are |
| 217 | accepted, with simple or relaxed canonicalization; rsa-sha1, a body |
| 218 | length tag (=l==), an expired =x== and a =t== more than fifteen |
| 219 | minutes ahead are refused. Only the first five signatures are |
| 220 | checked. The key is looked up at =<s>._domainkey.<d>= with a |
| 221 | five-second timeout and cached for fifteen minutes (the resolver does |
| 222 | not report the record's TTL); a lookup that fails for a reason that |
| 223 | may pass (a timeout, SERVFAIL) leaves the message for the next poll, |
| 224 | up to the five tries above, while a missing key refuses it. |
| 225 | Signatures are checked on the message as fetched. Each passing |
| 226 | signature is recorded with the =Message-ID=, so a copy of the same |
| 227 | signed message posts once even with unsigned fields changed. |
| 228 | - Either =require_dkim= or =trusted_authserv_id= passing is enough to |
| 229 | authenticate =From=; when both are set, a reply needs only one of |
| 230 | them, and a refusal names both reasons. With only |
| 231 | =trusted_authserv_id=, the reply address may come from any recipient |
| 232 | field (=Delivered-To=, =X-Original-To=, =Envelope-To=, =To=, =Cc=), |
| 233 | since the mail host vouches for the sender and not for the fields. |
| 234 | Set both when the mail host adds =Authentication-Results= for most |
| 235 | senders but not all. |
| 236 | - =trusted_authserv_id= names the authserv-id the mail host writes at |
| 237 | the start of its =Authentication-Results= header (Gmail's is =mx.google.com=). |
| 198 | 238 | With it set, a reply is posted only when the topmost header with that |
| 199 | 239 | id shows =dmarc=pass= with =header.from= equal to the From domain, or |
| 200 | 240 | =dkim=pass= with a =header.d= in relaxed alignment with it (the same |
| @@ -205,19 +245,24 @@ trusted_authserv_id = "mx.example.org" # the mail host's Authentication-Result |
| 205 | 245 | claiming the same id are the sender's and are not read. This is only safe when the mail host |
| 206 | 246 | removes incoming =Authentication-Results= headers that claim its id, |
| 207 | 247 | as RFC 8601 asks; Gmail, Fastmail and Migadu do. Check yours before |
| 208 | | relying on it. Unset, the daemon logs a warning at start and =admin |
| 209 | | mail inbound check= repeats it: without it, =From= is whatever the |
| 210 | | sender wrote. Mail between two addresses at the same host may carry |
| 211 | | no =Authentication-Results= at all: at Migadu, mail from another |
| 248 | relying on it. With neither this nor =require_dkim= set, the daemon |
| 249 | logs a warning at start and =admin mail inbound check= repeats it: |
| 250 | =From= is then whatever the sender wrote. Mail between two addresses |
| 251 | at the same host may carry no =Authentication-Results= at all: at |
| 252 | Migadu, mail from another |
| 212 | 253 | Migadu-hosted domain is delivered through its outbound path and gets |
| 213 | | none, so setting the id refuses every reply from such users. |
| 214 | | gitbay.org runs without it for that reason until gitbayd verifies |
| 215 | | DKIM itself (#307). |
| 254 | none, so setting the id alone refuses every reply from such users. |
| 255 | That mail does carry a DKIM signature aligned with =From= (for |
| 256 | example =d=cleberg.net; s=key1; a=rsa-sha256; c=simple/simple; |
| 257 | h=from:to:subject:date:message-id:mime-version:content-type=), which |
| 258 | is why gitbay.org sets =require_dkim= instead. |
| 216 | 259 | - =gitbay admin mail inbound check= logs in, opens the mailbox |
| 217 | | read-only (EXAMINE) and reports the message and unseen counts, so a |
| 218 | | check never marks a reply seen before the poller reads it. With |
| 219 | | inbound off it says so and exits 0. Poll failures are logged as |
| 220 | | =mail reply: poll failed= with the server and the IMAP error. |
| 260 | read-only (EXAMINE) and reports the message and unseen counts and how |
| 261 | =From= is authenticated (=require_dkim=, =trusted_authserv_id=), so a |
| 262 | check never marks a reply seen before the poller reads it. It warns |
| 263 | when neither is set. With inbound off it says so and exits 0. Poll |
| 264 | failures are logged as =mail reply: poll failed= with the server and |
| 265 | the IMAP error. |
| 221 | 266 | |
| 222 | 267 | A reply is posted when all of these hold, checked when it is read: |
| 223 | 268 | |
| @@ -230,7 +275,8 @@ A reply is posted when all of these hold, checked when it is read: |
| 230 | 275 | by a delete and reused is not the account the token named. The same |
| 231 | 276 | holds for the repository. |
| 232 | 277 | 4. =From= is one of that account's verified addresses, and, with |
| 233 | | =trusted_authserv_id= set, the mail host authenticated it. |
| 278 | =require_dkim= or =trusted_authserv_id= set, a DKIM signature |
| 279 | gitbayd verified or the mail host's result authenticated it. |
| 234 | 280 | 5. The message has a =text/plain= part (HTML-only mail is refused, not |
| 235 | 281 | converted), and what is left after quoted text and the signature |
| 236 | 282 | are removed is not empty and fits a comment (64 KiB). |