Review round 2 F3 (ADR 0517 §3, 1858/AC5): acted=1 stayed in the address, so a reload, a restored tab or a bookmark of it recorded no page opened or opened. An act's 303 (and a mode chosen) now sets mail_acted for 10 seconds, HttpOnly and SameSite=Strict, Secure but on 127.0.0.1; the next list or pane it reaches records nothing and clears it; the address carries no marker. The local run keeps the browser's other cookies.
139 lines
4.7 KiB
Go
139 lines
4.7 KiB
Go
// mail-page-dev: the mail page, run locally to click through (issue 1859.5). It serves mesh-mail-web's own page
|
|
// handlers (internal/web, NewServer) on 127.0.0.1 only, over invented mail in two accounts and an in-memory
|
|
// mail reading; nothing reaches the mesh: no bus, no database, no Keycloak, no mail server, and nothing is
|
|
// written to disk. Sign-in is a stand-in that is always signed in, so every form works. It is not part of the
|
|
// module's build (module.json builds cmd/mesh-mail-web alone).
|
|
//
|
|
// go run ./cmd/mail-page-dev [-addr 127.0.0.1:8463] [-now 2026-10-22T09:00:00+02:00]
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"mesh-mail-web/internal/web"
|
|
)
|
|
|
|
// DefaultAddr is where the local run listens unless told another 127.0.0.1 address.
|
|
const DefaultAddr = "127.0.0.1:8463"
|
|
|
|
// localRun is a running local page.
|
|
type localRun struct {
|
|
URL string
|
|
server *http.Server
|
|
world *world
|
|
}
|
|
|
|
func (l *localRun) Close() error { return l.server.Close() }
|
|
|
|
// newBundle is the page's Bundle over the world's stand-ins: every seat the page reaches is given, so nothing
|
|
// ever falls back to the bus.
|
|
func newBundle(w *world) *web.Bundle {
|
|
r := w.read
|
|
return &web.Bundle{
|
|
Accounts: w.accounts,
|
|
Search: w.search,
|
|
Read: w.readMail,
|
|
Send: w.send,
|
|
SendStatus: w.sendStatus,
|
|
AccountBucket: w.bucket,
|
|
MailEntries: r.verb(r.entriesVerb),
|
|
MailGroups: r.verb(r.groupsVerb),
|
|
MailStatus: r.verb(r.statusVerb),
|
|
MailCorrect: r.verb(r.correctVerb),
|
|
MailLessons: r.verb(r.lessonsVerb),
|
|
MailUndo: r.verb(r.undoVerb),
|
|
MailList: r.verb(r.listVerb),
|
|
MailHandle: r.verb(r.act("handle")),
|
|
MailUnhandle: r.verb(r.act("unhandle")),
|
|
MailRemind: r.verb(r.act("remind")),
|
|
MailRecord: r.verb(r.recordVerb),
|
|
ModesSetting: func() (map[string][]string, error) {
|
|
return map[string][]string{"work": {"work"}, "personal": {"personal"}}, nil
|
|
},
|
|
Now: w.now,
|
|
}
|
|
}
|
|
|
|
// start serves the page at addr, which must be a 127.0.0.1 address; now fixes "today" when not zero.
|
|
func start(addr string, now time.Time) (*localRun, error) {
|
|
host, _, err := net.SplitHostPort(addr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("-addr %q is not host:port: %v", addr, err)
|
|
}
|
|
if host != "127.0.0.1" {
|
|
return nil, errors.New("-addr must be a 127.0.0.1 address: the local run serves this machine alone")
|
|
}
|
|
clock := time.Now
|
|
begin := time.Now()
|
|
if !now.IsZero() {
|
|
offset := now.Sub(begin)
|
|
clock = func() time.Time { return time.Now().Add(offset) }
|
|
begin = now
|
|
}
|
|
w := newWorld(begin, clock)
|
|
|
|
// The stand-in sign-in: one session, made now, put on every request in place of whatever cookie the
|
|
// browser carries — so every page and every form (their token is this session's) works, and no request
|
|
// ever goes to sign in.
|
|
sessions := web.NewSessions(clock)
|
|
id, err := sessions.Create("operator (the local run's stand-in)")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
page := web.NewServer(host, &web.Auth{Sessions: sessions, Pending: web.NewPendingAuths(clock)}, newBundle(w))
|
|
signedIn := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
// Every cookie the browser carries but the session's own (the act's, web.ActedCookie, among them).
|
|
kept := req.Cookies()
|
|
req.Header.Del("Cookie")
|
|
for _, c := range kept {
|
|
if c.Name != web.SessionCookie {
|
|
req.AddCookie(c)
|
|
}
|
|
}
|
|
req.AddCookie(&http.Cookie{Name: web.SessionCookie, Value: id})
|
|
page.ServeHTTP(rw, req)
|
|
})
|
|
|
|
ln, err := net.Listen("tcp", addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
srv := &http.Server{Handler: signedIn, ReadHeaderTimeout: 10 * time.Second}
|
|
go func() { _ = srv.Serve(ln) }()
|
|
return &localRun{URL: "http://" + ln.Addr().String() + "/", server: srv, world: w}, nil
|
|
}
|
|
|
|
func main() {
|
|
addr := flag.String("addr", DefaultAddr, "where to listen: a 127.0.0.1 address only")
|
|
nowFlag := flag.String("now", "", "fix today's time (RFC 3339, such as 2026-10-22T09:00:00+02:00), to show the list on that day")
|
|
flag.Parse()
|
|
var now time.Time
|
|
if *nowFlag != "" {
|
|
t, err := time.Parse(time.RFC3339, *nowFlag)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "mail-page-dev: -now %q is not RFC 3339: %v\n", *nowFlag, err)
|
|
os.Exit(2)
|
|
}
|
|
now = t
|
|
}
|
|
run, err := start(*addr, now)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "mail-page-dev: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Printf("mail-page-dev: the mail page with invented mail, at %s\n", run.URL)
|
|
fmt.Println("mail-page-dev: it serves 127.0.0.1 alone; sign-in is a stand-in, always signed in")
|
|
fmt.Println("mail-page-dev: nothing reaches the mesh: no bus, no database, no Keycloak, no mail; nothing is kept after it stops")
|
|
if !now.IsZero() {
|
|
fmt.Printf("mail-page-dev: today is fixed at %s\n", now.Format(time.RFC3339))
|
|
}
|
|
fmt.Println("mail-page-dev: Ctrl-C stops it")
|
|
select {}
|
|
}
|