oficina / calendar Public

Clone
git clone https://amadan.net/oficina/calendar

Plain git — no account needed to clone.

Download

Download this file

1package calendar
2
3import (
4 "errors"
5 "regexp"
6)
7
8// addressPattern matches an email address well enough to redact one.
9//
10// Deliberately loose. A redactor that misses is worse than one that
11// over-matches, so this takes anything shaped like local@domain.tld
12// rather than trying to implement RFC 5322 — the cost of a false
13// positive here is a log line that says [address] where it could have
14// said a hostname, and the cost of a false negative is a real person's
15// address in platform-held storage we cannot go back and grep.
16var addressPattern = regexp.MustCompile(`[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}`)
17
18// scrub removes email addresses from a string bound for the log.
19//
20// AGENTS.md §Logs: no title, place, note or address in any log line,
21// error string or metric label. `carlos logs` is platform-held storage
22// we cannot grep afterwards, so the rule has to be applied BEFORE the
23// line is written, not apologised for later.
24//
25// This exists because the rule was being broken on every failed send
26// and not by this app's own code: rastrillo's mailer formats the
27// recipient into its error ("send to %s: ..."), and logging that error
28// verbatim — which is the obvious, careful-looking thing to do — put
29// the address straight into the log. An error from a dependency is
30// still an error string we are writing.
31func scrub(s string) string {
32 return addressPattern.ReplaceAllString(s, "[address]")
33}
34
35// scrubErr is scrub for an error, returning a string rather than an
36// error so a caller cannot accidentally log the original by wrapping
37// the result.
38func scrubErr(err error) string {
39 if err == nil {
40 return ""
41 }
42 return scrub(err.Error())
43}
44
45// mailCode reduces a sender's error to a word. The sender's TEXT is
46// never logged: rastrillo's SMTP sender quotes the whole subject when
47// it refuses a header, and a subject carries the title and the booker's
48// name. Scrubbing addresses out of that is not enough.
49func mailCode(err error) string {
50 switch {
51 case err == nil:
52 return "ok"
53 case errors.Is(err, ErrMailBusy):
54 return "busy"
55 case errors.Is(err, ErrMailTimeout):
56 return "timeout"
57 default:
58 return "refused"
59 }
60}
61