installer API: reference handler (internal/installapi), SMTP mailer with STARTTLS, plain+HTML code template, rate limits; verae-mailtest; user-token.ps1 validates via Go; stricter key masking
This commit is contained in:
parent
6e76bc7b0e
commit
1317bea604
1 changed files with 1249 additions and 5 deletions
|
|
@ -1,6 +1,7 @@
|
|||
# Verae installer registration API (proposed)
|
||||
|
||||
Status: **proposal + client implementation**. The client side is implemented in
|
||||
Status: **proposal + client implementation + reference server pieces**
|
||||
(`internal/installapi` handler, `internal/mailer` SMTP mailer; §7). The client side is implemented in
|
||||
`internal/auth/portal_install.go` and driven by the Windows installer
|
||||
(`platform/windows/installer-debug.nsi` → `verae-print installer-account`).
|
||||
The server side does **not exist yet**. The portal backend source was not
|
||||
|
|
@ -202,3 +203,33 @@ components:
|
|||
| Verify email | `--op verify`; "Send a new code" → `--op resend` |
|
||||
| Paste key | button opens customer.verae.ai; `validate-key` before Next |
|
||||
| Skip | warning; the helper shows a key dialog on first print and holds the job until a key is saved |
|
||||
|
||||
## 7. Reference server implementation and email delivery
|
||||
|
||||
* `internal/installapi`: `Server.Handler()` serves `/install/capabilities|register|verify|resend|login`. Mount it under `/portal/api` in the portal backend. Account storage goes through the `Accounts` interface (`EmailExists`, `HashPassword`, `CreateAccount`, `Authenticate` → `ErrTOTPRequired`/`ErrTOTPInvalid`/`ErrInvalidCredentials`, `MintToken`), so it plugs into the existing portal DB and token code.
|
||||
* At `/register` the password is hashed immediately. The plaintext is never kept in the pending record and is never logged.
|
||||
* Codes are stored as salted SHA-256 and compared in constant time. They are single use, with a 15 min TTL and 5 attempts.
|
||||
* An existing email gets a 202 plus an "you already have an account" email, so the endpoint reveals nothing.
|
||||
* Logs contain masked emails only. Responses use `Cache-Control: no-store`.
|
||||
* Pending sign-ups and rate-limit counters live in memory. Use a shared store (Redis/DB) when running more than one replica.
|
||||
* `internal/mailer`: SMTP sender with mandatory STARTTLS (port 587) or implicit TLS (465), TLS ≥ 1.2, and AUTH PLAIN only after TLS. The SMTP password is scrubbed from every error and is never shown by `Config.String()`. Recipients and subjects are checked against header injection.
|
||||
* Template: `CodeEmail` (multipart/alternative: plain text + responsive HTML, code shown as `123 456`, expiry, "ignore if this wasn't you") and `AccountExistsEmail`.
|
||||
* Rate limits (`DefaultLimits`, sliding window): 60 s resend cooldown per address, 5 codes/h per address, 10/h per client IP, 20/min and 400/day globally. Gmail caps a normal account at about 500 recipients/day, so move to a transactional provider before real volume.
|
||||
|
||||
### Mailer configuration (environment only; never commit credentials)
|
||||
|
||||
| Variable | Value |
|
||||
|---|---|
|
||||
| `SMTP_HOST` | `smtp.gmail.com` (default) |
|
||||
| `SMTP_PORT` | `587` (default; STARTTLS) |
|
||||
| `SMTP_USER` | `veraetimestamp@gmail.com` |
|
||||
| `SMTP_PASS` | Gmail **app password** for that account, from your secret store. Never put it in files, logs or the repo. |
|
||||
| `SMTP_FROM` | default `Verae TimeStamp <veraetimestamp@gmail.com>` (Gmail rewrites a From that differs from the authenticated account unless it is a verified alias) |
|
||||
|
||||
Delivery check (sends exactly one email; the code is not printed):
|
||||
|
||||
```sh
|
||||
SMTP_USER=veraetimestamp@gmail.com SMTP_PASS="$VERAE_GMAIL_APP_PASSWORD" \
|
||||
go run ./cmd/verae-mailtest --to veraetimestamp@gmail.com --send
|
||||
go run ./cmd/verae-mailtest --preview /tmp/mailprev # render only, no send
|
||||
```
|
||||
|
|
|
|||
Loading…
Reference in a new issue