From 812741219dcd18e94f1686cafd814dd7994f3a36 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 30 Sep 2021 16:02:13 -0400 Subject: [PATCH] Ability to auto-fill span elements (#2095) * ability to autofill span elements * add modification comments --- src/content/autofill.css | 4 ++++ src/content/autofill.js | 33 ++++++++++++++++++++++++++++++-- src/models/autofillField.ts | 1 + src/services/autofill.service.ts | 32 ++++++++++++++++++++++++++++--- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/content/autofill.css b/src/content/autofill.css index e32a6f278e..453556777c 100644 --- a/src/content/autofill.css +++ b/src/content/autofill.css @@ -26,6 +26,10 @@ } } +span[data-bwautofill].com-bitwarden-browser-animated-fill { + display: inline-block; +} + .com-bitwarden-browser-animated-fill { animation: bitwardenfill 200ms ease-in-out 0ms 1; -webkit-animation: bitwardenfill 200ms ease-in-out 0ms 1; diff --git a/src/content/autofill.js b/src/content/autofill.js index b4aa58397b..260350a3ea 100644 --- a/src/content/autofill.js +++ b/src/content/autofill.js @@ -38,6 +38,7 @@ 5. Remove fakeTested prop. 6. Rename com.agilebits.* stuff to com.bitwarden.* 7. Remove "some useful globals" on window + 8. Add ability to autofill span[data-bwautofill] elements */ function collect(document, undefined) { @@ -103,6 +104,11 @@ return el; default: + // START MODIFICATION + if (!el.type && el.tagName.toLowerCase() === 'span') { + return el.innerText; + } + // END MODIFICATION return el.value; } } @@ -268,8 +274,16 @@ addProp(field, 'htmlClass', getElementAttrValue(el, 'class')); addProp(field, 'tabindex', getElementAttrValue(el, 'tabindex')); addProp(field, 'title', getElementAttrValue(el, 'title')); + // START MODIFICATION addProp(field, 'userEdited', !!el.dataset['com.browser.browser.userEdited']); + + var elTagName = el.tagName.toLowerCase(); + addProp(field, 'tagName', elTagName); + + if (elTagName === 'span') { + return field; + } // END MODIFICATION if ('hidden' != toLowerString(el.type)) { @@ -555,7 +569,8 @@ var els = []; try { var elsList = theDoc.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="reset"])' + - ':not([type="button"]):not([type="image"]):not([type="file"]):not([data-bwignore]), select'); + ':not([type="button"]):not([type="image"]):not([type="file"]):not([data-bwignore]), select, ' + + 'span[data-bwautofill]'); els = Array.prototype.slice.call(elsList); } catch (e) { } @@ -809,6 +824,12 @@ break; default: el.value == op || doAllFillOperations(el, function (theEl) { + // START MODIFICATION + if (!theEl.type && theEl.tagName.toLowerCase() === 'span') { + theEl.innerText = op; + return; + } + // END MODIFICATION theEl.value = op; }); } @@ -932,6 +953,11 @@ currentEl = currentEl === document; } } + // START MODIFICATION + if (el && !el.type && el.tagName.toLowerCase() === 'span') { + return true; + } + // END MODIFICATION return currentEl ? -1 !== 'email text password number tel url'.split(' ').indexOf(el.type || '') : false; } @@ -942,7 +968,10 @@ return null; } try { - var elements = Array.prototype.slice.call(selectAllFromDoc('input, select, button')); + // START MODIFICATION + var elements = Array.prototype.slice.call(selectAllFromDoc('input, select, button, ' + + 'span[data-bwautofill]')); + // END MODIFICATION var filteredElements = elements.filter(function (o) { return o.opid == theOpId; }); diff --git a/src/models/autofillField.ts b/src/models/autofillField.ts index 0223e50c07..236fe81577 100644 --- a/src/models/autofillField.ts +++ b/src/models/autofillField.ts @@ -21,4 +21,5 @@ export default class AutofillField { autoCompleteType: string; selectInfo: any; maxLength: number; + tagName: string; } diff --git a/src/services/autofill.service.ts b/src/services/autofill.service.ts index 1298727b5a..d50813cc43 100644 --- a/src/services/autofill.service.ts +++ b/src/services/autofill.service.ts @@ -306,7 +306,11 @@ export default class AutofillService implements AutofillServiceInterface { }); pageDetails.fields.forEach((field: any) => { - if (filledFields.hasOwnProperty(field.opid) || !field.viewable) { + if (filledFields.hasOwnProperty(field.opid)) { + return; + } + + if (!field.viewable && field.tagName !== 'span') { return; } @@ -459,6 +463,10 @@ export default class AutofillService implements AutofillServiceInterface { const fillFields: { [id: string]: AutofillField; } = {}; pageDetails.fields.forEach((f: any) => { + if (this.forCustomFieldsOnly(f)) { + return; + } + if (this.isExcludedType(f.type, ExcludedAutofillTypes)) { return; } @@ -691,6 +699,10 @@ export default class AutofillService implements AutofillServiceInterface { const fillFields: { [id: string]: AutofillField; } = {}; pageDetails.fields.forEach((f: any) => { + if (this.forCustomFieldsOnly(f)) { + return; + } + if (this.isExcludedType(f.type, ExcludedAutofillTypes)) { return; } @@ -928,6 +940,10 @@ export default class AutofillService implements AutofillServiceInterface { mustBeEmpty: boolean, fillNewPassword: boolean) { const arr: AutofillField[] = []; pageDetails.fields.forEach(f => { + if (this.forCustomFieldsOnly(f)) { + return; + } + const isPassword = f.type === 'password'; const valueIsLikePassword = (value: string) => { if (value == null) { @@ -976,6 +992,10 @@ export default class AutofillService implements AutofillServiceInterface { let usernameField: AutofillField = null; for (let i = 0; i < pageDetails.fields.length; i++) { const f = pageDetails.fields[i]; + if (this.forCustomFieldsOnly(f)) { + continue; + } + if (f.elementNumber >= passwordField.elementNumber) { break; } @@ -1152,8 +1172,14 @@ export default class AutofillService implements AutofillServiceInterface { if (field.maxLength && value && value.length > field.maxLength) { value = value.substr(0, value.length); } - fillScript.script.push(['click_on_opid', field.opid]); - fillScript.script.push(['focus_by_opid', field.opid]); + if (field.tagName !== 'span') { + fillScript.script.push(['click_on_opid', field.opid]); + fillScript.script.push(['focus_by_opid', field.opid]); + } fillScript.script.push(['fill_by_opid', field.opid, value]); } + + private forCustomFieldsOnly(field: AutofillField): boolean { + return field.tagName === 'span'; + } }