mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 06:13:38 +00:00
This reverts commit 208be8dfbf.
This commit is contained in:
@@ -31,115 +31,21 @@
|
|||||||
/*
|
/*
|
||||||
MODIFICATIONS FROM ORIGINAL
|
MODIFICATIONS FROM ORIGINAL
|
||||||
|
|
||||||
1. Populate isFirefox
|
1. Populate isFirefox
|
||||||
2. Remove isChrome and isSafari since they are not used.
|
2. Remove isChrome and isSafari since they are not used.
|
||||||
3. Unminify and format to meet Mozilla review requirements.
|
3. Unminify and format to meet Mozilla review requirements.
|
||||||
4. Remove unnecessary input types from getFormElements query selector and limit number of elements returned.
|
4. Remove unnecessary input types from getFormElements query selector and limit number of elements returned.
|
||||||
5. Remove fakeTested prop.
|
5. Remove fakeTested prop.
|
||||||
6. Rename com.agilebits.* stuff to com.bitwarden.*
|
6. Rename com.agilebits.* stuff to com.bitwarden.*
|
||||||
7. Remove "some useful globals" on window
|
7. Remove "some useful globals" on window
|
||||||
8. Add ability to autofill span[data-bwautofill] elements
|
8. Add ability to autofill span[data-bwautofill] elements
|
||||||
9. Add new handler, for new command that responds with page details in response callback
|
9. Add new handler, for new command that responds with page details in response callback
|
||||||
10. Handle sandbox iframe and sandbox rule in CSP
|
10. Handle sandbox iframe and sandbox rule in CSP
|
||||||
11. Work on array of saved urls instead of just one to determine if we should autofill non-https sites
|
11. Work on array of saved urls instead of just one to determine if we should autofill non-https sites
|
||||||
12. Remove setting of attribute com.browser.browser.userEdited on user-inputs
|
12. Remove setting of attribute com.browser.browser.userEdited on user-inputs
|
||||||
13. Handle null value URLs in urlNotSecure
|
13. Handle null value URLs in urlNotSecure
|
||||||
14. Implement new HTML element query logic to be able to traverse into ShadowRoot
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* `openOrClosedShadowRoot` is only available to WebExtensions.
|
|
||||||
* We need to use the correct implementation based on browser.
|
|
||||||
*/
|
|
||||||
// START MODIFICATION
|
|
||||||
var getShadowRoot;
|
|
||||||
|
|
||||||
if (chrome.dom && chrome.dom.openOrClosedShadowRoot) {
|
|
||||||
// Chromium 88+
|
|
||||||
// https://developer.chrome.com/docs/extensions/reference/dom/
|
|
||||||
getShadowRoot = function (element) {
|
|
||||||
if (!(element instanceof HTMLElement)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return chrome.dom.openOrClosedShadowRoot(element);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
getShadowRoot = function (element) {
|
|
||||||
// `openOrClosedShadowRoot` is currently available for Firefox 63+
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Element/openOrClosedShadowRoot
|
|
||||||
// Fallback to usual shadowRoot if it doesn't exist, which will only find open ShadowRoots, not closed ones.
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot#browser_compatibility
|
|
||||||
return element.openOrClosedShadowRoot || element.shadowRoot;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns elements like Document.querySelectorAll does, but traverses the document and shadow
|
|
||||||
* roots, yielding a visited node only if it passes the predicate in filterCallback.
|
|
||||||
*/
|
|
||||||
function queryDocAll(doc, rootEl, filterCallback) {
|
|
||||||
var accumulatedNodes = [];
|
|
||||||
|
|
||||||
// mutates accumulatedNodes
|
|
||||||
accumulatingQueryDocAll(doc, rootEl, filterCallback, accumulatedNodes);
|
|
||||||
|
|
||||||
return accumulatedNodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
function accumulatingQueryDocAll(doc, rootEl, filterCallback, accumulatedNodes) {
|
|
||||||
var treeWalker = doc.createTreeWalker(rootEl, NodeFilter.SHOW_ELEMENT);
|
|
||||||
var node;
|
|
||||||
|
|
||||||
while (node = treeWalker.nextNode()) {
|
|
||||||
if (filterCallback(node)) {
|
|
||||||
accumulatedNodes.push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If node contains a ShadowRoot we want to step into it and also traverse all child nodes inside.
|
|
||||||
var nodeShadowRoot = getShadowRoot(node);
|
|
||||||
|
|
||||||
if (!nodeShadowRoot) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// recursively traverse into ShadowRoot
|
|
||||||
accumulatingQueryDocAll(doc, nodeShadowRoot, filterCallback, accumulatedNodes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns an element like Document.querySelector does, but traverses the document and shadow
|
|
||||||
* roots, yielding a visited node only if it passes the predicate in filterCallback.
|
|
||||||
*/
|
|
||||||
function queryDoc(doc, rootEl, filterCallback) {
|
|
||||||
var treeWalker = doc.createTreeWalker(rootEl, NodeFilter.SHOW_ELEMENT);
|
|
||||||
var node;
|
|
||||||
|
|
||||||
while (node = treeWalker.nextNode()) {
|
|
||||||
if (filterCallback(node)) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If node contains a ShadowRoot we want to step into it and also traverse all child nodes inside.
|
|
||||||
var nodeShadowRoot = getShadowRoot(node);
|
|
||||||
|
|
||||||
if (!nodeShadowRoot) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// recursively traverse into ShadowRoot
|
|
||||||
var subQueryResult = queryDoc(doc, nodeShadowRoot, filterCallback);
|
|
||||||
|
|
||||||
if (subQueryResult) {
|
|
||||||
return subQueryResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// END MODIFICATION
|
|
||||||
|
|
||||||
function collect(document, undefined) {
|
function collect(document, undefined) {
|
||||||
// START MODIFICATION
|
// START MODIFICATION
|
||||||
var isFirefox = navigator.userAgent.indexOf('Firefox') !== -1 || navigator.userAgent.indexOf('Gecko/') !== -1;
|
var isFirefox = navigator.userAgent.indexOf('Firefox') !== -1 || navigator.userAgent.indexOf('Gecko/') !== -1;
|
||||||
@@ -292,22 +198,12 @@
|
|||||||
theLabels = Array.prototype.slice.call(el.labels);
|
theLabels = Array.prototype.slice.call(el.labels);
|
||||||
} else {
|
} else {
|
||||||
if (el.id) {
|
if (el.id) {
|
||||||
// START MODIFICATION
|
theLabels = theLabels.concat(Array.prototype.slice.call(
|
||||||
var elId = JSON.stringify(el.id);
|
queryDoc(theDoc, 'label[for=' + JSON.stringify(el.id) + ']')));
|
||||||
var labelsByReferencedId = queryDocAll(theDoc, theDoc.body, function (node) {
|
|
||||||
return node.nodeName === 'LABEL' && node.htmlFor === elId;
|
|
||||||
});
|
|
||||||
theLabels = theLabels.concat(labelsByReferencedId);
|
|
||||||
// END MODIFICATION
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.name) {
|
if (el.name) {
|
||||||
// START MODIFICATION
|
docLabel = queryDoc(theDoc, 'label[for=' + JSON.stringify(el.name) + ']');
|
||||||
var elName = JSON.stringify(el.name);
|
|
||||||
docLabel = queryDocAll(theDoc, theDoc.body, function (node) {
|
|
||||||
return node.nodeName === 'LABEL' && node.htmlFor === elName;
|
|
||||||
});
|
|
||||||
// END MODIFICATION
|
|
||||||
|
|
||||||
for (var labelIndex = 0; labelIndex < docLabel.length; labelIndex++) {
|
for (var labelIndex = 0; labelIndex < docLabel.length; labelIndex++) {
|
||||||
if (-1 === theLabels.indexOf(docLabel[labelIndex])) {
|
if (-1 === theLabels.indexOf(docLabel[labelIndex])) {
|
||||||
@@ -364,21 +260,28 @@
|
|||||||
function toLowerString(s) {
|
function toLowerString(s) {
|
||||||
return 'string' === typeof s ? s.toLowerCase() : ('' + s).toLowerCase();
|
return 'string' === typeof s ? s.toLowerCase() : ('' + s).toLowerCase();
|
||||||
}
|
}
|
||||||
// START MODIFICATION
|
|
||||||
// renamed queryDoc to queryDocAll and moved to top
|
/**
|
||||||
// END MODIFICATION
|
* Query the document `doc` for elements matching the selector `selector`
|
||||||
|
* @param {Document} doc
|
||||||
|
* @param {string} query
|
||||||
|
* @returns {HTMLElement[]} An array of elements matching the selector
|
||||||
|
*/
|
||||||
|
function queryDoc(doc, query) {
|
||||||
|
var els = [];
|
||||||
|
try {
|
||||||
|
els = doc.querySelectorAll(query);
|
||||||
|
} catch (e) { }
|
||||||
|
return els;
|
||||||
|
}
|
||||||
|
|
||||||
// end helpers
|
// end helpers
|
||||||
|
|
||||||
var theView = theDoc.defaultView ? theDoc.defaultView : window,
|
var theView = theDoc.defaultView ? theDoc.defaultView : window,
|
||||||
passwordRegEx = RegExp('((\\\\b|_|-)pin(\\\\b|_|-)|password|passwort|kennwort|(\\\\b|_|-)passe(\\\\b|_|-)|contraseña|senha|密码|adgangskode|hasło|wachtwoord)', 'i');
|
passwordRegEx = RegExp('((\\\\b|_|-)pin(\\\\b|_|-)|password|passwort|kennwort|(\\\\b|_|-)passe(\\\\b|_|-)|contraseña|senha|密码|adgangskode|hasło|wachtwoord)', 'i');
|
||||||
|
|
||||||
// get all the docs
|
// get all the docs
|
||||||
// START MODIFICATION
|
var theForms = Array.prototype.slice.call(queryDoc(theDoc, 'form')).map(function (formEl, elIndex) {
|
||||||
var formNodes = queryDocAll(theDoc, theDoc.body, function (el) {
|
|
||||||
return el.nodeName === 'FORM';
|
|
||||||
});
|
|
||||||
var theForms = formNodes.map(function (formEl, elIndex) {
|
|
||||||
// END MODIFICATION
|
|
||||||
var op = {},
|
var op = {},
|
||||||
formOpId = '__form__' + elIndex;
|
formOpId = '__form__' + elIndex;
|
||||||
|
|
||||||
@@ -536,11 +439,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// get proper page title. maybe they are using the special meta tag?
|
// get proper page title. maybe they are using the special meta tag?
|
||||||
// START MODIFICATION
|
var theTitle = document.querySelector('[data-onepassword-title]')
|
||||||
var theTitle = queryDoc(theDoc, theDoc, function (node) {
|
|
||||||
return node.hasAttribute('data-onepassword-title');
|
|
||||||
});
|
|
||||||
// END MODIFICATION
|
|
||||||
if (theTitle && theTitle.dataset[DISPLAY_TITLE_ATTRIBUE]) {
|
if (theTitle && theTitle.dataset[DISPLAY_TITLE_ATTRIBUE]) {
|
||||||
pageDetails.displayTitle = theTitle.dataset.onepasswordTitle;
|
pageDetails.displayTitle = theTitle.dataset.onepasswordTitle;
|
||||||
}
|
}
|
||||||
@@ -656,10 +555,7 @@
|
|||||||
// walk the dom tree until we reach the top
|
// walk the dom tree until we reach the top
|
||||||
for (var elStyle; theEl && theEl !== document;) {
|
for (var elStyle; theEl && theEl !== document;) {
|
||||||
// Calculate the style of the element
|
// Calculate the style of the element
|
||||||
// START MODIFICATION
|
elStyle = el.getComputedStyle ? el.getComputedStyle(theEl, null) : theEl.style;
|
||||||
elStyle = el.getComputedStyle && theEl instanceof Element ? el.getComputedStyle(theEl, null) : theEl.style;
|
|
||||||
// END MODIFICATION
|
|
||||||
|
|
||||||
// If there's no computed style at all, we're done, as we know that it's not hidden
|
// If there's no computed style at all, we're done, as we know that it's not hidden
|
||||||
if (!elStyle) {
|
if (!elStyle) {
|
||||||
return true;
|
return true;
|
||||||
@@ -769,28 +665,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ignoredInputTypes = {
|
|
||||||
hidden: true,
|
|
||||||
submit: true,
|
|
||||||
reset: true,
|
|
||||||
button: true,
|
|
||||||
image: true,
|
|
||||||
file: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* inputEl MUST BE an instanceof HTMLInputElement, else inputEl.type.toLowerCase will throw an error
|
|
||||||
*/
|
|
||||||
function isRelevantInputField(inputEl) {
|
|
||||||
if (inputEl.hasAttribute('data-bwignore')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isIgnoredInputType = ignoredInputTypes.hasOwnProperty(inputEl.type.toLowerCase());
|
|
||||||
|
|
||||||
return !isIgnoredInputType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query `theDoc` for form elements that we can use for autofill, ranked by importance and limited by `limit`
|
* Query `theDoc` for form elements that we can use for autofill, ranked by importance and limited by `limit`
|
||||||
* @param {Document} theDoc The Document to query
|
* @param {Document} theDoc The Document to query
|
||||||
@@ -799,19 +673,13 @@
|
|||||||
*/
|
*/
|
||||||
function getFormElements(theDoc, limit) {
|
function getFormElements(theDoc, limit) {
|
||||||
// START MODIFICATION
|
// START MODIFICATION
|
||||||
|
var els = [];
|
||||||
var els = queryDocAll(theDoc, theDoc.body, function (el) {
|
try {
|
||||||
switch (el.nodeName) {
|
var elsList = theDoc.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="reset"])' +
|
||||||
case 'SELECT':
|
':not([type="button"]):not([type="image"]):not([type="file"]):not([data-bwignore]), select, ' +
|
||||||
return true;
|
'span[data-bwautofill]');
|
||||||
case 'SPAN':
|
els = Array.prototype.slice.call(elsList);
|
||||||
return el.hasAttribute('data-bwautofill');
|
} catch (e) { }
|
||||||
case 'INPUT':
|
|
||||||
return isRelevantInputField(el);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!limit || els.length <= limit) {
|
if (!limit || els.length <= limit) {
|
||||||
return els;
|
return els;
|
||||||
@@ -841,8 +709,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return returnEls;
|
return returnEls;
|
||||||
|
// END MODIFICATION
|
||||||
}
|
}
|
||||||
// END MODIFICATION
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focus the element `el` and optionally restore its original value
|
* Focus the element `el` and optionally restore its original value
|
||||||
@@ -871,12 +739,6 @@
|
|||||||
var markTheFilling = true,
|
var markTheFilling = true,
|
||||||
animateTheFilling = true;
|
animateTheFilling = true;
|
||||||
|
|
||||||
function queryPasswordInputs() {
|
|
||||||
return queryDocAll(document, document.body, function (el) {
|
|
||||||
return el.nodeName === 'INPUT' && el.type.toLowerCase() === 'password';
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if URL is not secure when the original saved one was
|
// Check if URL is not secure when the original saved one was
|
||||||
function urlNotSecure(savedURLs) {
|
function urlNotSecure(savedURLs) {
|
||||||
var passwordInputs = null;
|
var passwordInputs = null;
|
||||||
@@ -884,7 +746,7 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return savedURLs.some(url => url?.indexOf('https://') === 0) && 'http:' === document.location.protocol && (passwordInputs = queryPasswordInputs(),
|
return savedURLs.some(url => url?.indexOf('https://') === 0) && 'http:' === document.location.protocol && (passwordInputs = document.querySelectorAll('input[type=password]'),
|
||||||
0 < passwordInputs.length && (confirmResult = confirm('Warning: This is an unsecured HTTP page, and any information you submit can potentially be seen and changed by others. This Login was originally saved on a secure (HTTPS) page.\n\nDo you still wish to fill this login?'),
|
0 < passwordInputs.length && (confirmResult = confirm('Warning: This is an unsecured HTTP page, and any information you submit can potentially be seen and changed by others. This Login was originally saved on a secure (HTTPS) page.\n\nDo you still wish to fill this login?'),
|
||||||
0 == confirmResult)) ? true : false;
|
0 == confirmResult)) ? true : false;
|
||||||
}
|
}
|
||||||
@@ -1236,12 +1098,9 @@
|
|||||||
*/
|
*/
|
||||||
function getAllFields() {
|
function getAllFields() {
|
||||||
var r = RegExp('((\\\\b|_|-)pin(\\\\b|_|-)|password|passwort|kennwort|passe|contraseña|senha|密码|adgangskode|hasło|wachtwoord)', 'i');
|
var r = RegExp('((\\\\b|_|-)pin(\\\\b|_|-)|password|passwort|kennwort|passe|contraseña|senha|密码|adgangskode|hasło|wachtwoord)', 'i');
|
||||||
return queryDocAll(document, document.body, function (el) {
|
return Array.prototype.slice.call(selectAllFromDoc("input[type='text']")).filter(function (el) {
|
||||||
return el.nodeName === 'INPUT' &&
|
return el.value && r.test(el.value);
|
||||||
el.type.toLowerCase() === 'text' &&
|
}, this);
|
||||||
el.value &&
|
|
||||||
r.test(el.value);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1266,9 +1125,7 @@
|
|||||||
a: {
|
a: {
|
||||||
currentEl = el;
|
currentEl = el;
|
||||||
for (var owner = el.ownerDocument, owner = owner ? owner.defaultView : {}, theStyle; currentEl && currentEl !== document;) {
|
for (var owner = el.ownerDocument, owner = owner ? owner.defaultView : {}, theStyle; currentEl && currentEl !== document;) {
|
||||||
// START MODIFICATION
|
theStyle = owner.getComputedStyle ? owner.getComputedStyle(currentEl, null) : currentEl.style;
|
||||||
theStyle = owner.getComputedStyle && currentEl instanceof Element ? owner.getComputedStyle(currentEl, null) : currentEl.style;
|
|
||||||
// END MODIFICATION
|
|
||||||
if (!theStyle) {
|
if (!theStyle) {
|
||||||
currentEl = true;
|
currentEl = true;
|
||||||
break a;
|
break a;
|
||||||
@@ -1302,19 +1159,12 @@
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// START MODIFICATION
|
// START MODIFICATION
|
||||||
var filteredElements = queryDocAll(document, document.body, function (el) {
|
var elements = Array.prototype.slice.call(selectAllFromDoc('input, select, button, ' +
|
||||||
switch (el.nodeName) {
|
'span[data-bwautofill]'));
|
||||||
case 'INPUT':
|
|
||||||
case 'SELECT':
|
|
||||||
case 'BUTTON':
|
|
||||||
return el.opid === theOpId;
|
|
||||||
case 'SPAN':
|
|
||||||
return el.hasAttribute('data-bwautofill') && el.opid === theOpId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
// END MODIFICATION
|
// END MODIFICATION
|
||||||
|
var filteredElements = elements.filter(function (o) {
|
||||||
|
return o.opid == theOpId;
|
||||||
|
});
|
||||||
if (0 < filteredElements.length) {
|
if (0 < filteredElements.length) {
|
||||||
theElement = filteredElements[0],
|
theElement = filteredElements[0],
|
||||||
1 < filteredElements.length && console.warn('More than one element found with opid ' + theOpId);
|
1 < filteredElements.length && console.warn('More than one element found with opid ' + theOpId);
|
||||||
@@ -1335,11 +1185,11 @@
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function selectAllFromDoc(theSelector) {
|
function selectAllFromDoc(theSelector) {
|
||||||
// START MODIFICATION
|
var d = document, elements = [];
|
||||||
return queryDocAll(document, document, function(node) {
|
try {
|
||||||
return node.matches(theSelector);
|
elements = d.querySelectorAll(theSelector);
|
||||||
});
|
} catch (e) { }
|
||||||
// END MODIFICATION
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user