package web
import (
"net/http"
"net/url"
"strings"
"testing"
)
// An invite link is a BEARER CREDENTIAL: it opens an account. (A reset
// link is never shown to anybody but its owner, by mail — #319.) It used to
// ride setFlash, which is Path="/" with a 30-second life — so until it
// was spent the browser sent it back on every request to any path, and
// the credential crossed the edge many times instead of once.
//
// It rides the vault now (secretvault.go): the link stays server-side
// under a single-use nonce and only the nonce travels.
func TestTheOneTimeLinksDoNotRideTheFlash(t *testing.T) {
srv, accts, _ := betaForge(t)
if err := accts.AddAccount("jo", "the-old-password", false); err != nil {
t.Fatal(err)
}
for _, c := range []struct {
name, path string
form url.Values
}{
{"an invite", "/fleet/people/invite", url.Values{"name": {"newbie"}}},
} {
res := as(t, srv, "root", "POST", c.path, c.form)
body(res)
if res.StatusCode != 303 {
t.Errorf("FAIL: %s answered %d", c.name, res.StatusCode)
continue
}
// The nonce travels; the link does not.
where := res.Header.Get("Location")
if !strings.Contains(where, "?s=") {
t.Errorf("FAIL: %s carries no vault nonce: %q", c.name, where)
} else if strings.Contains(where, "/invite/") {
t.Errorf("FAIL: %s put the link itself in the URL: %q", c.name, where)
} else {
t.Logf("ok: %s travels as a nonce", c.name)
}
// And no cookie the response sets contains the link.
for _, ck := range res.Cookies() {
if strings.Contains(ck.Value, "/invite/") {
t.Errorf("FAIL: %s put the link in cookie %q", c.name, ck.Name)
}
}
t.Logf("ok: %s is in no cookie", c.name)
}
}
// Single use, which is what "shown once" has always claimed. Asking
// twice with the same nonce shows nothing the second time.
func TestAOneTimeLinkIsShownOnce(t *testing.T) {
srv, accts, _ := betaForge(t)
if err := accts.AddAccount("jo", "the-old-password", false); err != nil {
t.Fatal(err)
}
res := as(t, srv, "root", "POST", "/fleet/people/invite", url.Values{"name": {"newbie"}})
body(res)
where := res.Header.Get("Location")
get := func() string {
req, _ := http.NewRequest("GET", srv.URL+where, nil)
req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "tok-root"})
for _, ck := range res.Cookies() {
req.AddCookie(ck)
}
r, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
return body(r)
}
if !strings.Contains(get(), "/invite/") {
t.Fatal("FAIL: the link was not shown even once")
}
t.Log("ok: shown once")
if strings.Contains(get(), "/invite/") {
t.Error("FAIL: the same nonce showed the link twice")
} else {
t.Log("ok: and not twice")
}
}