| 1 | package calendar |
| 2 | |
| 3 | import ( |
| 4 | "net/http" |
| 5 | |
| 6 | "amadan.net/oficina/home/connect" |
| 7 | ) |
| 8 | |
| 9 | // beginSignin is POST /signin, in both modes: rauth's Begin for EVERY |
| 10 | // address, under connect.OAuthContinuation. What the form answers |
| 11 | // depends on the address's domain alone, never on the allowlist — any |
| 12 | // difference between a permitted and a non-permitted address would |
| 13 | // turn this endpoint into a membership oracle. |
| 14 | // |
| 15 | // - A Keymail address (keymail.dev itself, or a domain delegating to |
| 16 | // Keymail with a `_keymail` TXT record), permitted or not, goes to |
| 17 | // Keymail. Begin answers with a 303 to Keymail's authorize URL, |
| 18 | // which OAuthContinuation turns into a page (renderKeymail): CSP's |
| 19 | // form-action 'self' covers a form submission's whole redirect |
| 20 | // chain in Safari, so a 303 out of the POST would be refused. |
| 21 | // Admission is asked only after Keymail has verified the address, |
| 22 | // by rauth's Authorize, and its refusal is the door saying so |
| 23 | // (rauth's Refused hook, handlers.refused) — told only to someone |
| 24 | // who has just proved they hold the address. |
| 25 | // - Any other address is answered ?sent=1, and mailQueue mails the |
| 26 | // link only if the allowlist holds it — after the response, in a |
| 27 | // worker, so not even the response time differs (signin_mail.go) — |
| 28 | // and this app's sending identity is no open relay for whatever a |
| 29 | // stranger types. |
| 30 | // |
| 31 | // Both kinds of address spend the same rate budgets and parse the same |
| 32 | // way, and a failed send is logged after the response, not answered. |
| 33 | // |
| 34 | // It used to gate the allowlist in front of Begin and set force=1 on |
| 35 | // every permitted request, which kept Keymail out of Calendar |
| 36 | // altogether. Paul ruled on 2026-10-06 that Calendar uses Keymail. |
| 37 | // force now arrives only from the form rastrillo lands a failed |
| 38 | // Keymail exchange on (?force=1&err=keymail), and asks for an emailed |
| 39 | // link instead, so nobody is stuck. |
| 40 | func beginSignin(origin string, begin http.HandlerFunc, render func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { |
| 41 | return connect.OAuthContinuation(origin, begin, render) |
| 42 | } |
| 43 | |