fix(17): CR-01 refuse non-http sitemap URLs on save, import and output
A url item stored as javascript://%0aalert(1)%0a//x passed Url::to and reached <loc>, which sitemap.xsl renders as a link on the site origin. - The definitions form refuses, per row, a url that is not a path or an http(s) URL (classes.AllowedItemURL) and a urlPattern that is not a path (signpost.ValidItemPattern), keyed data.<i>.url / .urlPattern. - Generator.addItem drops a loc or alternate that is not http(s). - sitemap:import-winter drops such url items and clears such patterns with a report line; sitemap:import refuses such an entry.
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.golem15.com/golem15/sm-sitemap-plugin/classes"
|
||||
"git.golem15.com/golem15/sm-sitemap-plugin/models"
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/bonfire"
|
||||
@@ -22,7 +23,8 @@ import (
|
||||
// its url items; with --append the URLs are added after every existing item.
|
||||
// The definition is always the one /sitemap.xml serves (theme default);
|
||||
// --theme is accepted for PHP compatibility and a theme other than default
|
||||
// is reported.
|
||||
// is reported. An entry whose url is not a path or an http(s) URL
|
||||
// (classes.AllowedItemURL) is refused, as the admin form refuses it.
|
||||
func Import(app *backpack.App) bonfire.Command {
|
||||
return bonfire.Command{
|
||||
Name: "sitemap:import",
|
||||
@@ -67,6 +69,9 @@ func ImportFile(ctx context.Context, db *gorm.DB, file, theme string, appendMode
|
||||
if fields["url"] == nil || err != nil || phpEmpty(fields["url"]) {
|
||||
return fmt.Errorf("Entry %s is missing a 'url' field", labels[i])
|
||||
}
|
||||
if !classes.AllowedItemURL(models.Text(url)) {
|
||||
return fmt.Errorf("Entry %s has a url that is not a path or an http(s) URL", labels[i])
|
||||
}
|
||||
item := models.DefinitionItem{Type: models.ItemTypeURL, URL: url}
|
||||
item.Changefreq = textOr(fields["changefreq"], "monthly")
|
||||
item.Priority = textOr(fields["priority"], "0.5")
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.golem15.com/golem15/sm-sitemap-plugin/classes"
|
||||
"git.golem15.com/golem15/sm-sitemap-plugin/models"
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/bonfire"
|
||||
@@ -65,9 +66,12 @@ type WinterReport struct {
|
||||
// their URL, --map old=new renames applied first),
|
||||
// an item of a registry type that takes references is dropped when its
|
||||
// reference is not among the type's current references, an item of an
|
||||
// unknown type is dropped, and every dropped or remapped item is printed. A
|
||||
// definition that already has items is refused without --force. Settings
|
||||
// keys missing from the export take the PHP defaults.
|
||||
// unknown type is dropped, a url item whose URL is not a path or an http(s)
|
||||
// URL (classes.AllowedItemURL) is dropped, a URL pattern that is not a path
|
||||
// (signpost.ValidItemPattern) is cleared, and every dropped, remapped or
|
||||
// cleared item is printed. A definition that already has items is refused
|
||||
// without --force. Settings keys missing from the export take the PHP
|
||||
// defaults.
|
||||
func ImportWinter(app *backpack.App) bonfire.Command {
|
||||
return bonfire.Command{
|
||||
Name: "sitemap:import-winter",
|
||||
@@ -328,7 +332,16 @@ func mapItems(ctx context.Context, reg *signpost.Registry, data json.RawMessage,
|
||||
if page, ok := fields["cmsPage"].(string); ok && page != "" {
|
||||
report.Lines = append(report.Lines, fmt.Sprintf("%s: cmsPage '%s' dropped (CMS pages are not supported)", label, page))
|
||||
}
|
||||
if p := models.Text(item.URLPattern); p != "" && !signpost.ValidItemPattern(p) {
|
||||
report.Lines = append(report.Lines, fmt.Sprintf("%s: urlPattern '%s' cleared (not a path starting with a single /)", label, p))
|
||||
item.URLPattern = nil
|
||||
}
|
||||
if url, ok := pageURLs[models.Text(item.Reference)]; ok && droppedTypes[item.Type] {
|
||||
if !classes.AllowedItemURL(url) {
|
||||
report.Lines = append(report.Lines, fmt.Sprintf("%s: dropped (--page-url '%s' is not a path or an http(s) URL)", label, url))
|
||||
report.Dropped++
|
||||
continue
|
||||
}
|
||||
report.Lines = append(report.Lines, fmt.Sprintf("%s: copied as type 'url' with url '%s'", label, url))
|
||||
report.Remapped++
|
||||
item.Type = models.ItemTypeURL
|
||||
@@ -349,6 +362,11 @@ func mapItems(ctx context.Context, reg *signpost.Registry, data json.RawMessage,
|
||||
}
|
||||
}
|
||||
if item.Type == models.ItemTypeURL {
|
||||
if !classes.AllowedItemURL(models.Text(item.URL)) {
|
||||
report.Lines = append(report.Lines, fmt.Sprintf("%s: dropped (the url is not a path or an http(s) URL)", label))
|
||||
report.Dropped++
|
||||
continue
|
||||
}
|
||||
out = append(out, item)
|
||||
report.Kept++
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user