mirror of
https://github.com/bitwarden/android.git
synced 2026-10-22 02:53:19 -05:00
Parsing data from shadow dom selectors
This commit is contained in:
2 files changed
+37
-7
No files matched your search
+12
-5
@@ -194,17 +194,24 @@ private fun parseCompositeSelectorArray(element: JsonElement): List<SelectorClau
|
||||
}
|
||||
|
||||
internal fun parseSingleSelector(selector: String): SelectorClause? {
|
||||
if (selector.contains(">>>")) return null
|
||||
if (selector.trimStart().startsWith(".")) return null
|
||||
// For shadow DOM / iframe selectors (>>>), extract the last segment — the actual target
|
||||
// element. Android's autofill framework may expose these elements via htmlInfo when they
|
||||
// are reachable (e.g. open shadow roots), so we parse their attributes for matching.
|
||||
val effective = if (selector.contains(">>>")) {
|
||||
selector.substringAfterLast(">>>").trim()
|
||||
} else {
|
||||
selector
|
||||
}
|
||||
if (effective.trimStart().startsWith(".")) return null
|
||||
|
||||
val tag = TAG_REGEX.find(selector)?.groupValues?.get(1)
|
||||
val tag = TAG_REGEX.find(effective)?.groupValues?.get(1)
|
||||
|
||||
var id: String? = null
|
||||
var name: String? = null
|
||||
var type: String? = null
|
||||
var role: String? = null
|
||||
|
||||
ATTRIBUTE_REGEX.findAll(selector).forEach { match ->
|
||||
ATTRIBUTE_REGEX.findAll(effective).forEach { match ->
|
||||
val attrName = match.groupValues[1]
|
||||
val attrValue = match.groupValues[2]
|
||||
when (attrName) {
|
||||
@@ -217,7 +224,7 @@ internal fun parseSingleSelector(selector: String): SelectorClause? {
|
||||
|
||||
// Fallback: extract id from #shorthand (e.g. input#oid) when not present as [id='...'].
|
||||
if (id == null) {
|
||||
id = ID_SHORTHAND_REGEX.find(selector)?.groupValues?.get(1)
|
||||
id = ID_SHORTHAND_REGEX.find(effective)?.groupValues?.get(1)
|
||||
}
|
||||
|
||||
return SelectorClause(tag = tag, id = id, name = name, type = type, role = role)
|
||||
|
||||
+25
-2
@@ -320,8 +320,31 @@ class FillAssistManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parseSingleSelector returns null for shadow DOM selector`() {
|
||||
assertNull(parseSingleSelector("div#container >>> input#field"))
|
||||
fun `parseSingleSelector extracts last segment of shadow DOM selector`() {
|
||||
assertEquals(
|
||||
FillAssistRules.SelectorClause(
|
||||
tag = "input",
|
||||
id = "field",
|
||||
name = null,
|
||||
type = null,
|
||||
role = null,
|
||||
),
|
||||
parseSingleSelector("div#container >>> input#field"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parseSingleSelector extracts last segment of multi-level shadow DOM selector`() {
|
||||
assertEquals(
|
||||
FillAssistRules.SelectorClause(
|
||||
tag = "input",
|
||||
name = "password",
|
||||
id = null,
|
||||
type = null,
|
||||
role = null,
|
||||
),
|
||||
parseSingleSelector("div#form-container >>> form > div >>> input[name='password']"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user