- TestMemberTokenScopes walks E-2's acceptance list item by item, plus the per-application catalog and the legacy MintAPIToken fallback; TestMemberTokenScopesBoot (no Docker) the boot refusals - TestBackendLinkAuthTime (C-CR-02), TestBackendLinkShowPost (C-WR-01, C-IN-06), TestAccessRevocation (C-CR-01), TestUserMCPGuardClientIP (C-IN-04), TestAPITokenRevokeEvent (C-IN-02), TestOrganisationLogo (E-1) - README Testing section names them
111 lines
4.0 KiB
Go
111 lines
4.0 KiB
Go
package user
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.golem15.com/golem15/sm-user-plugin/models"
|
|
"git.golem15.com/golem15/summercms/modules/compass"
|
|
)
|
|
|
|
// TestBackendLinkShowPost pins plan 08's link code transport (C-WR-01,
|
|
// C-IN-06): POST /backend-link/show answers exactly like the GET route (the
|
|
// data for a live code, 404 for an unknown, a used or an expired one), both
|
|
// with Cache-Control no-store, private; My account answers the link as
|
|
// <frontend_url>/link-admin#code=<64 hex> with no query string;
|
|
// golem15.user.backend_links.page_path changes the path, and a value
|
|
// without a leading slash gets one. Postgres only: under -short nothing
|
|
// runs.
|
|
func TestBackendLinkShowPost(t *testing.T) {
|
|
if testing.Short() {
|
|
return
|
|
}
|
|
env := newAdminEnv(t)
|
|
show := func(t *testing.T, code string) (get, post *struct {
|
|
status int
|
|
body string
|
|
cache string
|
|
}) {
|
|
t.Helper()
|
|
g := env.call(t, http.MethodGet, "/_user/api/v1/backend-link/"+code, "", nil)
|
|
p := env.call(t, http.MethodPost, "/_user/api/v1/backend-link/show", "", map[string]string{"code": code})
|
|
return &struct {
|
|
status int
|
|
body string
|
|
cache string
|
|
}{g.Code, g.Body.String(), g.Header().Get("Cache-Control")}, &struct {
|
|
status int
|
|
body string
|
|
cache string
|
|
}{p.Code, p.Body.String(), p.Header().Get("Cache-Control")}
|
|
}
|
|
same := func(t *testing.T, code string, status int) {
|
|
t.Helper()
|
|
get, post := show(t, code)
|
|
if get.status != status || post.status != status {
|
|
t.Fatalf("show %s: GET %d, POST %d, want %d", code[:8], get.status, post.status, status)
|
|
}
|
|
if !bytes.Equal([]byte(get.body), []byte(post.body)) {
|
|
t.Fatalf("POST show differs from GET:\nGET %s\nPOST %s", get.body, post.body)
|
|
}
|
|
if get.cache != "no-store, private" || post.cache != "no-store, private" {
|
|
t.Fatalf("Cache-Control: GET %q, POST %q", get.cache, post.cache)
|
|
}
|
|
}
|
|
|
|
t.Run("POST show answers like GET", func(t *testing.T) {
|
|
token := env.admin(t)
|
|
live := env.startLink(t, token)
|
|
same(t, live, http.StatusOK)
|
|
if _, post := show(t, live); !strings.Contains(post.body, `"admin"`) || !strings.Contains(post.body, `"expires_at"`) {
|
|
t.Fatalf("POST show data = %s", post.body)
|
|
}
|
|
same(t, strings.Repeat("a", 64), http.StatusNotFound)
|
|
|
|
used := env.startLink(t, env.admin(t))
|
|
if status, body := env.confirmLink(t, freshUserToken(t, env.seedUser(t, "show-used", nil)), used); status != http.StatusOK {
|
|
t.Fatalf("confirm = %d %s", status, body)
|
|
}
|
|
same(t, used, http.StatusNotFound)
|
|
|
|
expiring := env.admin(t)
|
|
expired := env.startLink(t, expiring)
|
|
if err := env.gdb.Model(&models.BackendLinkRequest{}).Where("backend_user_id = ?", adminID(t, expiring)).
|
|
Update("expires_at", time.Now().Add(-time.Minute)).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
same(t, expired, http.StatusNotFound)
|
|
})
|
|
|
|
t.Run("the My account URL carries the code in the fragment only", func(t *testing.T) {
|
|
var out struct {
|
|
URL string `json:"url"`
|
|
}
|
|
adminInto(t, env.expect(t, http.StatusOK, http.MethodPost, adminAPI("/account/contributions/frontend_account/actions/link"), env.admin(t), map[string]any{}), &out)
|
|
if !regexp.MustCompile(`^https://app\.example\.test/link-admin#code=[a-f0-9]{64}$`).MatchString(out.URL) || strings.Contains(out.URL, "?") {
|
|
t.Fatalf("link URL = %q", out.URL)
|
|
}
|
|
})
|
|
|
|
for _, c := range []struct{ value, want string }{{"/pl/polacz", "/pl/polacz"}, {"pl/polacz", "/pl/polacz"}} {
|
|
t.Run("page_path "+c.value, func(t *testing.T) {
|
|
custom := newAdminEnv(t, func(cfg *compass.Config) {
|
|
if err := cfg.Set("golem15.user.backend_links.page_path", c.value); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
var out struct {
|
|
URL string `json:"url"`
|
|
}
|
|
adminInto(t, custom.expect(t, http.StatusOK, http.MethodPost, adminAPI("/account/contributions/frontend_account/actions/link"), custom.admin(t), map[string]any{}), &out)
|
|
if !regexp.MustCompile(`^https://app\.example\.test` + regexp.QuoteMeta(c.want) + `#code=[a-f0-9]{64}$`).MatchString(out.URL) {
|
|
t.Fatalf("link URL with page_path %q = %q", c.value, out.URL)
|
|
}
|
|
})
|
|
}
|
|
}
|