mirror of
https://github.com/vale981/tridactyl
synced 2025-03-05 09:31:41 -05:00
src/{content,dom,hinting}.ts: Implement addEventListener hijacking
This commit makes Tridactyl aware of elements made interactive through JavaScript and lets Tridactyl put hints on them. Something possibly dangerous is done here: exporting a function to the page's context. While it is believed that the current implementation is secure and that pages can't discover whether the function has been exported or not, this might change due to new standards being adopted by firefox. One of these standards is the Custom Elements api: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements It will be necessary to check how Tridactyl behaves once this API has landed. The status of this API seems to be tracked here: https://bugzilla.mozilla.org/show_bug.cgi?id=1406825
This commit is contained in:
parent
a4a3d4feb5
commit
f584c67f16
3 changed files with 73 additions and 2 deletions
|
@ -41,3 +41,5 @@ import * as webext from './lib/webext'
|
|||
webext,
|
||||
l: prom => prom.then(console.log).catch(console.error),
|
||||
})
|
||||
|
||||
dom.hijackPageListenerFunctions()
|
||||
|
|
66
src/dom.ts
66
src/dom.ts
|
@ -270,3 +270,69 @@ export function compareElementArea(a: HTMLElement, b: HTMLElement): number {
|
|||
|
||||
return aArea - bArea
|
||||
}
|
||||
|
||||
export const hintworthy_js_elems = []
|
||||
|
||||
/** Adds or removes an element from the hintworthy_js_elems array of the
|
||||
* current tab.
|
||||
* This function is made available to the page. We should be very careful
|
||||
* about the input it accepts and what it does with it. It should especially
|
||||
* be tested again when Custom elements land in Firefox.
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1406825
|
||||
* @param {EventTarget} elem The element add/removeEventListener is called on
|
||||
* @param {boolean} add true when called from addEventListener,
|
||||
* false from removeEventListener
|
||||
* @param {string} event The event name given to add/removeEventListener
|
||||
*/
|
||||
export function registerEvListenerAction(elem: EventTarget, add: boolean, event: string) {
|
||||
// Make sure elem is can exist in a document
|
||||
try {
|
||||
// We need to clone elem here otherwise it will be removed frome the page
|
||||
document.createDocumentFragment().appendChild((elem as Node).cloneNode())
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case "click":
|
||||
case "mousedown":
|
||||
case "mouseup":
|
||||
case "mouseover":
|
||||
if (add) {
|
||||
hintworthy_js_elems.push(elem)
|
||||
} else {
|
||||
// Possible bug: If a page adds an event listener for "click" and
|
||||
// "mousedown" and removes "mousedown" twice, we lose track of the
|
||||
// elem even though it still has a "click" listener.
|
||||
// Fixing this might not be worth the added complexity.
|
||||
let index = hintworthy_js_elems.indexOf(elem)
|
||||
if (index >= 0)
|
||||
hintworthy_js_elems.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Replace the page's addEventListener with a closure containing a reference
|
||||
* to the original addEventListener and [[registerEvListenerAction]]. Do the
|
||||
* same with removeEventListener.
|
||||
*/
|
||||
export function hijackPageListenerFunctions(): void {
|
||||
let exportedName = 'registerEvListenerAction'
|
||||
exportFunction(registerEvListenerAction, window, {defineAs: exportedName})
|
||||
|
||||
let eval_str = ["addEventListener", "removeEventListener"].reduce((acc, cur) => `${acc};
|
||||
EventTarget.prototype.${cur} = ((realFunction, register) => {
|
||||
return function (...args) {
|
||||
let result = realFunction.apply(this, args)
|
||||
try {
|
||||
register(this, ${cur === "addEventListener"}, args[0])
|
||||
} catch (e) {
|
||||
// Don't let the page know something wrong happened here
|
||||
}
|
||||
return result
|
||||
}
|
||||
})(EventTarget.prototype.${cur}, ${exportedName})`
|
||||
, "")
|
||||
|
||||
window.eval(eval_str + `;delete ${exportedName}`)
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
import * as DOM from './dom'
|
||||
import {log} from './math'
|
||||
import {permutationsWithReplacement, islice, izip, map} from './itertools'
|
||||
import {permutationsWithReplacement, islice, izip, map, unique} from './itertools'
|
||||
import {hasModifiers} from './keyseq'
|
||||
import state from './state'
|
||||
import {messageActiveTab, message} from './messaging'
|
||||
|
@ -371,7 +371,10 @@ function pushKey(ke) {
|
|||
2. Not hidden by another element
|
||||
*/
|
||||
function hintables(selectors=HINTTAGS_selectors) {
|
||||
return DOM.getElemsBySelector(selectors, [DOM.isVisible])
|
||||
let elems = DOM.getElemsBySelector(selectors, [])
|
||||
elems = elems.concat(DOM.hintworthy_js_elems)
|
||||
elems = unique(elems)
|
||||
return elems.filter(DOM.isVisible)
|
||||
}
|
||||
|
||||
function elementswithtext() {
|
||||
|
|
Loading…
Add table
Reference in a new issue