def _download_requested(self, download_item) -> None:
        """
        * If a download is requested call a save file dialog
        * :param download_item: file to be downloaded
        """
        if bindings() == "PyQt5":
            from PyQt5.QtWidgets import QFileDialog
        else:
            from PySide2.QtWidgets import QFileDialog
        dialog = QFileDialog(self)
        path = dialog.getSaveFileName(dialog, "Save File",
                                      download_item.path())

        if path[0]:
            download_item.setPath(path[0])
            print(f"downloading file to:( {download_item.path()} )")
            download_item.accept()
            self.download_item = download_item
            download_item.finished.connect(self._download_finished)
        else:
            print("Download canceled")
Example #2
0
#### Jade Application Kit
# * https://codesardine.github.io/Jade-Application-Kit
# * Vitor Lopes Copyright (c) 2016 - 2020
# * https://vitorlopes.me

import sys
import os
from JAK.Utils import Instance, bindings, getScreenGeometry
from JAK.KeyBindings import KeyPress
if bindings() == "PyQt5":
    from PyQt5.QtCore import Qt, QSize, QUrl
    from PyQt5.QtGui import QIcon, QPixmap, QImage
    from PyQt5.QtWidgets import QMainWindow, QWidget, QMessageBox, QDesktopWidget, QSystemTrayIcon,\
        QAction, QToolBar, QMenu, QMenuBar, QFileDialog, QLabel
else:
    from PySide2.QtCore import Qt, QSize, QUrl
    from PySide2.QtGui import QIcon, QPixmap, QImage
    from PySide2.QtWidgets import QMainWindow, QWidget, QMessageBox, QDesktopWidget, QSystemTrayIcon,\
        QAction, QToolBar, QMenu, QMenuBar, QFileDialog, QLabel


class SystemTrayIcon(QSystemTrayIcon):
    def __init__(self, icon, app, config):
        self.config = config
        self.icon = icon
        super(SystemTrayIcon, self).__init__(icon, parent=app)
        self.setContextMenu(self.tray_menu())
        self.show()

    def tray_menu(self):
        """
    def __init__(self, config):
        self.config = config
        super(JWebView, self).__init__()
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.profile = QWebEngineProfile.defaultProfile()
        self.webpage = JWebPage(self.profile, self, config)
        self.setPage(self.webpage)
        if config["inject_JavaScript"]["JavaScript"]:
            from JAK.Utils import JavaScript
            JavaScript.inject(self.page(), config["inject_JavaScript"])
        self.interceptor = Interceptor(config)

        if config["user_agent"]:
            # Set user agent
            self.profile.setHttpUserAgent(config["user_agent"])

        if config["debug"]:
            self.settings().setAttribute(QWebEngineSettings.XSSAuditingEnabled,
                                         True)
        else:
            self.setContextMenuPolicy(Qt.PreventContextMenu)

        if config["transparent"]:
            # Activates background transparency
            self.setAttribute(Qt.WA_TranslucentBackground)
            self.page().setBackgroundColor(Qt.transparent)
            self.setStyleSheet("background:transparent;")
            print(
                "Transparency detected, make sure you set [ body {background:transparent;} ]"
            )

        # * Set Engine options
        if self.config["JavascriptCanPaste"]:
            self.settings().setAttribute(QWebEngineSettings.JavascriptCanPaste,
                                         True)
        else:
            self.settings().setAttribute(QWebEngineSettings.JavascriptCanPaste,
                                         False)
        if self.config["PlaybackRequiresUserGesture"]:
            self.settings().setAttribute(
                QWebEngineSettings.PlaybackRequiresUserGesture, True)
        else:
            self.settings().setAttribute(
                QWebEngineSettings.PlaybackRequiresUserGesture, False)
        if self.config["FullScreenSupportEnabled"]:
            self.settings().setAttribute(
                QWebEngineSettings.FullScreenSupportEnabled, True)
        else:
            self.settings().setAttribute(
                QWebEngineSettings.FullScreenSupportEnabled, False)
        if self.config["AllowWindowActivationFromJavaScript"]:
            self.settings().setAttribute(
                QWebEngineSettings.AllowWindowActivationFromJavaScript, True)
        else:
            self.settings().setAttribute(
                QWebEngineSettings.AllowWindowActivationFromJavaScript, False)
        if self.config["LocalContentCanAccessRemoteUrls"]:
            self.settings().setAttribute(
                QWebEngineSettings.LocalContentCanAccessRemoteUrls, True)
        else:
            self.settings().setAttribute(
                QWebEngineSettings.LocalContentCanAccessRemoteUrls, False)
        if self.config["JavascriptCanAccessClipboard"]:
            self.settings().setAttribute(
                QWebEngineSettings.JavascriptCanAccessClipboard, True)
        else:
            self.settings().setAttribute(
                QWebEngineSettings.JavascriptCanAccessClipboard, False)
        if self.config["SpatialNavigationEnabled"]:
            self.settings().setAttribute(
                QWebEngineSettings.SpatialNavigationEnabled, True)
        else:
            self.settings().setAttribute(
                QWebEngineSettings.SpatialNavigationEnabled, False)
        if self.config["TouchIconsEnabled"]:
            self.settings().setAttribute(QWebEngineSettings.TouchIconsEnabled,
                                         True)
        else:
            self.settings().setAttribute(QWebEngineSettings.TouchIconsEnabled,
                                         False)
        if self.config["FocusOnNavigationEnabled"]:
            self.settings().setAttribute(
                QWebEngineSettings.FocusOnNavigationEnabled, True)
        else:
            self.settings().setAttribute(
                QWebEngineSettings.FocusOnNavigationEnabled, False)

        if config["online"]:
            self.settings().setAttribute(QWebEngineSettings.DnsPrefetchEnabled,
                                         True)
            print("Engine online (IPC) Disabled")
            self.page().profile().downloadRequested.connect(
                self._download_requested)

            # Set persistent cookies
            self.profile.setPersistentCookiesPolicy(
                QWebEngineProfile.ForcePersistentCookies)

            # set cookies on user folder
            if config["cookies_path"]:
                # allow specific path per application.
                _cookies_path = f"{os.getenv('HOME')}/.jak/{config['cookies_path']}"
            else:
                # use separate cookies database per application
                title = config["title"].lower().replace(" ", "-")
                _cookies_path = f"{os.getenv('HOME')}/.jak/{title}"

            self.profile.setPersistentStoragePath(_cookies_path)
            print(f"Cookies PATH:{_cookies_path}")
        else:
            self.settings().setAttribute(QWebEngineSettings.ShowScrollBars,
                                         False)
            print("Engine interprocess communication (IPC) up and running:")
            self._ipc_scheme_handler = IpcSchemeHandler()
            self.profile.installUrlSchemeHandler('ipc'.encode(),
                                                 self._ipc_scheme_handler)
            if config["webChannel"]["active"]:
                from JAK.Utils import JavaScript
                if bindings() == "PyQt5":
                    from PyQt5.QtCore import QFile, QIODevice
                    from PyQt5.QtWebChannel import QWebChannel

                webchannel_js = QFile(':/qtwebchannel/qwebchannel.js')
                webchannel_js.open(QIODevice.ReadOnly)
                webchannel_js = bytes(webchannel_js.readAll()).decode('utf-8')
                webchannel_js += """ var JAK;
                                      new QWebChannel(qt.webChannelTransport, function (channel) {
                                      JAK = channel.objects.Bridge;
                                      });"""

                JavaScript.inject(self.page(), {
                    "JavaScript": webchannel_js,
                    "name": "QWebChannel API"
                })
                self.channel = QWebChannel(self.page())
                if config["webChannel"]["shared_obj"]:
                    self.bridge_obj = config["webChannel"]["shared_obj"]
                else:
                    raise NotImplementedError("QWebChannel shared QObject")

                self.channel.registerObject("Bridge", self.bridge_obj)
                self.page().setWebChannel(self.channel)
                print("QWebChannel bridge active")

        self.profile.setRequestInterceptor(self.interceptor)
        print(self.profile.httpUserAgent())
        validate_url(self, config["web_contents"])
Example #4
0
    def __init__(self, config):
        self.config = config
        super(JWebView, self).__init__()
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.profile = QWebEngineProfile.defaultProfile()
        self.webpage = JWebPage(self.profile, self, config)
        self.setPage(self.webpage)
        if config['webview']["injectJavaScript"]["JavaScript"]:
            self._inject_script(config['webview']["injectJavaScript"])
        self.interceptor = Interceptor(config)

        if config['webview']["userAgent"]:
            # Set user agent
            self.profile.setHttpUserAgent(config['webview']["userAgent"])

        if config["debug"]:
            self.settings().setAttribute(QWebEngineSettings.XSSAuditingEnabled,
                                         True)
        else:
            self.setContextMenuPolicy(Qt.PreventContextMenu)

        if config['window']["transparent"]:
            # Activates background transparency
            self.setAttribute(Qt.WA_TranslucentBackground)
            self.page().setBackgroundColor(Qt.transparent)
            print("Transparency detected")

        # * Set Engine options
        self.settings().setAttribute(
            self.config['webview']['disabledSettings'], False)
        for setting in self.config['webview']['enabledSettings']:
            self.settings().setAttribute(setting, True)

        if config['webview']["online"]:
            self.settings().setAttribute(QWebEngineSettings.DnsPrefetchEnabled,
                                         True)
            print("Engine online IPC and Bridge Disabled")
            self.page().profile().downloadRequested.connect(
                self._download_requested)

            # Set persistent cookies
            self.profile.setPersistentCookiesPolicy(
                QWebEngineProfile.ForcePersistentCookies)

            # set cookies on user folder
            if config['webview']["cookiesPath"]:
                # allow specific path per application.
                _cookies_path = f"{os.getenv('HOME')}/.jak/{config['webview']['cookiesPath']}"
            else:
                # use separate cookies database per application
                title = config['window']["title"].lower().replace(" ", "-")
                _cookies_path = f"{os.getenv('HOME')}/.jak/{title}"

            self.profile.setPersistentStoragePath(_cookies_path)
            print(f"Cookies PATH:{_cookies_path}")
        else:
            self.settings().setAttribute(QWebEngineSettings.ShowScrollBars,
                                         False)
            application_script = "const JAK = {};"

            if config['webview']["IPC"]:
                print("IPC Active:")
                self._ipc_scheme_handler = IpcSchemeHandler()
                self.profile.installUrlSchemeHandler('ipc'.encode(),
                                                     self._ipc_scheme_handler)
                application_script += """JAK.IPC = function(backendFunction) {
                            window.location.href = "ipc:" + backendFunction;
                        };"""

            if config['webview']["webChannel"]["active"]:
                if bindings() == "PyQt5":
                    from PyQt5.QtCore import QFile, QIODevice
                    from PyQt5.QtWebChannel import QWebChannel

                webchannel_js = QFile(':/qtwebchannel/qwebchannel.js')
                webchannel_js.open(QIODevice.ReadOnly)
                webchannel_js = bytes(webchannel_js.readAll()).decode('utf-8')
                webchannel_js += """new QWebChannel(qt.webChannelTransport, function (channel) {
                                        JAK.Bridge = channel.objects.Bridge;
                                    });"""

                application_script += webchannel_js
                self._inject_script({
                    "JavaScript": application_script,
                    "name": "JAK"
                })
                channel = QWebChannel(self.page())
                if config['webview']["webChannel"]["sharedOBJ"]:
                    bridge_obj = config['webview']["webChannel"]["sharedOBJ"]
                else:
                    raise NotImplementedError("QWebChannel shared QObject")

                channel.registerObject("Bridge", bridge_obj)
                self.page().setWebChannel(channel)
                print("WebChannel Active:")
            else:
                self._inject_script({
                    "JavaScript": application_script,
                    "name": "JAK"
                })

        self.profile.setRequestInterceptor(self.interceptor)
        print(self.profile.httpUserAgent())
        validate_url(self, config['webview']["webContents"])
Example #5
0
    def __init__(self, config=Settings.config(), **app_config):
        super(JWebApp, self).__init__(sys.argv)
        self.config = config
        self.setAAttribute(Qt.AA_UseHighDpiPixmaps)
        self.setAAttribute(Qt.AA_EnableHighDpiScaling)
        self.applicationStateChanged.connect(self._applicationStateChanged_cb)
        for key, value in app_config.items():
            if isinstance(value, dict):
                for subkey, subvalue in app_config[key].items():
                    config[key][subkey] = subvalue
            else:
                config[key] = value

        for attr in config["setAAttribute"]:
            self.setAAttribute(attr)

        if config["remote-debug"] or "--remote-debug" in sys.argv:
            sys.argv.append("--remote-debugging-port=9000")

        if config["debug"] or "--dev" in sys.argv:
            print("Debugging On")
            if not config["debug"]:
                config["debug"] = True
        else:
            print("Production Mode On, use (--dev) for debugging")

        # Enable/Disable GPU acceleration
        if not config["disableGPU"]:
            # Virtual machine detection using SystemD
            detect_virtual_machine = subprocess.Popen(["systemd-detect-virt"],
                                                      stdout=subprocess.PIPE,
                                                      stderr=subprocess.STDOUT)
            # FIXME find a more reliable way of detecting NVIDIA cards
            detect_nvidia_pci = subprocess.Popen(
                "lspci | grep -i --color 'vga\|3d\|2d'",
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                shell=True)
            virtual = detect_virtual_machine.communicate()
            nvidia_pci = detect_nvidia_pci.communicate()
            nvidia_pci = nvidia_pci[0].decode("utf-8").lower()

        if config["disableGPU"]:
            self.disable_opengl()
            print("Disabling GPU, Software Rendering explicitly activated")
        else:
            if virtual[-1]:
                # Detect virtual machine
                print(f"Virtual machine detected:{virtual}")
                self.disable_opengl()

            elif nvidia_pci:
                # Detect NVIDIA cards
                if "nvidia" in nvidia_pci:
                    print(
                        "NVIDIA detected:Known bug - kernel rejected pushbuf")
                    print("Falling back to Software Rendering")
                    self.disable_opengl()
            else:
                print(f"Virtual Machine:{virtual[-1]}")

        # Desktop file must match application name in lowercase with dashes instead of white space.
        self.setDesktopFileName(
            f"{self.config['window']['title'].lower().replace(' ', '-')}.desktop"
        )
        self.setOrganizationDomain(self.config['webview']['webContents'])
        self.setApplicationVersion(__version__)
        if not self.config['webview']['online'] and self.config['webview'][
                'IPC']:
            if bindings() == "PyQt5":
                from PyQt5.QtWebEngineCore import QWebEngineUrlScheme
            else:
                from PySide2.QtWebEngineCore import QWebEngineUrlScheme
            QWebEngineUrlScheme.registerScheme(
                QWebEngineUrlScheme("ipc".encode()))
Example #6
0
    def __init__(self, config=config(), **app_config):
        self.config = config
        for key, value in app_config.items():
            config[key] = value

        QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
        QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
        if config["debug"] or "--dev" in sys.argv:
            # Adding some command line arguments for testing purposes,
            # this MUST BE done before initializing QApplication
            sys.argv.append(f"--remote-debugging-port={config['debug_port']}")
            print("Debugging Mode On")
            if not config["debug"]:
                config["debug"] = True
        else:
            print("Production Mode On, use (--dev) for debugging")
        # Enable/Disable GPU acceleration
        if not config["disable_gpu"]:
            # Virtual machine detection using SystemD
            detect_virtual_machine = subprocess.Popen(["systemd-detect-virt"],
                                                      stdout=subprocess.PIPE,
                                                      stderr=subprocess.STDOUT)
            # FIXME find a more reliable way of detecting NVIDIA cards
            detect_nvidia_pci = subprocess.Popen(
                "lspci | grep -i --color 'vga\|3d\|2d'",
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                shell=True)
            virtual = detect_virtual_machine.communicate()
            nvidia_pci = detect_nvidia_pci.communicate()
            nvidia_pci = nvidia_pci[0].decode("utf-8").lower()

        def disable_opengl():
            # Disable GPU acceleration
            # https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/206307
            QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL, True)

        if config["disable_gpu"]:
            disable_opengl()
            print("Disabling GPU, Software Rendering explicitly activated")
        else:
            if virtual[-1]:
                # Detect virtual machine
                print(f"Virtual machine detected:{virtual}")
                disable_opengl()

            elif nvidia_pci:
                # Detect NVIDIA cards
                if "nvidia" in nvidia_pci:
                    print(
                        "NVIDIA detected:Known bug - kernel rejected pushbuf")
                    print("Falling back to Software Rendering")
                    disable_opengl()
            else:
                print(f"Virtual Machine:{virtual[-1]}")

        super(JWebApp, self).__init__(sys.argv)
        # Desktop file must match application name in lowercase with dashes instead of white space.
        self.setDesktopFileName(
            f"{config['title'].lower().replace(' ', '-')}.desktop")
        self.setOrganizationDomain(config['web_contents'])
        self.setApplicationVersion(__version__)
        if not config['online']:
            if bindings() == "PyQt5":
                from PyQt5.QtWebEngineCore import QWebEngineUrlScheme
            else:
                from PySide2.QtWebEngineCore import QWebEngineUrlScheme
            QWebEngineUrlScheme.registerScheme(
                QWebEngineUrlScheme("ipc".encode()))