oficina / meet Public

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

Plain git — no account needed to clone.

Download

Download this file

1package calls
2
3import (
4 "bytes"
5 "encoding/base64"
6 "io"
7 "log/slog"
8 "net/http"
9 "net/http/httptest"
10 "path/filepath"
11 "strings"
12 "testing"
13
14 "amadan.net/oficina/home/connect"
15 assertioncrypto "amadan.net/rastrillo/rastrillo/crypto"
16 "amadan.net/rastrillo/rastrillo/db"
17)
18
19const homeTestDirectory = "https://directory.example.test"
20
21// newHomeConsumerFixture configures Home the way production does: from the
22// environment, through connect.CredentialsFromEnv (cmd/calls/main.go), so
23// HOME_DIRECTORY_ORIGIN (unprefixed, the name Home itself reads) is read
24// exactly as it is live.
25func newHomeConsumerFixture(t *testing.T, directory string) *homeRouterFixture {
26 t.Helper()
27 logger := slog.New(slog.NewTextHandler(io.Discard, nil))
28 d, err := db.Open(filepath.Join(t.TempDir(), "calls.db"), logger)
29 if err != nil {
30 t.Fatal(err)
31 }
32 t.Cleanup(func() { d.Close() })
33 key, err := assertioncrypto.Generate()
34 if err != nil {
35 t.Fatal(err)
36 }
37 t.Setenv("CALLS_HOME_ISSUER", homeTestIssuer)
38 t.Setenv("CALLS_HOME_CONSUMER_ID", "calls-test")
39 t.Setenv("CALLS_HOME_KEYS_BASE64", homeKeysBase64(key))
40 t.Setenv("CALLS_HOME_DEK_BASE64", base64.StdEncoding.EncodeToString(bytes.Repeat([]byte{7}, 32)))
41 t.Setenv("HOME_DIRECTORY_ORIGIN", directory)
42 return newHomeRouterFixtureWith(t, d, logger, key, connect.CredentialsFromEnv("CALLS"))
43}
44
45// Sign out in Calls ends the id.* session too: the app session ends and
46// the same POST is handed on (307) to {issuer}/signout, which returns the
47// browser to /signed-out. Without it the next "Sign in" passed silently
48// through the live id.* session (spec shared-chrome §9.5).
49func TestHomeSignoutChainsToIssuer(t *testing.T) {
50 f := newHomeConsumerFixture(t, "")
51 f.local(t)
52 w := f.do("POST", "/signout", "")
53 if w.Code != http.StatusTemporaryRedirect || w.Header().Get("Location") != homeTestIssuer+"/signout" {
54 t.Fatalf("POST /signout: status %d Location %q, want 307 to %s/signout", w.Code, w.Header().Get("Location"), homeTestIssuer)
55 }
56 if got := w.Header().Get("Referrer-Policy"); got != "strict-origin-when-cross-origin" {
57 t.Fatalf("Referrer-Policy %q: id.* admits the null-Origin hop by Referer", got)
58 }
59 if f.cookies[f.app.home.sessions.CookieName()] != nil {
60 t.Fatal("sign-out kept the Calls session cookie")
61 }
62}
63
64// A signed-in person who follows a "Sign in" link goes straight to where
65// they were headed, with no second exchange.
66func TestHomeSigninWhenSignedInReturnsToPage(t *testing.T) {
67 f := newHomeConsumerFixture(t, "")
68 f.local(t)
69 if got := homeRedirect(t, f.do("GET", "/signin?return_to=%2Fsettings", "")); got != "/settings" {
70 t.Fatalf("signed-in /signin went to %q, want /settings", got)
71 }
72}
73
74// "All apps" goes to the hub directory, from HOME_DIRECTORY_ORIGIN, in the
75// account corner, and is absent when no directory is configured.
76func TestAllAppsLinksToDirectory(t *testing.T) {
77 link := `href="` + homeTestDirectory + `/"`
78 f := newHomeConsumerFixture(t, homeTestDirectory)
79 f.local(t)
80 for _, path := range []string{"/", "/settings"} {
81 w := f.do("GET", path, "")
82 if body := w.Body.String(); w.Code != http.StatusOK || !strings.Contains(body, link) || !strings.Contains(body, ">All apps<") {
83 t.Fatalf("GET %s (%d): no All apps link to %s/", path, w.Code, homeTestDirectory)
84 }
85 }
86
87 bare := newHomeConsumerFixture(t, "")
88 bare.local(t)
89 if body := bare.do("GET", "/", "").Body.String(); strings.Contains(body, "All apps") {
90 t.Fatal("All apps shown with no directory configured")
91 }
92}
93
94// homeSignout asserts the Home-mode sign-out response: a 307 on to the
95// issuer's /signout, which returns the browser to /signed-out.
96func homeSignout(t *testing.T, w *httptest.ResponseRecorder) {
97 t.Helper()
98 if w.Code != http.StatusTemporaryRedirect || w.Header().Get("Location") != homeTestIssuer+"/signout" {
99 t.Fatalf("POST /signout: status %d Location %q, want 307 to %s/signout", w.Code, w.Header().Get("Location"), homeTestIssuer)
100 }
101}
102
103// A signed-out visit to a page in Home mode goes to sign-in carrying the
104// page, and Home sign-in comes back to that exact page, not the root.
105func TestHomeSigninReturnsToTheExactPage(t *testing.T) {
106 f := newHomeConsumerFixture(t, "")
107 f.link(t)
108 homeSignout(t, f.do("POST", "/signout", ""))
109
110 signin := homeRedirect(t, f.do("GET", "/settings", ""))
111 if signin != "/signin?return_to=%2Fsettings" {
112 t.Fatalf("signed-out /settings went to %q, want /signin?return_to=%%2Fsettings", signin)
113 }
114 start := homeRedirect(t, f.do("GET", signin, ""))
115 if got := homeRedirect(t, f.exchange(t, start, "opaque-home-alice")); got != "/settings" {
116 t.Fatalf("Home sign-in landed on %q, want /settings", got)
117 }
118}
119