| 1 | package docs_test |
| 2 | |
| 3 | import ( |
| 4 | "html" |
| 5 | "net/http" |
| 6 | "strings" |
| 7 | "testing" |
| 8 | |
| 9 | "github.com/carlosframework/docs/internal/docs" |
| 10 | ) |
| 11 | |
| 12 | // Grant refuses what is not an address. |
| 13 | // |
| 14 | // Before this, Grant accepted any non-empty string: "not-an-email" became |
| 15 | // a row, appeared on the share page as though it were a person, and made |
| 16 | // HasGrant answer true — widening the instance's front door to a string |
| 17 | // that can never sign in. (Branch review, finding 10.) |
| 18 | func TestGrantRefusesNonsenseAddresses(t *testing.T) { |
| 19 | app, _ := docs.NewForTest(t) |
| 20 | alice := signInCookies(t, app, "alice@example.com") |
| 21 | sqid := createDoc(t, app, alice, "Minutes") |
| 22 | |
| 23 | for _, bad := range []string{"not-an-email", "@example.com", "bob@", "bob example@x.com"} { |
| 24 | rec := post(t, app, alice, "/d/"+sqid+"/share", "address="+strings.ReplaceAll(bad, " ", "+")) |
| 25 | if rec.Code == http.StatusSeeOther { |
| 26 | t.Errorf("granted to %q", bad) |
| 27 | } |
| 28 | // Looked for in a grant row, not the whole page: the page's |
| 29 | // account menu names alice@example.com, which contains |
| 30 | // "@example.com". |
| 31 | if body := get(t, app, alice, "/d/"+sqid+"/share").Body.String(); strings.Contains(body, "<span docs-share-who>"+html.EscapeString(bad)+"</span>") { |
| 32 | t.Errorf("the share page lists %q", bad) |
| 33 | } |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | // An owner cannot grant to themselves. They already reach it by owning it, |
| 38 | // and the row would put them on their own share list looking like an |
| 39 | // invitation somebody made. |
| 40 | func TestGrantRefusesTheOwner(t *testing.T) { |
| 41 | app, _ := docs.NewForTest(t) |
| 42 | alice := signInCookies(t, app, "alice@example.com") |
| 43 | sqid := createDoc(t, app, alice, "Minutes") |
| 44 | |
| 45 | if rec := post(t, app, alice, "/d/"+sqid+"/share", "address=alice@example.com&role=writer"); rec.Code == http.StatusSeeOther { |
| 46 | t.Error("the owner granted a document to herself") |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | // A grant on a document that no longer exists does not hold the front door |
| 51 | // open. Admission is meant to follow from reaching something; a grant on a |
| 52 | // deleted document reaches nothing, because readable hides it. |
| 53 | func TestAGrantOnADeletedDocumentAdmitsNobody(t *testing.T) { |
| 54 | app := members(t, "alice@example.com") |
| 55 | alice := signInCookies(t, app, "alice@example.com") |
| 56 | sqid := createDoc(t, app, alice, "Minutes") |
| 57 | post(t, app, alice, "/d/"+sqid+"/share", "address=bob@example.com&role=reader") |
| 58 | |
| 59 | if _, err := app.TestSignIn(t, "bob@example.com"); err != nil { |
| 60 | t.Fatalf("precondition: the grantee cannot sign in: %v", err) |
| 61 | } |
| 62 | |
| 63 | app.TestSoftDelete(t, sqid) |
| 64 | |
| 65 | if _, err := app.TestSignIn(t, "bob@example.com"); err == nil { |
| 66 | t.Error("a grant on a deleted document still admits its holder") |
| 67 | } |
| 68 | } |
| 69 | |