package callstest import ( "net/http" "net/url" "strings" "testing" "time" ) func enableWaitingRoom(t *testing.T, x *harness, sqid string) { t.Helper() c := x.browser(t) c.signIn("paul@example.com") if r := c.post("/meetings/"+sqid+"/settings", url.Values{"waiting_room": {"on"}}); r.Code != 303 { t.Fatal(r.Code, r.Body.String()) } } func TestMeetingDefaultsAndIndependentOverrides(t *testing.T) { x := newHarness(t, "paul@example.com") c := x.browser(t) c.signIn("paul@example.com") old, _ := createMeeting(t, c, "Original", "") if r := c.post("/settings/defaults", url.Values{"require_signin": {"on"}, "waiting_room": {"on"}}); r.Code != 303 { t.Fatal(r.Code) } next, token := createMeeting(t, c, "Restricted", "") if r := x.browser(t).get("/j/" + token); r.Code != 303 || r.Header().Get("Location") != "/signin" { t.Fatal("sign-in not required", r.Code) } for _, tc := range []struct { sqid string checked bool }{{old, false}, {next, true}} { r := c.get("/meetings/" + tc.sqid + "/settings") if r.Code != 200 || strings.Contains(r.Body.String(), " checked") != tc.checked { t.Fatal("settings not retained", r.Body.String()) } } if r := c.post("/meetings/"+next+"/settings", url.Values{}); r.Code != 303 { t.Fatal(r.Code) } if r := x.browser(t).get("/j/" + token); r.Code != 200 { t.Fatal("guest override not applied", r.Code) } if r := c.get("/settings"); !strings.Contains(r.Body.String(), " checked") { t.Fatal("override altered defaults") } } func TestAnonymousGuestJoinsWithoutMemberPowers(t *testing.T) { x, sqid, token := memberWithMeeting(t) g := x.browser(t) r := g.get("/j/" + token) if r.Code != 200 || !strings.Contains(r.Body.String(), "oficina-calls://join?") { t.Fatal("missing guest/app choice", r.Code) } if r := g.post("/j/"+token+"/guest", url.Values{"name": {" "}}); r.Code != 422 { t.Fatal("empty name accepted") } if r := g.post("/j/"+token+"/guest", url.Values{"name": {"Visitor"}}); r.Code != 303 { t.Fatal(r.Code, r.Body.String()) } if r := g.get("/m/" + sqid + "/join"); r.Code != 200 || !strings.Contains(r.Body.String(), "Visitor") { t.Fatal("guest holding", r.Code, r.Body.String()) } for _, path := range []string{"/settings", "/meetings/" + sqid + "/settings", "/"} { if r := g.get(path); r.Code != 404 { t.Fatal("guest can reach", path, r.Code) } } if r := g.post("/meetings/"+sqid+"/settings", url.Values{"waiting_room": {"on"}}); r.Code != 404 { t.Fatal("guest can change settings") } s := g.stream("/m/" + sqid + "/stream") defer s.close() peer, _ := s.hello() if res, b := g.signal(sqid, peer, `{"type":"join"}`); res.StatusCode != http.StatusOK { t.Fatal(res.StatusCode, string(b)) } if _, data, ok := s.nextOf("roster", 2*time.Second); !ok || !strings.Contains(string(data), `"kind":"guest"`) { t.Fatal("guest not directly admitted", string(data)) } } func TestAnonymousEntryRefusesRestrictedAndRevokedInvitations(t *testing.T) { x, sqid, token := memberWithMeeting(t) m := x.browser(t) m.signIn("paul@example.com") g := x.browser(t) m.post("/meetings/"+sqid+"/settings", url.Values{"require_signin": {"on"}}) if r := g.post("/j/"+token+"/guest", url.Values{"name": {"Visitor"}}); r.Code != 303 || r.Header().Get("Location") != "/signin" { t.Fatal("restricted guest POST accepted") } m.post("/meetings/"+sqid+"/settings", url.Values{}) g.post("/j/"+token+"/guest", url.Values{"name": {"Visitor"}}) m.post("/meetings/"+sqid+"/settings", url.Values{"require_signin": {"on"}}) if r := g.get("/m/" + sqid + "/join"); r.Code != 404 { t.Fatal("guest bypassed new sign-in requirement") } m.post("/meetings/"+sqid+"/links", nil) if r := x.browser(t).post("/j/"+token+"/guest", url.Values{"name": {"Visitor"}}); r.Code != 404 { t.Fatal("revoked invitation accepted") } } func TestTurningOffWaitingRoomAdmitsQueuedAnonymousGuest(t *testing.T) { x, sqid, token := memberWithMeeting(t) enableWaitingRoom(t, x, sqid) g := x.browser(t) if r := g.post("/j/"+token+"/guest", url.Values{"name": {"Waiting visitor"}}); r.Code != 303 { t.Fatal(r.Code) } s := g.stream("/m/" + sqid + "/stream") defer s.close() peer, _ := s.hello() if r, b := g.signal(sqid, peer, `{"type":"join"}`); r.StatusCode != 200 { t.Fatal(r.StatusCode, string(b)) } if r := g.getStream("/m/" + sqid + "/ice?peer=" + peer); r.Code != 404 { t.Fatal("waiting guest admitted prematurely", r.Code) } member := x.browser(t) member.signIn("paul@example.com") if r := member.post("/meetings/"+sqid+"/settings", url.Values{}); r.Code != 303 { t.Fatal(r.Code) } if _, _, ok := s.nextOf("roster", 2*time.Second); !ok { t.Fatal("queued guest not admitted after disabling waiting room") } }