Beispiel #1
0
 def __init__(self, parent):
     Gtk.Dialog.__init__(self)
     self.set_default_size(420, 400)
     self.set_transient_for(parent)
     self.set_title(_("Terms of Use"))
     # buttons
     self.add_button(_("Decline"), Gtk.ResponseType.NO)
     self.add_button(_("Accept"), Gtk.ResponseType.YES)
     # label
     self.label = Gtk.Label(_(u"One moment, please\u2026"))
     self.label.show()
     # add the label
     box = self.get_action_area()
     box.pack_start(self.label, False, False, 0)
     box.set_child_secondary(self.label, True)
     # hrm, hrm, there really should be a better way
     for itm in box.get_children():
         if itm.get_label() == _("Accept"):
             self.button_accept = itm
             break
     self.button_accept.set_sensitive(False)
     # webkit
     wb = ScrolledWebkitWindow()
     wb.show_all()
     self.webkit = wb.webkit
     self.webkit.connect("notify::load-status",
                         self._on_load_status_changed)
     # content
     content = self.get_content_area()
     self.spinner = SpinnerNotebook(wb)
     self.spinner.show_all()
     content.pack_start(self.spinner, True, True, 0)
Beispiel #2
0
 def __init__(self, parent):
     Gtk.Dialog.__init__(self)
     self.set_default_size(420, 400)
     self.set_transient_for(parent)
     self.set_title(_("Terms of Use"))
     # buttons
     self.add_button(_("Decline"), Gtk.ResponseType.NO)
     self.add_button(_("Accept"), Gtk.ResponseType.YES)
     # label
     self.label = Gtk.Label(_(u"One moment, please\u2026"))
     self.label.show()
     # add the label
     box = self.get_action_area()
     box.pack_start(self.label, False, False, 0)
     box.set_child_secondary(self.label, True)
     # hrm, hrm, there really should be a better way
     for itm in box.get_children():
         if itm.get_label() == _("Accept"):
             self.button_accept = itm
             break
     self.button_accept.set_sensitive(False)
     # webkit
     wb = ScrolledWebkitWindow()
     wb.show_all()
     self.webkit = wb.webkit
     self.webkit.connect(
         "notify::load-status", self._on_load_status_changed)
     # content
     content = self.get_content_area()
     self.spinner = SpinnerNotebook(wb)
     self.spinner.show_all()
     content.pack_start(self.spinner, True, True, 0)
    def init_view(self):
        if self.wk is None:
            self.wk = ScrolledWebkitWindow()
            #self.wk.webkit.connect("new-window-policy-decision-requested",
            #    self._on_new_window)
            self.wk.webkit.connect("create-web-view", self._on_create_web_view)
            self.wk.webkit.connect("close-web-view", self._on_close_web_view)
            self.wk.webkit.connect("console-message", self._on_console_message)

            # a possible way to do IPC (script or title change)
            self.wk.webkit.connect("script-alert", self._on_script_alert)
            self.wk.webkit.connect("title-changed", self._on_title_changed)
            self.wk.webkit.connect("notify::load-status",
                                   self._on_load_status_changed)
        # unblock signal handlers if needed when showing the purchase webkit
        # view in case they were blocked after a previous purchase was
        # completed or canceled
        self._unblock_wk_handlers()
 def _on_create_web_view(self, view, frame):
     win = Gtk.Window()
     win.set_size_request(400, 400)
     wk = ScrolledWebkitWindow(include_progress_ui=True)
     wk.webkit.connect("close-web-view", self._on_close_web_view)
     win.add(wk)
     win.show_all()
     # make sure close will work later
     wk.webkit.set_data("win", win)
     # find and set parent
     w = self.wk.get_parent()
     while w.get_parent():
         w = w.get_parent()
     win.set_transient_for(w)
     return wk.webkit
Beispiel #5
0
    def init_view(self):
        if self.wk is None:
            self.wk = ScrolledWebkitWindow()
            #self.wk.webkit.connect("new-window-policy-decision-requested",
            #    self._on_new_window)
            self.wk.webkit.connect("create-web-view", self._on_create_web_view)
            self.wk.webkit.connect("close-web-view", self._on_close_web_view)
            self.wk.webkit.connect("console-message", self._on_console_message)

            # a possible way to do IPC (script or title change)
            self.wk.webkit.connect("script-alert", self._on_script_alert)
            self.wk.webkit.connect("title-changed", self._on_title_changed)
            self.wk.webkit.connect("notify::load-status",
                self._on_load_status_changed)
        # unblock signal handlers if needed when showing the purchase webkit
        # view in case they were blocked after a previous purchase was
        # completed or canceled
        self._unblock_wk_handlers()
class PurchaseView(Gtk.VBox):
    """
    View that displays the webkit-based UI for purchasing an item.
    """

    LOADING_HTML = """
<html>
<head>
 <title></title>
</head>
<style type="text/css">
html {
  background: #fff;
  color: #000;
  font: sans-serif;
  font: caption;
  text-align: center;
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%%;
  height: 100%%;
  display: table;
}
body {
  display: table-cell;
  vertical-align: middle;
}
h1 {
  background: url(file:///usr/share/software-center/images/spinner.gif) top \
center no-repeat;
  padding-top: 48px; /* leaves room for the spinner above */
  font-size: 100%%;
  font-weight: normal;
}
</style>
<body>
 <h1>%s</h1>
</body>
</html>
""" % _("Connecting to payment service...")

    __gsignals__ = {
        'purchase-succeeded': (GObject.SignalFlags.RUN_LAST, None, ()),
        'purchase-failed': (GObject.SignalFlags.RUN_LAST, None, ()),
        'purchase-cancelled-by-user': (GObject.SignalFlags.RUN_LAST, None, ()),
        'terms-of-service-declined': (GObject.SignalFlags.RUN_LAST, None, ()),
        'purchase-needs-spinner':
        (GObject.SignalFlags.RUN_LAST, None, (bool, )),
    }

    def __init__(self):
        GObject.GObject.__init__(self)
        self.wk = None
        self._wk_handlers_blocked = False
        self._oauth_token = None
        self.config = get_config()

    def init_view(self):
        if self.wk is None:
            self.wk = ScrolledWebkitWindow()
            # automatically fill in the email in the login page
            email = ""
            if self.config.has_option("general", "email"):
                email = self.config.get("general", "email")
            self.wk.webkit.set_auto_insert_email(email)
            #self.wk.webkit.connect("new-window-policy-decision-requested",
            #    self._on_new_window)
            self.wk.webkit.connect("create-web-view", self._on_create_web_view)
            self.wk.webkit.connect("close-web-view", self._on_close_web_view)
            self.wk.webkit.connect("console-message", self._on_console_message)

            # a possible way to do IPC (script or title change)
            self.wk.webkit.connect("script-alert", self._on_script_alert)
            self.wk.webkit.connect("title-changed", self._on_title_changed)
            self.wk.webkit.connect("notify::load-status",
                                   self._on_load_status_changed)
        # unblock signal handlers if needed when showing the purchase webkit
        # view in case they were blocked after a previous purchase was
        # completed or canceled
        self._unblock_wk_handlers()

    def _ask_for_tos_acceptance_if_needed(self):
        try:
            accepted_tos = self.config.getboolean("general", "accepted_tos")
        except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
            accepted_tos = False
        if not accepted_tos:
            # show the dialog and ensure the user accepts it
            res = show_accept_tos_dialog(get_parent(self))
            if not res:
                return False
            self.config.set("general", "accepted_tos", "yes")
            return True
        return True

    def initiate_purchase(self, app, iconname, url=None, html=None):
        """
        initiates the purchase workflow inside the embedded webkit window
        for the item specified
        """
        if not self._ask_for_tos_acceptance_if_needed():
            self.emit("terms-of-service-declined")
            return False

        self.init_view()
        self.app = app
        self.iconname = iconname
        self.wk.webkit.load_html_string(self.LOADING_HTML, "file:///")
        self.wk.show()
        while Gtk.events_pending():
            Gtk.main_iteration()
        if url:
            self.wk.webkit.load_uri(url)
        elif html:
            self.wk.webkit.load_html_string(html, "file:///")
        else:
            self.wk.webkit.load_html_string(DUMMY_HTML, "file:///")
        self.pack_start(self.wk, True, True, 0)
        # only for debugging
        if os.environ.get("SOFTWARE_CENTER_DEBUG_BUY"):
            GObject.timeout_add_seconds(1, _generate_events, self)
        return True

    def _on_new_window(self, view, frame, request, action, policy):
        LOG.debug("_on_new_window")
        import subprocess
        subprocess.Popen(['xdg-open', request.get_uri()])
        return True

    def _on_close_web_view(self, view):
        win = view.get_data("win")
        win.destroy()
        return True

    def _on_create_web_view(self, view, frame):
        win = Gtk.Window()
        win.set_size_request(400, 400)
        wk = ScrolledWebkitWindow(include_progress_ui=True)
        wk.webkit.connect("close-web-view", self._on_close_web_view)
        win.add(wk)
        win.show_all()
        # make sure close will work later
        wk.webkit.set_data("win", win)
        # find and set parent
        w = self.wk.get_parent()
        while w.get_parent():
            w = w.get_parent()
        win.set_transient_for(w)
        return wk.webkit

    def _on_console_message(self, view, message, line, source_id):
        try:
            # load the token from the console message
            self._oauth_token = json.loads(message)
            # compat with the regular oauth naming
            self._oauth_token["token"] = self._oauth_token["token_key"]
        except ValueError:
            pass
        for k in ["token_key", "token_secret", "consumer_secret"]:
            if k in message:
                LOG.debug(
                    "skipping console message that contains sensitive data")
                return True
        LOG.debug("_on_console_message '%s'" % message)
        return False

    def _on_script_alert(self, view, frame, message):
        self._process_json(message)
        # stop further processing to avoid actually showing the alter
        return True

    def _on_title_changed(self, view, frame, title):
        #print "on_title_changed", view, frame, title
        # see wkwidget.py _on_title_changed() for a code example
        self._process_json(title)

    def _on_load_status_changed(self, view, property_spec):
        """ helper to give visual feedback while the page is loading """
        prop = view.get_property(property_spec.name)
        window = self.get_window()
        if prop == webkit.LoadStatus.PROVISIONAL:
            self.emit("purchase-needs-spinner", True)
            if window:
                window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
        elif (prop == webkit.LoadStatus.FIRST_VISUALLY_NON_EMPTY_LAYOUT
              or prop == webkit.LoadStatus.FAILED
              or prop == webkit.LoadStatus.FINISHED):
            self.emit("purchase-needs-spinner", False)
            if window:
                window.set_cursor(None)

    def _process_json(self, json_string):
        try:
            LOG.debug("server returned: '%s'" % json_string)
            res = json.loads(json_string)
            #print res
        except:
            LOG.debug("error processing json: '%s'" % json_string)
            return
        if res["successful"] == False:
            if (res.get("user_canceled", False) or
                    # note the different spelling
                    res.get("user_cancelled", False) or
                    # COMPAT with older clients that do not send the user
                    #        canceled property (LP: #696861), this msg appears
                    #        to be not translated
                    "CANCELLED" in res.get("failures", "")):
                self.emit("purchase-cancelled-by-user")
                self._block_wk_handlers()
                return
            # this is what the agent implements
            elif "failures" in res:
                LOG.error("the server returned a error: '%s'" %
                          res["failures"])
            # show a generic error, the "failures" string we get from the
            # server is way too technical to show, but we do log it
            self.emit("purchase-failed")
            self._block_wk_handlers()
            return
        else:
            self.emit("purchase-succeeded")
            self._block_wk_handlers()
            # gather data from response
            deb_line = res["deb_line"]
            signing_key_id = res["signing_key_id"]
            license_key = res.get("license_key")
            license_key_path = res.get("license_key_path")
            # add repo and key
            backend = get_install_backend()
            backend.add_repo_add_key_and_install_app(
                deb_line, signing_key_id, self.app, self.iconname, license_key,
                license_key_path, json.dumps(self._oauth_token))

    def _block_wk_handlers(self):
        # we need to block webkit signal handlers when we hide the
        # purchase webkit view, this prevents e.g. handling of signals on
        # title_change on reloads (see LP: #696861)
        if not self._wk_handlers_blocked:
            self.wk.webkit.handler_block_by_func(self._on_script_alert)
            self.wk.webkit.handler_block_by_func(self._on_title_changed)
            self.wk.webkit.handler_block_by_func(self._on_load_status_changed)
            self._wk_handlers_blocked = True

    def _unblock_wk_handlers(self):
        if self._wk_handlers_blocked:
            self.wk.webkit.handler_unblock_by_func(self._on_script_alert)
            self.wk.webkit.handler_unblock_by_func(self._on_title_changed)
            self.wk.webkit.handler_unblock_by_func(
                self._on_load_status_changed)
            self._wk_handlers_blocked = False
Beispiel #7
0
class PurchaseView(Gtk.VBox):
    """
    View that displays the webkit-based UI for purchasing an item.
    """

    LOADING_HTML = """
<html>
<head>
 <title></title>
</head>
<style type="text/css">
html {
  background: #fff;
  color: #000;
  font: sans-serif;
  font: caption;
  text-align: center;
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%%;
  height: 100%%;
  display: table;
}
body {
  display: table-cell;
  vertical-align: middle;
}
h1 {
  background: url(file:///usr/share/software-center/images/spinner.gif) top \
center no-repeat;
  padding-top: 48px; /* leaves room for the spinner above */
  font-size: 100%%;
  font-weight: normal;
}
</style>
<body>
 <h1>%s</h1>
</body>
</html>
""" % _("Connecting to payment service...")

    __gsignals__ = {
         'purchase-succeeded': (GObject.SignalFlags.RUN_LAST,
                                None,
                                ()),
         'purchase-failed': (GObject.SignalFlags.RUN_LAST,
                             None,
                             ()),
         'purchase-cancelled-by-user': (GObject.SignalFlags.RUN_LAST,
                                        None,
                                        ()),
         'terms-of-service-declined': (GObject.SignalFlags.RUN_LAST,
                                       None,
                                       ()),
         'purchase-needs-spinner': (GObject.SignalFlags.RUN_LAST,
                                     None,
                                    (bool, )),

    }

    def __init__(self):
        GObject.GObject.__init__(self)
        self.wk = None
        self._wk_handlers_blocked = False
        self._oauth_token = None
        self.config = get_config()

    def init_view(self):
        if self.wk is None:
            self.wk = ScrolledWebkitWindow()
            #self.wk.webkit.connect("new-window-policy-decision-requested",
            #    self._on_new_window)
            self.wk.webkit.connect("create-web-view", self._on_create_web_view)
            self.wk.webkit.connect("close-web-view", self._on_close_web_view)
            self.wk.webkit.connect("console-message", self._on_console_message)

            # a possible way to do IPC (script or title change)
            self.wk.webkit.connect("script-alert", self._on_script_alert)
            self.wk.webkit.connect("title-changed", self._on_title_changed)
            self.wk.webkit.connect("notify::load-status",
                self._on_load_status_changed)
        # unblock signal handlers if needed when showing the purchase webkit
        # view in case they were blocked after a previous purchase was
        # completed or canceled
        self._unblock_wk_handlers()

    def _ask_for_tos_acceptance_if_needed(self):
        try:
            accepted_tos = self.config.getboolean("general", "accepted_tos")
        except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
            accepted_tos = False
        if not accepted_tos:
            # show the dialog and ensure the user accepts it
            res = show_accept_tos_dialog(get_parent(self))
            if not res:
                return False
            self.config.set("general", "accepted_tos", "yes")
            return True
        return True

    def initiate_purchase(self, app, iconname, url=None, html=None):
        """
        initiates the purchase workflow inside the embedded webkit window
        for the item specified
        """
        if not self._ask_for_tos_acceptance_if_needed():
            self.emit("terms-of-service-declined")
            return False

        self.init_view()
        self.app = app
        self.iconname = iconname
        self.wk.webkit.load_html_string(self.LOADING_HTML, "file:///")
        self.wk.show()
        while Gtk.events_pending():
            Gtk.main_iteration()
        if url:
            self.wk.webkit.load_uri(url)
        elif html:
            self.wk.webkit.load_html_string(html, "file:///")
        else:
            self.wk.webkit.load_html_string(DUMMY_HTML, "file:///")
        self.pack_start(self.wk, True, True, 0)
        # only for debugging
        if os.environ.get("SOFTWARE_CENTER_DEBUG_BUY"):
            GObject.timeout_add_seconds(1, _generate_events, self)
        return True

    def _on_new_window(self, view, frame, request, action, policy):
        LOG.debug("_on_new_window")
        import subprocess
        subprocess.Popen(['xdg-open', request.get_uri()])
        return True

    def _on_close_web_view(self, view):
        win = view.get_data("win")
        win.destroy()
        return True

    def _on_create_web_view(self, view, frame):
        win = Gtk.Window()
        win.set_size_request(400, 400)
        wk = ScrolledWebkitWindow(include_progress_ui=True)
        wk.webkit.connect("close-web-view", self._on_close_web_view)
        win.add(wk)
        win.show_all()
        # make sure close will work later
        wk.webkit.set_data("win", win)
        # find and set parent
        w = self.wk.get_parent()
        while w.get_parent():
            w = w.get_parent()
        win.set_transient_for(w)
        return wk.webkit

    def _on_console_message(self, view, message, line, source_id):
        try:
            # load the token from the console message
            self._oauth_token = json.loads(message)
            # compat with the regular oauth naming
            self._oauth_token["token"] = self._oauth_token["token_key"]
        except ValueError:
            pass
        for k in ["token_key", "token_secret", "consumer_secret"]:
            if k in message:
                LOG.debug(
                    "skipping console message that contains sensitive data")
                return True
        LOG.debug("_on_console_message '%s'" % message)
        return False

    def _on_script_alert(self, view, frame, message):
        self._process_json(message)
        # stop further processing to avoid actually showing the alter
        return True

    def _on_title_changed(self, view, frame, title):
        #print "on_title_changed", view, frame, title
        # see wkwidget.py _on_title_changed() for a code example
        self._process_json(title)

    def _on_load_status_changed(self, view, property_spec):
        """ helper to give visual feedback while the page is loading """
        prop = view.get_property(property_spec.name)
        window = self.get_window()
        if prop == webkit.LoadStatus.PROVISIONAL:
            self.emit("purchase-needs-spinner", True)
            if window:
                window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
        elif (prop == webkit.LoadStatus.FIRST_VISUALLY_NON_EMPTY_LAYOUT or
              prop == webkit.LoadStatus.FAILED or
              prop == webkit.LoadStatus.FINISHED):
            self.emit("purchase-needs-spinner", False)
            if window:
                window.set_cursor(None)

    def _process_json(self, json_string):
        try:
            LOG.debug("server returned: '%s'" % json_string)
            res = json.loads(json_string)
            #print res
        except:
            LOG.debug("error processing json: '%s'" % json_string)
            return
        if res["successful"] == False:
            if (res.get("user_canceled", False) or
                # note the different spelling
                res.get("user_cancelled", False) or
                # COMPAT with older clients that do not send the user
                #        canceled property (LP: #696861), this msg appears
                #        to be not translated
                "CANCELLED" in res.get("failures", "")):
                self.emit("purchase-cancelled-by-user")
                self._block_wk_handlers()
                return
            # this is what the agent implements
            elif "failures" in res:
                LOG.error("the server returned a error: '%s'" %
                    res["failures"])
            # show a generic error, the "failures" string we get from the
            # server is way too technical to show, but we do log it
            self.emit("purchase-failed")
            self._block_wk_handlers()
            return
        else:
            self.emit("purchase-succeeded")
            self._block_wk_handlers()
            # gather data from response
            deb_line = res["deb_line"]
            signing_key_id = res["signing_key_id"]
            license_key = res.get("license_key")
            license_key_path = res.get("license_key_path")
            # add repo and key
            backend = get_install_backend()
            backend.add_repo_add_key_and_install_app(
                deb_line, signing_key_id, self.app, self.iconname,
                license_key, license_key_path, json.dumps(self._oauth_token))

    def _block_wk_handlers(self):
        # we need to block webkit signal handlers when we hide the
        # purchase webkit view, this prevents e.g. handling of signals on
        # title_change on reloads (see LP: #696861)
        if not self._wk_handlers_blocked:
            self.wk.webkit.handler_block_by_func(self._on_script_alert)
            self.wk.webkit.handler_block_by_func(self._on_title_changed)
            self.wk.webkit.handler_block_by_func(self._on_load_status_changed)
            self._wk_handlers_blocked = True

    def _unblock_wk_handlers(self):
        if self._wk_handlers_blocked:
            self.wk.webkit.handler_unblock_by_func(self._on_script_alert)
            self.wk.webkit.handler_unblock_by_func(self._on_title_changed)
            self.wk.webkit.handler_unblock_by_func(
                self._on_load_status_changed)
            self._wk_handlers_blocked = False