Files
go-extractor/node.go
Steve Dudenhoeffer 6e94bfe10f
All checks were successful
CI / build (pull_request) Successful in 47s
CI / test (pull_request) Successful in 48s
CI / vet (pull_request) Successful in 1m1s
fix: eliminate XSS vulnerability in SetAttribute by using Playwright arg passing
Replace string interpolation in SetAttribute with Playwright's Evaluate
argument passing mechanism. This structurally eliminates the injection
surface — arbitrary name/value strings are safely passed as JavaScript
arguments rather than interpolated into the expression string.

The vulnerable escapeJavaScript helper (which only escaped \ and ') is
removed since it is no longer needed.

Closes #12

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:12:46 +00:00

113 lines
2.2 KiB
Go

package extractor
import (
"fmt"
"github.com/playwright-community/playwright-go"
)
type Node interface {
Content() (string, error)
Text() (string, error)
Attr(name string) (string, error)
Screenshot() ([]byte, error)
Type(input string) error
Click() error
Select(selector string) Nodes
SelectFirst(selector string) Node
ForEach(selector string, fn func(Node) error) error
SetHidden(val bool) error
SetAttribute(name, value string) error
}
type node struct {
locator playwright.Locator
}
func (n node) Type(input string) error {
return n.locator.Type(input)
}
func (n node) Click() error {
return n.locator.Click()
}
func (n node) Content() (string, error) {
return n.locator.TextContent()
}
func (n node) Text() (string, error) {
return n.locator.InnerText()
}
func (n node) Attr(name string) (string, error) {
return n.locator.GetAttribute(name)
}
func (n node) Screenshot() ([]byte, error) {
return n.locator.Screenshot()
}
func (n node) Select(selector string) Nodes {
elements, err := n.locator.Locator(selector).All()
if err != nil {
return nil
}
var nodes Nodes
for _, element := range elements {
nodes = append(nodes, node{locator: element})
}
return nodes
}
func (n node) SelectFirst(selector string) Node {
return n.Select(selector).First()
}
func (n node) ForEach(selector string, fn func(Node) error) error {
elements, err := n.locator.Locator(selector).All()
if err != nil {
return err
}
for _, element := range elements {
if err := fn(node{locator: element}); err != nil {
return err
}
}
return nil
}
func (n node) SetHidden(val bool) error {
visible, err := n.locator.IsVisible()
if err != nil {
return fmt.Errorf("error checking visibility: %w", err)
}
if visible == !val {
return nil
}
// Set the hidden property
_, err = n.locator.Evaluate(fmt.Sprintf(`(element) => element.hidden = %t;`, val), nil)
if err != nil {
return fmt.Errorf("error setting hidden property: %w", err)
}
return nil
}
func (n node) SetAttribute(name, value string) error {
_, err := n.locator.Evaluate(
`(element, args) => element.setAttribute(args.name, args.value)`,
map[string]string{"name": name, "value": value},
)
return err
}