//go:build browser package callstest import ( "bufio" "bytes" "context" "encoding/json" "net/http" "net/http/cookiejar" "net/url" "os/exec" "path/filepath" "testing" "time" "amadan.net/oficina/calls/callscore" ) func TestNativeBrowserAuthentication(t *testing.T) { // "server" is the apps' Sign in button: the server's own address, no // meeting, landing home. for _, name := range []string{"member", "guest", "server"} { t.Run(name, func(t *testing.T) { rig := newBrowserRig(t) room, token := rig.createMeeting(t) address := memberB target := "/m/" + room want := room switch name { case "guest": rig.ctl.SetAllowlist(memberA) target = "/j/" + token case "server": target = "" want = "" } ctx, cancel := context.WithTimeout(t.Context(), 45*time.Second) defer cancel() auth, err := callscore.BeginAuthentication(ctx, rig.origin+target) if err != nil { t.Fatal(err) } defer auth.Cancel() cmd := exec.CommandContext(ctx, "node", filepath.Join(repoRootForBrowser(t), "test/browser/native-auth.mjs")) stdin, err := cmd.StdinPipe() if err != nil { t.Fatal(err) } stdout, err := cmd.StdoutPipe() if err != nil { t.Fatal(err) } var stderr bytes.Buffer cmd.Stderr = &stderr if err := cmd.Start(); err != nil { t.Fatal(err) } defer stdin.Close() json.NewEncoder(stdin).Encode(map[string]string{"url": auth.BrowserURL(), "address": address, "code": auth.ConfirmationCode()}) scanner := bufio.NewScanner(stdout) approved := false for scanner.Scan() { switch scanner.Text() { case "mail": to, link := rig.mail.last() if to != address || link == "" { cancel() cmd.Wait() t.Fatal("missing email") } json.NewEncoder(stdin).Encode(map[string]string{"link": link}) case "stage:signin", "stage:email-opened": t.Log(scanner.Text()) case "approved": approved = true default: cancel() cmd.Wait() t.Fatal("unexpected browser output") } } if err := cmd.Wait(); err != nil { t.Fatalf("browser: %v: %s", err, stderr.String()) } if !approved { t.Fatal("browser did not approve") } result, err := auth.Wait() if err != nil { t.Fatal(err) } if result.Room != want || result.Origin != rig.origin || len(result.Cookies) != 1 { t.Fatal("wrong native destination") } jar, _ := cookiejar.New(nil) origin, _ := url.Parse(rig.origin) c := result.Cookies[0] jar.SetCookies(origin, []*http.Cookie{{Name: c.Name, Value: c.Value}}) client := &http.Client{Jar: jar, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }} res, err := client.Get(rig.origin + "/m/" + room + "/info") if err != nil { t.Fatal(err) } defer res.Body.Close() if res.StatusCode != 200 { t.Fatalf("native session cannot access meeting: %d", res.StatusCode) } }) } }