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>
113 lines
2.2 KiB
Go
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
|
|
}
|