Coverage for qutebrowser/browser/greasemonkey.py : 22%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org> # # This file is part of qutebrowser. # # qutebrowser is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # qutebrowser is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Get the directory of the scripts.""" return os.path.join(standarddir.data(), 'greasemonkey')
"""Container class for userscripts, parses metadata blocks."""
self._code = code self.includes = [] self.excludes = [] self.description = None self.name = None self.namespace = None self.run_at = None self.script_meta = None self.runs_on_sub_frames = True for name, value in properties: if name == 'name': self.name = value elif name == 'namespace': self.namespace = value elif name == 'description': self.description = value elif name in ['include', 'match']: self.includes.append(value) elif name in ['exclude', 'exclude_match']: self.excludes.append(value) elif name == 'run-at': self.run_at = value elif name == 'noframes': self.runs_on_sub_frames = False
def parse(cls, source): """GreasemonkeyScript factory.
Takes a userscript source and returns a GreasemonkeyScript. Parses the Greasemonkey metadata block, if present, to fill out attributes. """ matches = re.split(cls.HEADER_REGEX, source, maxsplit=2) try: _head, props, _code = matches except ValueError: props = "" script = cls(re.findall(cls.PROPS_REGEX, props), source) script.script_meta = props if not props: script.includes = ['*'] return script
"""Return the processed JavaScript code of this script.
Adorns the source code with GM_* methods for Greasemonkey compatibility and wraps it in an IFFE to hide it within a lexical scope. Note that this means line numbers in your browser's debugger/inspector will not match up to the line numbers in the source script directly. """ return jinja.js_environment.get_template( 'greasemonkey_wrapper.js').render( scriptName="/".join([self.namespace or '', self.name]), scriptInfo=self._meta_json(), scriptMeta=self.script_meta, scriptSource=self._code)
return json.dumps({ 'name': self.name, 'description': self.description, 'matches': self.includes, 'includes': self.includes, 'excludes': self.excludes, 'run-at': self.run_at, })
"""All userscripts registered to run on a particular url."""
"""Manager of userscripts and a Greasemonkey compatible environment.
Signals: scripts_reloaded: Emitted when scripts are reloaded from disk. Any cached or already-injected scripts should be considered obsolete. """
# https://wiki.greasespot.net/Include_and_exclude_rules#Greaseable_schemes # Limit the schemes scripts can run on due to unreasonable levels of # exploitability
super().__init__(parent) self.load_scripts()
instance='greasemonkey') def load_scripts(self): """Re-read Greasemonkey scripts from disk.
The scripts are read from a 'greasemonkey' subdirectory in qutebrowser's data directory (see `:version`). """ self._run_start = [] self._run_end = [] self._run_idle = []
scripts_dir = os.path.abspath(_scripts_dir()) log.greasemonkey.debug("Reading scripts from: {}".format(scripts_dir)) for script_filename in glob.glob(os.path.join(scripts_dir, '*.js')): if not os.path.isfile(script_filename): continue script_path = os.path.join(scripts_dir, script_filename) with open(script_path, encoding='utf-8') as script_file: script = GreasemonkeyScript.parse(script_file.read()) if not script.name: script.name = script_filename
if script.run_at == 'document-start': self._run_start.append(script) elif script.run_at == 'document-end': self._run_end.append(script) elif script.run_at == 'document-idle': self._run_idle.append(script) else: if script.run_at: log.greasemonkey.warning( "Script {} has invalid run-at defined, " "defaulting to document-end".format(script_path)) # Default as per # https://wiki.greasespot.net/Metadata_Block#.40run-at self._run_end.append(script) log.greasemonkey.debug("Loaded script: {}".format(script.name)) self.scripts_reloaded.emit()
"""Fetch scripts that are registered to run for url.
returns a tuple of lists of scripts meant to run at (document-start, document-end, document-idle) """ if url.scheme() not in self.greaseable_schemes: return MatchingScripts(url, [], [], [])
string_url = url.toString(QUrl.FullyEncoded)
def _match(pattern): # For include and exclude rules if they start and end with '/' they # should be treated as a (ecma syntax) regular expression. if pattern.startswith('/') and pattern.endswith('/'): matches = re.search(pattern[1:-1], string_url, flags=re.I) return matches is not None
# Otherwise they are glob expressions. return fnmatch.fnmatch(string_url, pattern)
tester = (lambda script: any(_match(pat) for pat in script.includes) and not any(_match(pat) for pat in script.excludes))
return MatchingScripts( url, [script for script in self._run_start if tester(script)], [script for script in self._run_end if tester(script)], [script for script in self._run_idle if tester(script)] )
"""Return all scripts found in the configured script directory.""" return self._run_start + self._run_end + self._run_idle
"""Initialize Greasemonkey support.""" gm_manager = GreasemonkeyManager() objreg.register('greasemonkey', gm_manager)
try: os.mkdir(_scripts_dir()) except FileExistsError: pass |