1# Copyright (c) 2017-2021 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
2# This program is free software: you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation, either version 3 of the License, or
5# (at your option) any later version.
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9# GNU General Public License for more details.
10# You should have received a copy of the GNU General Public License
11# along with this program. If not, see <http://www.gnu.org/licenses/>.
12
13from gi.repository import Gio, WebKit2
14
15from urllib.parse import urlparse
16
17from eolie.helper_passwords import PasswordsHelper
18from eolie.define import App
19from eolie.utils import get_baseuri, emit_signal
20from eolie.logger import Logger
21
22
23class WebViewHelpers:
24    """
25        JS helpers for webview
26    """
27
28    def __init__(self):
29        """
30            Init helpers
31        """
32        self.__readability_status = False
33        self.__passwords_helper = PasswordsHelper()
34
35    def set_forms_content(self, uuid):
36        """
37            Set input forms for uuid
38            @parma uuid as str
39        """
40        self.__passwords_helper.get_by_uuid(uuid, self.__on_get_password_by)
41
42    def check_readability(self):
43        """
44            Check webview readability
45            @param webview as WebView
46        """
47        # Load Readability
48        js1 = Gio.File.new_for_uri(
49            "resource:///org/gnome/Eolie/Readability-readerable.js")
50        js2 = Gio.File.new_for_uri(
51            "resource:///org/gnome/Eolie/Readability_check.js")
52        (status, content1, tags) = js1.load_contents()
53        (status, content2, tags) = js2.load_contents()
54        script = content1.decode("utf-8") + content2.decode("utf-8")
55        self.run_javascript(script, None, self.__on_readability_status)
56
57    @property
58    def readability_status(self):
59        """
60            True if webview readable
61            @return bool
62        """
63        return self.__readability_status
64
65#######################
66# PROTECTED           #
67#######################
68    def _on_load_changed(self, webview, event):
69        """
70            Run JS helpers
71            @param webview as WebView
72            @param event as WebKit2.LoadEvent
73        """
74        if event == WebKit2.LoadEvent.FINISHED:
75            user_script = App().settings.get_value(
76                "user-script-uri").get_string()
77            f = Gio.File.new_for_uri(user_script)
78            if f.query_exists():
79                try:
80                    (status, contents, tags) = f.load_contents(None)
81                    self.run_javascript(contents.decode("utf-8"), None, None)
82                except:
83                    pass
84            self.run_javascript_from_gresource(
85                "/org/gnome/Eolie/Extensions.js", None, None)
86            self.run_javascript_from_gresource(
87                "/org/gnome/Eolie/javascript/HandleInput.js", None, None)
88            self.__run_insecure(webview.uri)
89            self.__run_set_forms(webview.uri)
90
91#######################
92# PRIVATE             #
93#######################
94    def __run_insecure(self, uri):
95        """
96            Run a script checking for password inputs while in http
97            @parma uri as str
98        """
99        parsed = urlparse(uri)
100        if parsed.scheme == "http":
101            self.run_javascript_from_gresource(
102                "/org/gnome/Eolie/javascript/Insecure.js", None, None)
103
104    def __run_set_forms(self, uri):
105        """
106            Set input forms for current uri
107            @parma uri as str
108        """
109        self.run_javascript_from_gresource(
110                "/org/gnome/Eolie/javascript/FormMenu.js",
111                None, self.__on_get_forms)
112
113    def __on_readability_status(self, source, result):
114        """
115            Get readability status
116            @param source as GObject.Object
117            @param result as Gio.AsyncResult
118        """
119        try:
120            data = source.run_javascript_from_gresource_finish(result)
121            self.__readability_status = bool(data.get_js_value().to_string())
122            emit_signal(self, "readability-status", self.__readability_status)
123        except Exception as e:
124            Logger.error("WebViewHelpers::__on_readability_status(): %s", e)
125
126    def __on_get_forms(self, source, result):
127        """
128            Start search with selection
129            @param source as GObject.Object
130            @param result as Gio.AsyncResult
131        """
132        try:
133            data = source.run_javascript_from_gresource_finish(result)
134            message = data.get_js_value().to_string()
135            split = message.split("\n")
136            for user_form_name in split:
137                self.__passwords_helper.get(get_baseuri(self.uri),
138                                            user_form_name,
139                                            None,
140                                            self.__on_get_password_by)
141        except Exception as e:
142            Logger.warning("WebViewHelpers::__on_get_forms(): %s", e)
143
144    def __on_get_password_by(self, attributes, password,
145                             ignored, index, count):
146        """
147            Set login/password input
148            @param attributes as {}
149            @param password as str
150            @param ignored
151            @param index as int
152            @param count as int
153        """
154        if attributes is None or count > 1:
155            return
156        f = Gio.File.new_for_uri(
157            "resource:///org/gnome/Eolie/javascript/SetForms.js")
158        (status, contents, tags) = f.load_contents(None)
159        js = contents.decode("utf-8")
160        js = js.replace("@INPUT_NAME@", attributes["userform"])
161        js = js.replace("@INPUT_PASSWORD@", attributes["passform"])
162        js = js.replace("@USERNAME@", attributes["login"])
163        js = js.replace("@PASSWORD@", password)
164        self.run_javascript(js, None, None)
165