mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-04 20:17:09 +00:00
fix(chrome): validate attribute name in unknown-prefix branch
A selector like `foo]:has(*),body[x:value` previously produced [foo]:has(*),body[x="..."], a syntactically valid CSS selector that escaped the attribute match and selected `body`. Reject anything that isn't a plain HTML attribute name.
This commit is contained in:
1 parent
8c7470a1a6
commit
a69bac7abd
2 files changed
+24
No files matched your search
@@ -3,10 +3,16 @@ package chrome
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// attrNamePattern matches HTML attribute names that are safe to drop into a
|
||||||
|
// CSS attribute selector without escaping. This avoids selectors like
|
||||||
|
// `foo]:has(*),body[x="..."]` that would escape the intended match.
|
||||||
|
var attrNamePattern = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]*$`)
|
||||||
|
|
||||||
// TranslateStringSelector converts a legacy string selector ("id:foo",
|
// TranslateStringSelector converts a legacy string selector ("id:foo",
|
||||||
// "descPrefix:bar") into a CSS selector or XPath expression usable from the
|
// "descPrefix:bar") into a CSS selector or XPath expression usable from the
|
||||||
// chrome driver's TapSelector fallback path. The boolean return is true when
|
// chrome driver's TapSelector fallback path. The boolean return is true when
|
||||||
@@ -41,6 +47,9 @@ func TranslateStringSelector(selector string) (string, bool, error) {
|
|||||||
case "placeholder", "placeholderValue", "hintText":
|
case "placeholder", "placeholderValue", "hintText":
|
||||||
return `[placeholder="` + cssEscape(value) + `"]`, false, nil
|
return `[placeholder="` + cssEscape(value) + `"]`, false, nil
|
||||||
default:
|
default:
|
||||||
|
if !attrNamePattern.MatchString(kind) {
|
||||||
|
return "", false, fmt.Errorf("unsafe selector prefix %q", kind)
|
||||||
|
}
|
||||||
return `[` + kind + `="` + cssEscape(value) + `"]`, false, nil
|
return `[` + kind + `="` + cssEscape(value) + `"]`, false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,21 @@ func TestTranslateStringSelector_RejectsMissingPrefix(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTranslateStringSelector_RejectsUnsafePrefix(t *testing.T) {
|
||||||
|
cases := []string{
|
||||||
|
`foo]:has(*),body[x:value`,
|
||||||
|
`x y:value`,
|
||||||
|
`x"y:value`,
|
||||||
|
`*:value`,
|
||||||
|
`(:value`,
|
||||||
|
}
|
||||||
|
for _, selector := range cases {
|
||||||
|
if _, _, err := TranslateStringSelector(selector); err == nil {
|
||||||
|
t.Errorf("%q: expected error for unsafe prefix", selector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCSSEscape_ControlCharactersAndNUL(t *testing.T) {
|
func TestCSSEscape_ControlCharactersAndNUL(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
Reference in new issue
Block a user