# SPDX-License-Identifier: GPL-3.0-or-later """ Making temporary WebExtensions for use in the test suite """ # This file is part of Haketilo. # # Copyright (C) 2021 Wojtek Kosior # # This program 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. # # This program 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 this program. If not, see . # # I, Wojtek Kosior, thereby promise not to sue for violation of this file's # license. Although I request that you do not make use of this code in a # proprietary program, I am not going to enforce this in court. import json import zipfile from pathlib import Path from uuid import uuid4 from tempfile import TemporaryDirectory import shutil import subprocess from .misc_constants import * class ManifestTemplateValueToFill: pass def manifest_template(): return { 'manifest_version': 2, 'name': 'Haketilo test extension', 'version': '1.0', 'applications': { 'gecko': { 'id': ManifestTemplateValueToFill(), 'strict_min_version': '60.0' } }, 'permissions': [ 'contextMenus', 'webRequest', 'webRequestBlocking', 'activeTab', 'notifications', 'sessions', 'storage', 'tabs', '', 'unlimitedStorage' ], 'content_security_policy': "object-src 'none'; script-src 'self' https://serve.scrip.ts;", 'web_accessible_resources': ['testpage.html'], 'options_ui': { 'page': 'testpage.html', 'open_in_tab': True }, 'background': { 'persistent': True, 'scripts': ['__open_test_page.js', 'background.js'] }, 'content_scripts': [ { 'run_at': 'document_start', 'matches': [''], 'match_about_blank': True, 'all_frames': True, 'js': ['content.js'] } ] } class ExtraHTML: def __init__(self, html_path, append={}, wrap_into_htmldoc=True): self.html_path = html_path self.append = append self.wrap_into_htmldoc = wrap_into_htmldoc def add_to_xpi(self, xpi, tmpdir=None): if tmpdir is None: with TemporaryDirectory() as tmpdir: return self.add_to_xpi(xpi, tmpdir) append_flags = [] for filename, code in self.append.items(): append_flags.extend(['-A', f'{filename}:{code}']) awk = subprocess.run( ['awk', '-f', awk_script_name, '--', *unit_test_defines, *append_flags, '-H', self.html_path, '--write-js-deps', '--output=files-to-copy', f'--output-dir={tmpdir}'], stdout=subprocess.PIPE, cwd=script_root, check=True ) for path in filter(None, awk.stdout.decode().split('\n')): xpi.write(script_root / path, path) tmpdir = Path(tmpdir) for path in tmpdir.rglob('*'): relpath = str(path.relative_to(tmpdir)) if not path.is_dir() and relpath != self.html_path: xpi.write(path, relpath) with open(tmpdir / self.html_path, 'rt') as html_file: html = html_file.read() if self.wrap_into_htmldoc: html = f'{html}' xpi.writestr(self.html_path, html) default_background_script = '' default_content_script = '' default_test_page = ''' Extension's options page for testing

Extension's options page for testing

''' open_test_page_script = '''(() => { const page_url = browser.runtime.getURL("testpage.html"); const execute_details = { code: `window.wrappedJSObject.ext_page_url=${JSON.stringify(page_url)};` }; browser.tabs.query({currentWindow: true, active: true}) .then(t => browser.tabs.executeScript(t.id, execute_details)); })();''' def make_extension(destination_dir, background_script=default_background_script, content_script=default_content_script, test_page=default_test_page, extra_files={}, extra_html=[]): if not hasattr(extra_html, '__iter__'): extra_html = [extra_html] manifest = manifest_template() extension_id = '{%s}' % uuid4() manifest['applications']['gecko']['id'] = extension_id files = { 'manifest.json' : json.dumps(manifest), '__open_test_page.js': open_test_page_script, 'background.js' : background_script, 'content.js' : content_script, 'testpage.html' : test_page, **extra_files } destination_path = destination_dir / f'{extension_id}.xpi' with zipfile.ZipFile(destination_path, 'x') as xpi: for filename, contents in files.items(): if hasattr(contents, '__call__'): contents = contents() xpi.writestr(filename, contents) for html in extra_html: html.add_to_xpi(xpi) return destination_path