e2e/websignup_test.go

bd5cf5d7d1f34fa780660fd7562b9ffd9746ee27
gitbay/e2e/websignup_test.go history · blame · raw

94 lines · 3706 bytes

 1package e2e
 2
 3import (
 4	"fmt"
 5	"net/url"
 6	"os"
 7	"strings"
 8	"testing"
 9)
10
11func TestWebSignup(t *testing.T) {
12	t.Parallel()
13	smtp := startFakeSMTP(t)
14	inst := startInstanceWith(t, fmt.Sprintf(
15		"[web]\nmode = \"accounts\"\n[registration]\nmode = \"invite\"\n[mail]\nsmtp_host = %q\nfrom = \"noreply@gitbay.test\"\n",
16		smtp.addr))
17
18	// The landing page advertises signup; the form renders.
19	status, body := inst.get(t, "/")
20	if status != 200 || !strings.Contains(body, `href="/register"`) {
21		t.Fatalf("landing signup link: %d", status)
22	}
23	status, body = inst.get(t, "/register")
24	if status != 200 || !strings.Contains(body, "invite-only") || !strings.Contains(body, `name="key"`) {
25		t.Fatalf("register form: %d\n%s", status, body)
26	}
27	// The login page tells a brand-new visitor how to get an account.
28	status, body = inst.get(t, "/login")
29	if status != 200 || !strings.Contains(body, `href="/register"`) || !strings.Contains(body, "invite-only") {
30		t.Fatalf("login signup hint: %d\n%s", status, body)
31	}
32
33	// Invite issued over the admin path; redeemed through the browser.
34	inst.admin(t, "admin", "invite", "--email", "erin@example.test")
35	inviteCode := extractCode(t, smtp.waitMail(t, 0))
36	key := inst.newKey(t, "erin")
37	pub, err := os.ReadFile(key + ".pub")
38	if err != nil {
39		t.Fatal(err)
40	}
41
42	browser := newBrowser(t)
43	// A garbage key re-renders the form with the error, keeping the input.
44	_, body = browserPost(t, browser, inst.base()+"/register", url.Values{
45		"username": {"erin"}, "invite": {inviteCode}, "key": {"not a key"}})
46	if !strings.Contains(body, "does not parse as an SSH public key") || !strings.Contains(body, `value="erin"`) {
47		t.Fatalf("bad key handling:\n%s", body)
48	}
49	// A bad invite fails without burning anything.
50	_, body = browserPost(t, browser, inst.base()+"/register", url.Values{
51		"username": {"erin"}, "invite": {"deadbeef"}, "key": {string(pub)}})
52	if !strings.Contains(body, "invalid or already used") {
53		t.Fatalf("bad invite:\n%s", body)
54	}
55	// The real thing: account is active immediately (invite proves the mailbox).
56	status, body = browserPost(t, browser, inst.base()+"/register", url.Values{
57		"username": {"erin"}, "invite": {inviteCode}, "key": {string(pub)}})
58	if status != 200 || !strings.Contains(body, "welcome, erin") ||
59		!strings.Contains(body, `href="/settings#emails"`) || !strings.Contains(body, "Paste the code") {
60		t.Fatalf("signup: %d\n%s", status, body)
61	}
62	out, errOut, code := inst.ssh(t, key, "", "whoami")
63	if code != 0 || !strings.Contains(out, "erin") {
64		t.Fatalf("ssh after web signup: exit %d, %s%s", code, out, errOut)
65	}
66	// The invite is burned: reusing it (fresh browser, fresh key) fails.
67	key2 := inst.newKey(t, "mallory")
68	pub2, _ := os.ReadFile(key2 + ".pub")
69	_, body = browserPost(t, newBrowser(t), inst.base()+"/register", url.Values{
70		"username": {"mallory"}, "invite": {inviteCode}, "key": {string(pub2)}})
71	if !strings.Contains(body, "invalid or already used") {
72		t.Fatalf("invite reuse:\n%s", body)
73	}
74}
75
76func TestWebSignupClosedInstance(t *testing.T) {
77	t.Parallel()
78	inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
79	// Closed registration: no signup route at all, and no landing hint.
80	if status, _ := inst.get(t, "/register"); status != 404 {
81		t.Fatalf("register on closed instance: %d", status)
82	}
83	_, body := inst.get(t, "/")
84	if strings.Contains(body, `href="/register"`) {
85		t.Fatal("closed landing advertises signup")
86	}
87	_, body = inst.get(t, "/login")
88	if strings.Contains(body, `href="/register"`) {
89		t.Fatal("closed login page advertises signup")
90	}
91	if !strings.Contains(body, "not accepting new accounts") {
92		t.Fatalf("closed login page says nothing about accounts:\n%s", body)
93	}
94}