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 GLib, Gio
14
15from gettext import gettext as _
16
17from eolie.define import App, LoadingState
18
19
20class WebViewErrors:
21    """
22        Implement WebView erros, should be inherited by a WebView
23    """
24
25    def __init__(self):
26        """
27            Init errors
28        """
29        self.__bad_tls = None  # Keep invalid TLS certificate
30        self.connect("load-failed", self.__on_load_failed)
31        self.connect("load-failed-with-tls-errors", self.__on_load_failed_tls)
32        self.connect("web-process-crashed", self.__on_web_process_crashed)
33
34    def reset_bad_tls(self):
35        """
36            Reset invalid certificate
37        """
38        self.__bad_tls = None
39
40    @property
41    def bad_tls(self):
42        """
43            Get invalid certificate
44            @return Gio.TlsCertificate
45        """
46        return self.__bad_tls
47
48#######################
49# PROTECTED           #
50#######################
51
52#######################
53# PRIVATE             #
54#######################
55    def __check_for_network(self, uri):
56        """
57            Load uri when network is available
58        """
59        if Gio.NetworkMonitor.get_default().get_network_available():
60            self.load_uri(uri)
61        else:
62            return True
63
64    def __on_load_failed(self, view, event, uri, error):
65        """
66            Show error page
67            @param view as WebKit2.WebView
68            @param event as WebKit2.LoadEvent
69            @param uri as str
70            @param error as GLib.Error
71        """
72        self._loading_state = LoadingState.ERROR
73        # Ignore HTTP errors
74        if error.code > 101:
75            return False
76        network_available = Gio.NetworkMonitor.get_default(
77        ).get_network_available()
78        f = Gio.File.new_for_uri("resource:///org/gnome/Eolie/error.css")
79        (status, css_content, tag) = f.load_contents(None)
80        css = css_content.decode("utf-8")
81        # Hide reload button if network is down
82        if network_available:
83            css = css.replace("@button@", "")
84        else:
85            css = css.replace("@button@", "display: none")
86        f = Gio.File.new_for_uri("resource:///org/gnome/Eolie/error.html")
87        (status, content, tag) = f.load_contents(None)
88        html = content.decode("utf-8")
89        if network_available:
90            title = _("Failed to load this web page")
91            detail = _("It may be temporarily inaccessible or moved"
92                       " to a new address.<br/>"
93                       "You may wish to verify that your internet"
94                       " connection is working correctly.")
95            icon = "dialog-information-symbolic"
96        else:
97            title = _("Network not available")
98            detail = _("Check your network connection")
99            icon = "network-offline-symbolic"
100        html = html % (title,
101                       css,
102                       uri,
103                       "internal://%s" % icon,
104                       title,
105                       "<b>%s</b> %s" % (uri, error.message),
106                       detail,
107                       "suggested-action",
108                       _("Retry"))
109        self.load_alternate_html(html, uri)
110        if not network_available:
111            GLib.timeout_add(1000, self.__check_for_network, uri)
112        return True
113
114    def __on_load_failed_tls(self, view, uri, certificate, errors):
115        """
116            Show TLS error page
117            @param view as WebKit2.WebView
118            @param certificate as Gio.TlsCertificate
119            @parma errors as Gio.TlsCertificateFlags
120        """
121        self._loading_state = LoadingState.ERROR
122        self.__bad_tls = certificate
123        accept_uri = uri.replace("https://", "accept://")
124        if App().websettings.get("accept_tls", uri):
125            self.load_uri(accept_uri)
126        else:
127            f = Gio.File.new_for_uri("resource:///org/gnome/Eolie/error.css")
128            (status, css_content, tag) = f.load_contents(None)
129            css = css_content.decode("utf-8")
130            f = Gio.File.new_for_uri("resource:///org/gnome/Eolie/error.html")
131            (status, content, tag) = f.load_contents(None)
132            html = content.decode("utf-8")
133            if errors == Gio.TlsCertificateFlags.BAD_IDENTITY:
134                error = _("The certificate does not match this website")
135            elif errors == Gio.TlsCertificateFlags.EXPIRED:
136                error = _("The certificate has expired")
137            elif errors == Gio.TlsCertificateFlags.UNKNOWN_CA:
138                error = _("The signing certificate authority is not known")
139            elif errors == Gio.TlsCertificateFlags.GENERIC_ERROR:
140                error = _("The certificate contains errors")
141            elif errors == Gio.TlsCertificateFlags.REVOKED:
142                error = _("The certificate has been revoked")
143            elif errors == Gio.TlsCertificateFlags.INSECURE:
144                error = _("The certificate is signed using"
145                          " a weak signature algorithm")
146            elif errors == Gio.TlsCertificateFlags.NOT_ACTIVATED:
147                error = _(
148                    "The certificate activation time is still in the future")
149            else:
150                error = _("The identity of this website has not been verified")
151            html = html % (_("Connection is not secure"),
152                           css,
153                           accept_uri,
154                           "internal://dialog-warning-symbolic",
155                           _("Connection is not secure"),
156                           error,
157                           _("This does not look like the real %s.<br/>"
158                             "Attackers might be trying to steal or alter"
159                             " information going to or from this site"
160                             " (for example, private messages, credit card"
161                             " information, or passwords).") % uri,
162                           "destructive-action",
163                           _("Accept Risk and Proceed"))
164            self.load_alternate_html(html, uri)
165        return True
166
167    def __on_web_process_crashed(self, webview):
168        """
169            We just crashed :-(
170            @param webview as WebKit2.WebView
171        """
172        self._loading_state = LoadingState.ERROR
173        f = Gio.File.new_for_uri("resource:///org/gnome/Eolie/error.css")
174        (status, css_content, tag) = f.load_contents(None)
175        css = css_content.decode("utf-8")
176        f = Gio.File.new_for_uri("resource:///org/gnome/Eolie/error.html")
177        (status, content, tag) = f.load_contents(None)
178        html = content.decode("utf-8")
179        html = html % (_("WebKit web engine crashed"),
180                       css,
181                       "https://bugs.webkit.org/"
182                       "enter_bug.cgi?product=WebKit')",
183                       "internal://help-faq-symbolic",
184                       _("WebKit web engine crashed"),
185                       "",
186                       _("The webpage was terminated unexpectedly. "
187                         "To continue, reload or go to another page.<br/><br/>"
188                         "If problem persists, you can report a bug :)<br/>"
189                         "Use <b>'WebKit Gtk'</b> as component.<br/>"
190                         "Set <b>[GTK]</b> as subject prefix."),
191                       "suggested-action",
192                       _("Report a bug now"))
193        self.load_html(html, webview.uri)
194        return True
195