1
# Copyright (C) 2010 Canonical
7
# This program is free software; you can redistribute it and/or modify it under
8
# the terms of the GNU General Public License as published by the Free Software
9
# Foundation; version 3.
11
# This program is distributed in the hope that it will be useful, but WITHOUT
12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16
# You should have received a copy of the GNU General Public License along with
17
# this program; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
from gi.repository import WebKit as webkit
24
from gi.repository import Gtk
25
from gi.repository import Pango
28
from softwarecenter.i18n import get_language
29
from softwarecenter.paths import SOFTWARE_CENTER_CACHE_DIR
30
from softwarecenter.enums import WEBKIT_USER_AGENT_SUFFIX
31
from softwarecenter.utils import get_oem_channel_descriptor
33
from gi.repository import Soup
34
from gi.repository import WebKit
37
LOG = logging.getLogger(__name__)
40
def global_webkit_init():
41
""" this sets the defaults for webkit, its important that this gets
42
run if you want a secure webkit session
44
session = WebKit.get_default_session()
45
# add security by default (see bugzilla #666280 and #666276)
46
# enable certificates validation in webkit views unless specified otherwise
47
if not "SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK" in os.environ:
48
session = webkit.get_default_session()
50
"ssl-ca-file", "/etc/ssl/certs/ca-certificates.crt")
52
# WARN the user!! Do not remove this
53
LOG.warning("SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK " +
54
"has been specified, all purchase transactions " +
55
"are now INSECURE and UNENCRYPTED!!")
57
fname = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "cookies.txt")
58
# clear cookies again in a new session, see #1018347 comment #4
59
# there is no "logout" support right now on any of the USC pages
64
cookie_jar = Soup.CookieJarText.new(fname, False)
65
session.add_feature(cookie_jar)
66
# optional session debuggin
67
if "SOFTWARE_CENTER_DEBUG_WEBKIT" in os.environ:
68
# alternatively you can use HEADERS, BODY here
69
logger = Soup.Logger.new(Soup.LoggerLogLevel.BODY, -1)
70
logger.attach(session)
71
# ALWAYS run this or get insecurity by default
75
class SoftwareCenterWebView(webkit.WebView):
76
""" A customized version of the regular webview
79
- send Accept-Language headers from the users language
81
- send a custom user-agent string
82
- auto-fill in id_email in login.ubuntu.com
85
# javascript to auto fill email login on login.ubuntu.com
86
AUTO_FILL_SERVER = "https://login.ubuntu.com"
87
AUTO_FILL_EMAIL_JS = """
88
document.getElementById("id_email").value="%s";
89
document.getElementById("id_password").focus();
94
webkit.WebView.__init__(self)
95
self.connect("resource-request-starting",
96
self._on_resource_request_starting)
97
self.connect("notify::load-status",
98
self._on_load_status_changed)
99
settings = self.get_settings()
100
settings.set_property("enable-plugins", False)
101
settings.set_property("user-agent", self._get_user_agent_string())
102
self._auto_fill_email = ""
104
def set_auto_insert_email(self, email):
105
self._auto_fill_email = email
107
def _get_user_agent_string(self):
108
settings = self.get_settings()
109
user_agent_string = settings.get_property("user-agent")
110
user_agent_string += " %s " % WEBKIT_USER_AGENT_SUFFIX
111
user_agent_string += get_oem_channel_descriptor()
112
return user_agent_string
114
def _on_resource_request_starting(self, view, frame, res, req, resp):
115
lang = get_language()
117
message = req.get_message()
119
headers = message.get_property("request-headers")
120
headers.append("Accept-Language", lang)
121
#def _show_header(name, value, data):
123
#headers.foreach(_show_header, None)
125
def _maybe_auto_fill_in_username(self):
127
if self._auto_fill_email and uri.startswith(self.AUTO_FILL_SERVER):
129
self.AUTO_FILL_EMAIL_JS % self._auto_fill_email)
130
# ensure that we have the keyboard focus
133
def _on_load_status_changed(self, view, pspec):
135
status = view.get_property(prop)
136
if status == webkit.LoadStatus.FINISHED:
137
self._maybe_auto_fill_in_username()
140
class ScrolledWebkitWindow(Gtk.VBox):
142
def __init__(self, include_progress_ui=False):
143
super(ScrolledWebkitWindow, self).__init__()
145
self.webkit = SoftwareCenterWebView()
146
# add progress UI if needed
147
if include_progress_ui:
148
self._add_progress_ui()
149
# create main webkitview
150
self.scroll = Gtk.ScrolledWindow()
151
self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
152
Gtk.PolicyType.AUTOMATIC)
153
self.pack_start(self.scroll, True, True, 0)
154
# embed the webkit view in a scrolled window
155
self.scroll.add(self.webkit)
158
def _add_progress_ui(self):
160
self.header = Gtk.HBox()
162
self.spinner = Gtk.Spinner()
163
self.header.pack_start(self.spinner, False, False, 6)
164
# add a url to the toolbar
165
self.url = Gtk.Label()
166
self.url.set_ellipsize(Pango.EllipsizeMode.END)
167
self.url.set_alignment(0.0, 0.5)
168
self.url.set_text("")
169
self.header.pack_start(self.url, True, True, 0)
170
# frame around the box
171
self.frame = Gtk.Frame()
172
self.frame.set_border_width(3)
173
self.frame.add(self.header)
174
self.pack_start(self.frame, False, False, 6)
175
# connect the webkit stuff
176
self.webkit.connect("notify::uri", self._on_uri_changed)
177
self.webkit.connect("notify::load-status",
178
self._on_load_status_changed)
180
def _on_uri_changed(self, view, pspec):
182
uri = view.get_property(prop)
183
# the full uri is irellevant for the purchase view, but it is
184
# interessting to know what protocol/netloc is in use so that the
185
# user can verify its https on sites he is expecting
186
scheme, netloc, path, params, query, frag = urlparse.urlparse(uri)
187
if scheme == "file" and netloc == "":
188
self.url.set_text("")
190
self.url.set_text("%s://%s" % (scheme, netloc))
191
# start spinner when the uri changes
192
#self.spinner.start()
194
def _on_load_status_changed(self, view, pspec):
196
status = view.get_property(prop)
198
if status == webkit.LoadStatus.PROVISIONAL:
201
if (status == webkit.LoadStatus.FINISHED or
202
status == webkit.LoadStatus.FAILED):