package classes_test import ( "context" "strings" "testing" "git.golem15.com/golem15/sm-sitemap-plugin/classes" ) // rewriteBackend and rewriteDoc are the backend URL and the document of the // rewrite tests: a stylesheet instruction, a loc, hreflang links and the // backend URL in places the rewrite leaves alone. const rewriteBackend = "https://api.ex.pl" var rewriteDoc = "\n" + `` + "\n" + `https://api.ex.pl/a2026https://api.ex.pl1` + `` + `https://api.ex.pl/xhttps://other.pl/https://api.ex.plcp` + "\n" // TestRewrite pins the PHP routes.php frontend_url rewrite: the backend URL // is replaced inside loc, inside xhtml:link href and in the exact stylesheet // href, nowhere else; slashes are trimmed on both; an empty or "0" frontend // URL and equal URLs leave the document unchanged. func TestRewrite(t *testing.T) { const backend = rewriteBackend doc := rewriteDoc want := "\n" + `` + "\n" + `https://www.ex.pl/a2026https://api.ex.pl1` + `` + `https://api.ex.pl/xhttps://other.pl/https://www.ex.plcp` + "\n" for _, frontend := range []string{"https://www.ex.pl", "https://www.ex.pl/", "https://www.ex.pl///"} { for _, back := range []string{backend, backend + "/"} { if got := classes.Rewrite(doc, back, frontend); got != want { t.Fatalf("Rewrite(%q, %q):\n%s\nwant:\n%s", back, frontend, got, want) } } } for _, frontend := range []string{"", "0"} { if got := classes.Rewrite(doc, backend, frontend); got != doc { t.Fatalf("frontend %q changed the document", frontend) } } if got := classes.Rewrite(doc, backend, backend); got != doc { t.Fatal("equal URLs changed the document") } if got := classes.Rewrite(doc, backend+"/", backend); got != doc { t.Fatal("equal URLs up to a slash changed the document") } // An empty backend URL replaces nothing. if got := classes.Rewrite(doc, "", "https://www.ex.pl"); got != doc { t.Fatal("an empty backend URL changed the document") } // A stylesheet on another path is not the PHP pattern. other := `` if got := classes.Rewrite(other, backend, "https://www.ex.pl"); got != other { t.Fatalf("other stylesheet = %q", got) } } // The two frontend_url values of the T-17-15 reproduction: a script URL the // stylesheet would render as a link, and a value that closes the attribute // and the element it is written into. var frontendAttacks = []string{ "javascript:alert(document.domain)//", `https://x"/>", " https://www.ex.pl", "https://www.ex.pl\n", "//www.ex.pl", "www.ex.pl", "https:///x", "data:text/html,x", }, frontendAttacks...) for _, frontend := range refused { if got := classes.Rewrite(rewriteDoc, rewriteBackend, frontend); got != rewriteDoc { t.Errorf("frontend %q changed the document:\n%s", frontend, got) } } // The reproduction through the generator. const root = "https://api.example.test" xml, err := (&classes.Generator{Root: root}).Generate(context.Background(), urlItems("/blog/x")) if err != nil { t.Fatal(err) } if !strings.Contains(xml, `href="https://api.example.test/sitemap.xsl"`) { t.Fatalf("the generated document lacks the stylesheet instruction:\n%s", xml) } for _, frontend := range frontendAttacks { got := classes.Rewrite(xml, classes.BackendURL(root), frontend) if got != xml { t.Errorf("frontend %q changed the generated sitemap:\n%s", frontend, got) } if !strings.Contains(got, "https://api.example.test/blog/x") { t.Errorf("frontend %q: the loc is not on the backend URL:\n%s", frontend, got) } if lower := strings.ToLower(got); strings.Contains(lower, "javascript") || strings.Contains(lower, "https://www.example.test/blog/x") || !strings.Contains(got, `href="https://www.example.test/sitemap.xsl"`) || strings.Contains(got, "api.example.test") { t.Errorf("a valid frontend URL did not rewrite the sitemap:\n%s", got) } if got := classes.Rewrite(xml, classes.BackendURL(root), "HTTPS://WWW.EXAMPLE.TEST"); !strings.Contains(got, "HTTPS://WWW.EXAMPLE.TEST/blog/x") { t.Errorf("an upper-case frontend URL did not rewrite the loc:\n%s", got) } // The http(s) output filter after the rewrite: replacing "s://api.ex.pl" // would write httphttps://www.ex.pl/a, so loc and href keep their values. entry := `https://api.ex.pl/a` if got := classes.Rewrite(entry, "s://api.ex.pl", "https://www.ex.pl"); got != entry { t.Errorf("a rewrite to a non-http(s) URL was written:\n%s", got) } }