diff --git a/filter_tag_resolution_test.go b/filter_tag_resolution_test.go new file mode 100644 index 0000000..4237314 --- /dev/null +++ b/filter_tag_resolution_test.go @@ -0,0 +1,43 @@ +package pongo2_test + +import ( + "strings" + "testing" + + "github.com/flosch/pongo2/v7" +) + +func TestFilterTagResolvesFiltersAtParseTime(t *testing.T) { + t.Parallel() + tests := []struct { + name string + filter string + setup func(*pongo2.TemplateSet) error + want string + }{ + { + name: "banned", + filter: "upper", + setup: func(set *pongo2.TemplateSet) error { return set.BanFilter("upper") }, + want: "Usage of filter 'upper' is not allowed", + }, + { + name: "unknown", + filter: "does_not_exist", + setup: func(*pongo2.TemplateSet) error { return nil }, + want: "Filter 'does_not_exist' does not exist", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + set := pongo2.NewSet(test.name, &pongo2.DummyLoader{}) + if err := test.setup(set); err != nil { + t.Fatalf("setup: %v", err) + } + _, err := set.FromString("{% filter " + test.filter + " %}body{% endfilter %}") + if err == nil || !strings.Contains(err.Error(), test.want) { + t.Fatalf("FromString error = %v, want %q", err, test.want) + } + }) + } +} diff --git a/tags_filter.go b/tags_filter.go index 0356706..bcd64ba 100644 --- a/tags_filter.go +++ b/tags_filter.go @@ -2,12 +2,13 @@ package pongo2 import ( "bytes" + "fmt" ) -// nodeFilterCall represents a single filter call with its name and optional parameter. +// nodeFilterCall represents one resolved filter with its optional parameter. type nodeFilterCall struct { - name string paramExpr IEvaluator + filter FilterFunction } // tagFilterNode represents the {% filter %} tag. @@ -76,7 +77,7 @@ func (node *tagFilterNode) Execute(ctx *ExecutionContext, writer TemplateWriter) } else { param = AsValue(nil) } - value, err = ctx.template.set.ApplyFilter(call.name, value, param) + value, err = call.filter(value, param) if err != nil { return ctx.Error(err.Error(), node.position) } @@ -111,7 +112,15 @@ func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, er if nameToken == nil { return nil, arguments.Error("Expected a filter name (identifier).", nil) } - filterCall.name = nameToken.Val + if _, banned := doc.template.set.bannedFilters[nameToken.Val]; banned { + return nil, arguments.Error(fmt.Sprintf("Usage of filter '%s' is not allowed (sandbox restriction active).", + nameToken.Val), nameToken) + } + filter, exists := doc.template.set.filters[nameToken.Val] + if !exists { + return nil, arguments.Error(fmt.Sprintf("Filter '%s' does not exist.", nameToken.Val), nameToken) + } + filterCall.filter = filter if arguments.MatchOne(TokenSymbol, ":") != nil { // Filter parameter