예제 #1
0
 def __on_signal(self, connection, sender, path, interface, signal, params):
     """
         Add video to download manager
         @param connection as Gio.DBusConnection
         @param sender as str
         @param path as str
         @param interface as str
         @param signal as str
         @param parameters as GLib.Variant
     """
     if signal == "VideoInPage":
         uri = params[0]
         title = params[1]
         page_id = params[2]
         El().download_manager.add_video(uri, title, page_id)
     elif signal == "UnsecureFormFocused":
         self._window.toolbar.title.show_input_warning(self)
     elif signal == "InputMouseDown":
         if self.__last_click_event:
             model = FormMenu(params[0], self.get_page_id())
             popover = Gtk.Popover.new_from_model(self, model)
             popover.set_modal(False)
             self._window.register(popover)
             rect = Gdk.Rectangle()
             rect.x = self.__last_click_event["x"]
             rect.y = self.__last_click_event["y"] - 10
             rect.width = rect.height = 1
             popover.set_pointing_to(rect)
             helper = PasswordsHelper()
             helper.get(self.get_uri(), self.__on_password, popover, model)
예제 #2
0
 def __init__(self, extension, page, form_extension, jsblock_extension):
     """
         Init server
         @param extension as WebKit2WebExtension.WebExtension
         @param page as WebKit2WebExtension.WebPage
         @param form_extension as FormsExtension
         @param jsblock_extension as JSBlockExtension
     """
     self.__extension = extension
     self.__page = page
     self.__form_extension = form_extension
     self.__jsblock_extension = jsblock_extension
     self.__focused = None
     self.__on_input_timeout_id = None
     self.__elements_history = {}
     self.__send_requests = []
     self.__helper = PasswordsHelper()
     self.__proxy_bus = PROXY_BUS % self.__page.get_id()
     addr = Gio.dbus_address_get_for_bus_sync(Gio.BusType.SESSION, None)
     self.__bus = None
     Gio.DBusConnection.new_for_address(
                            addr,
                            Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT |
                            Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
                            None,
                            None,
                            self.__on_bus_new_for_address)
     form_extension.connect("submit-form", self.__on_submit_form)
     page.connect("send-request", self.__on_send_request)
     page.connect("context-menu", self.__on_context_menu)
     page.connect("notify::uri", self.__on_notify_uri)
     page.connect("form-controls-associated",
                  self.__on_form_control_associated)
예제 #3
0
 def __init__(self):
     """
         Init worker
     """
     self.__syncing = False
     self.__sync_cancellable = Gio.Cancellable()
     self.__username = ""
     self.__password = ""
     self.__token = ""
     self.__uid = ""
     self.__keyB = b""
     self.__mtimes = {"bookmarks": 0.1, "history": 0.1, "passwords": 0.1}
     # We do not create this here because it's slow down Eolie startup
     # See __firefox_sync property
     self.__mz = None
     self.__state_lock = True
     self.__session = None
     try:
         self.__pending_records = load(
             open(EOLIE_DATA_PATH + "/firefox_sync_pendings.bin", "rb"))
     except:
         self.__pending_records = {
             "history": [],
             "passwords": [],
             "bookmarks": []
         }
     self.__helper = PasswordsHelper()
     self.set_credentials()
예제 #4
0
 def __init__(self, username, userform, password, passform, uri, window):
     """
         Init popover
         @param username as str
         @param password as str
         @param netloc as str
         @param window as Window
     """
     Gtk.Popover.__init__(self)
     self.set_modal(False)
     window.register(self)
     self.__helper = PasswordsHelper()
     self.__username = username
     self.__userform = userform
     self.__password = password
     self.__passform = passform
     self.__uri = uri
     self.__uuid = None
     builder = Gtk.Builder()
     builder.add_from_resource('/org/gnome/Eolie/PopoverCredentials.ui')
     builder.connect_signals(self)
     self.__label = builder.get_object('label')
     parsed = urlparse(uri)
     builder.get_object('uri').set_text(parsed.netloc)
     builder.get_object('username').set_text(username)
     builder.get_object('password').set_text(password)
     self.add(builder.get_object('widget'))
예제 #5
0
파일: toolbar_end.py 프로젝트: bagage/eolie
 def _on_sync_button_clicked(self, button):
     """
         Start sync
         @param button as Gtk.Button
     """
     helper = PasswordsHelper()
     helper.get_sync(self.__on_get_sync)
     button.hide()
예제 #6
0
 def __init__(self, extension, settings):
     """
         Connect wanted signal
         @param extension as WebKit2WebExtension
         @param settings as Settings
     """
     self.__helper = PasswordsHelper()
     self.__settings = settings
     extension.connect("page-created", self.__on_page_created)
예제 #7
0
 def __init__(self, extension):
     """
         Connect wanted signal
         @param extension as WebKit2WebExtension
     """
     GObject.Object.__init__(self)
     self.__helper = PasswordsHelper()
     self.__extension = extension
     self.__elements_uri = None
     self.__pending_credentials = None
     self.__page_id = None
     extension.connect("page-created", self.__on_page_created)
예제 #8
0
 def __init__(self):
     """
         Init worker
     """
     GObject.GObject.__init__(self)
     self.__stop = True
     self.__username = ""
     self.__password = ""
     self.__mtimes = {"bookmarks": 0.1, "history": 0.1}
     self.__mozilla_sync = MozillaSync()
     self.__session = None
     self.__helper = PasswordsHelper()
예제 #9
0
 def __on_save_credentials(self, source, result, form_uri,
                           user_form_name, pass_form_name):
     """
         Get password and push credential to sync
         @param source as GObject.Object
         @param result as Gio.AsyncResult
         @param form_uri as str
         @param user_form_name as str
         @param pass_form_name as str
     """
     helper = PasswordsHelper()
     helper.get(form_uri, user_form_name,
                pass_form_name, self.__on_get_password)
예제 #10
0
 def __init__(self):
     """
         Init worker
     """
     self.__syncing = False
     self.__sync_cancellable = Gio.Cancellable()
     self.__username = ""
     self.__password = ""
     self.__mtimes = {"bookmarks": 0.1, "history": 0.1}
     self.__mozilla_sync = None
     self.__state_lock = True
     self.__session = None
     self.__helper = PasswordsHelper()
     self.__helper.get_sync(self.__set_credentials)
예제 #11
0
 def __init__(self):
     """
         Init popover
     """
     Gtk.Popover.__init__(self)
     self.__filter = ""
     self.__helper = PasswordsHelper()
     self.set_position(Gtk.PositionType.BOTTOM)
     builder = Gtk.Builder()
     builder.add_from_resource('/org/gnome/Eolie/PopoverPasswords.ui')
     builder.connect_signals(self)
     self.__listbox = builder.get_object("listbox")
     self.__listbox.set_filter_func(self.__filter_func)
     self.add(builder.get_object('widget'))
     self.set_size_request(300, 300)
예제 #12
0
 def SetAuthForms(self, username, page_id):
     """
         Get password forms for page id
         @param username as str
         @param page id as int
     """
     try:
         page = self.__extension.get_page(page_id)
         if page is None:
             return
         helper = PasswordsHelper()
         helper.get(page.get_uri(), self.__forms.set_input_forms, page,
                    username)
     except Exception as e:
         print("ProxyExtension::SetAuthForms():", e)
예제 #13
0
 def __init__(self, uuid, user_form_name, user_form_value, pass_form_name,
              uri, form_uri, page_id, window):
     """
         Init popover
         @param uuid as str
         @param user_form_name as str
         @param user_form_value as str
         @param pass_form_name as str
         @param uri as str
         @param form_uri as str
         @param page_id as int
         @param window as Window
     """
     Gtk.Popover.__init__(self)
     self.set_modal(False)
     window.register(self)
     self.__helper = PasswordsHelper()
     self.__user_form_name = user_form_name
     self.__user_form_value = user_form_value
     self.__pass_form_name = pass_form_name
     self.__uri = uri
     self.__form_uri = form_uri
     self.__uuid = uuid
     self.__page_id = page_id
     builder = Gtk.Builder()
     builder.add_from_resource('/org/gnome/Eolie/PopoverCredentials.ui')
     builder.connect_signals(self)
     self.__label = builder.get_object('label')
     parsed = urlparse(uri)
     builder.get_object('uri').set_text(parsed.netloc)
     if uuid:
         self.__label.set_text(_("Do you want to modify this password?"))
     self.add(builder.get_object('widget'))
예제 #14
0
 def __init__(self):
     """
         Init worker
     """
     self.__syncing = False
     self.__sync_cancellable = Gio.Cancellable()
     self.__username = ""
     self.__password = ""
     self.__token = ""
     self.__uid = ""
     self.__keyB = b""
     self.__mtimes = {"bookmarks": 0.1, "history": 0.1}
     # We do not create this here because it's slow down Eolie startup
     # See __mozilla_sync property
     self.__mz = None
     self.__state_lock = True
     self.__session = None
     self.__helper = PasswordsHelper()
     self.set_credentials()
예제 #15
0
 def __on_signal(self, signal, params):
     """
         Handle proxy signals
         @param signal as str
         @params as []
     """
     if signal == "UnsecureFormFocused":
         self._window.toolbar.title.show_input_warning(self)
     elif signal == "AskSaveCredentials":
         (uuid, user_form_name, user_form_value, pass_form_name, uri,
          form_uri) = params[0]
         self._window.close_popovers()
         self._window.toolbar.title.show_password(uuid, user_form_name,
                                                  user_form_value,
                                                  pass_form_name, uri,
                                                  form_uri,
                                                  self.get_page_id())
     elif signal == "ShowCredentials":
         (userform, form_uri) = params
         model = FormMenu(self.get_page_id(), self._window)
         helper = PasswordsHelper()
         helper.get(form_uri, userform, None, self.__on_password, model)
예제 #16
0
class FormsExtension:
    """
        Handle forms prefill
    """
    def __init__(self, extension, settings):
        """
            Connect wanted signal
            @param extension as WebKit2WebExtension
            @param settings as Settings
        """
        self.__helper = PasswordsHelper()
        self.__settings = settings
        extension.connect("page-created", self.__on_page_created)

    def has_password(self, webpage):
        """
            True if webpage has a password input
        """
        dom_document = webpage.get_dom_document()
        inputs = dom_document.get_elements_by_tag_name("input")
        i = 0
        while i < inputs.get_length():
            if inputs.item(i).get_input_type() == "password":
                return True
            i += 1
        return False

    def get_input_forms(self, webpage):
        """
            Return forms for webpage
            @param webpage as WebKit2WebExtension.WebPage
            @return [WebKit2WebExtension.DOMHTMLInputElement]
        """
        forms = []
        dom_document = webpage.get_dom_document()
        inputs = dom_document.get_elements_by_tag_name("input")
        i = 0
        while i < inputs.get_length():
            if inputs.item(i).get_input_type() in ["text", "search"]:
                forms.append(inputs.item(i))
            i += 1
        return forms

    def get_textarea_forms(self, webpage):
        """
            Return forms for webpage
            @param webpage as WebKit2WebExtension.WebPage
            @return [WebKit2WebExtension.DOMHTMLInputElement]
        """
        forms = []
        dom_document = webpage.get_dom_document()
        textareas = dom_document.get_elements_by_tag_name("textarea")
        i = 0
        while i < textareas.get_length():
            forms.append(textareas.item(i))
            i += 1
        return forms

    def get_password_forms(self, name, webpage):
        """
            Return forms for webpage
            @param name as str
            @param webpage as WebKit2WebExtension.WebPage
            @return [WebKit2WebExtension.DOMHTMLInputElement]
        """
        forms = []
        dom_document = webpage.get_dom_document()
        inputs = dom_document.get_elements_by_tag_name("input")
        i = 0
        while i < inputs.get_length():
            if inputs.item(i).get_input_type() == "password" and\
                    (not name or name == inputs.item(i).get_attribute("name")):
                forms.append(inputs.item(i))
            i += 1
        return forms

    def get_login_forms(self, name, webpage):
        """
            Return auth forms for webpage
            @param name as str
            @param webpage as WebKit2WebExtension.WebPage
            @return [WebKit2WebExtension.DOMHTMLInputElement]
        """
        dom_document = webpage.get_dom_document()
        inputs = dom_document.get_elements_by_tag_name("input")
        i = 0
        forms = []
        while i < inputs.get_length():
            if inputs.item(i).get_input_type() == "text":
                input_name = inputs.item(i).get_attribute("name")
                input_id = inputs.item(i).get_attribute("id")
                # We search for wanted name
                if name and (name == input_name or name == input_id):
                    forms.append(inputs.item(i))
                else:
                    if self.is_login_form(inputs.item(i)):
                        forms.append(inputs.item(i))
            i += 1
        return forms

    def set_input_forms(self,
                        attributes,
                        password,
                        uri,
                        index,
                        count,
                        webpage,
                        username=None):
        """
            Set username/password input
            @param attributes as {}
            @param password as str
            @param uri as str
            @param index as int
            @param count as int
            @param webpage as WebKit2WebExtension.WebPage
            @param username as str/None
        """
        # We only set first available password
        if index != 0 and username is None:
            return
        parsed = urlparse(uri)
        # Allow unsecure completion if wanted by user
        if parsed.scheme != "https" and username is None:
            return
        submit_uri = "%s://%s" % (parsed.scheme, parsed.netloc)
        # Do not set anything if no attributes or
        # If we have already text in input and we are not a perfect completion
        if attributes is None or\
                (username is not None and attributes["login"] != username) or\
                attributes["formSubmitURL"] != submit_uri:
            return
        try:
            usernames = self.get_login_forms(attributes["userform"], webpage)
            passwords = self.get_password_forms(attributes["passform"],
                                                webpage)
            # Passwords form may have changed, take first
            if not passwords:
                passwords = self.get_password_forms("", webpage)
            if usernames and passwords:
                usernames[0].set_value(attributes["login"])
                passwords[0].set_value(password)
        except Exception as e:
            print("FormsExtension::set_input_forms()", e)

    def is_login_form(self, form):
        """
            Return True if form is a login form
            @param form as WebKit2WebExtension.DOMHTMLInputElement
            @return bool
        """
        input_name = form.get_attribute("name")
        input_id = form.get_attribute("id")
        # We search for common name
        for search in LOGINS:
            if (input_name is not None and
                    input_name.lower().find(search) != -1) or\
                    (input_id is not None and
                        input_id.lower().find(search) != -1):
                return True
        return False

#######################
# PRIVATE             #
#######################

    def __on_page_created(self, extension, webpage):
        """
            Connect to send request
            @param extension as WebKit2WebExtension
            @param webpage as WebKit2WebExtension.WebPage
        """
        webpage.connect("document-loaded", self.__on_document_loaded)

    def __on_document_loaded(self, webpage):
        """
            Restore forms
            @param webpage as WebKit2WebExtension.WebPage
        """
        if not self.__settings.get_value("remember-passwords"):
            return
        if self.has_password(webpage):
            self.__helper.get(webpage.get_uri(), self.set_input_forms, webpage)
예제 #17
0
class FormsExtension(GObject.Object):
    """
        Handle forms prefill
    """

    __gsignals__ = {
        'submit-form': (GObject.SignalFlags.RUN_FIRST, None, (GLib.Variant, ))
    }

    def __init__(self, extension):
        """
            Connect wanted signal
            @param extension as WebKit2WebExtension
        """
        GObject.Object.__init__(self)
        self.__helper = PasswordsHelper()
        self.__extension = extension
        self.__elements_uri = None
        self.__pending_credentials = None
        self.__page_id = None
        extension.connect("page-created", self.__on_page_created)

    def set_credentials(self, form, webpage):
        """
            Set credentials on page
            @param form as {
                           "element":WebKit2WebExtension.DOMHTMLFormElement,
                           "username": WebKit2WebExtension.DOMHTMLInputElement,
                           "password": WebKit2WebExtension.DOMHTMLInputElement}
            @param webpage as WebKit2WebExtension.WebPage
        """
        if App().settings.get_value("remember-passwords"):
            form_input_username = form["username"].get_name()
            form_input_password = form["password"].get_name()
            if form_input_username is not None and\
                    form_input_password is not None:
                self.__helper.get(self.get_form_uri(form["element"]),
                                  form_input_username, form_input_password,
                                  self.set_input_forms, webpage, form)

    def set_input_forms(self,
                        attributes,
                        password,
                        uri,
                        index,
                        count,
                        webpage,
                        form,
                        username=None):
        """
            Set login/password input
            @param attributes as {}
            @param password as str
            @param uri as str
            @param index as int
            @param count as int
            @param webpage as WebKit2WebExtension.WebPage
            @param form as {
                           "element":WebKit2WebExtension.DOMHTMLFormElement,
                           "username": WebKit2WebExtension.DOMHTMLInputElement,
                           "password": WebKit2WebExtension.DOMHTMLInputElement}
            @param username as str
        """
        if attributes is None:
            return
        # We only set first available password
        if (index != 0 or count > 1) and username is None:
            return
        parsed = urlparse(self.get_form_uri(form["element"]))
        # Allow unsecure completion if wanted by user
        if parsed.scheme != "https" and username is None:
            return
        # We want a user, check if it wanted password
        if username is not None and username != attributes["login"]:
            return
        try:
            form["username"].set_value(attributes["login"])
            form["password"].set_value(password)
        except Exception as e:
            Logger.error("FormsExtension::set_input_forms(): %s", e)

    def get_elements(self, elements):
        """
            Get forms as dict and textareas for elements
            @param elements as [WebKit2WebExtension.DOMElement]
            @return elements as
                ([{"element":WebKit2WebExtension.DOMHTMLFormElement,
                   "username": WebKit2WebExtension.DOMHTMLInputElement,
                   "password": WebKit2WebExtension.DOMHTMLInputElement}],
                 [WebKit2WebExtension.DOMHTMLTextAreaElement])
        """
        forms = []
        textareas = []
        for element in elements:
            if isinstance(element, WebKit2WebExtension.DOMHTMLTextAreaElement):
                textareas.append(element)
            elif isinstance(element, WebKit2WebExtension.DOMHTMLFormElement):
                form = {"element": element}
                elements_collection = element.get_elements()
                h = 0
                while h < elements_collection.get_length():
                    element = elements_collection.item(h)
                    # Ignore hidden elements
                    if element.get_client_top() == 0:
                        h += 1
                        continue
                    if isinstance(element,
                                  WebKit2WebExtension.DOMHTMLInputElement):
                        if element.get_input_type() == "password" and\
                                element.get_name() is not None:
                            form["password"] = element
                        elif element.get_input_type() in ["text",
                                                          "email",
                                                          "search"] and\
                                element.get_name() is not None:
                            form["username"] = element
                    elif isinstance(
                            element,
                            WebKit2WebExtension.DOMHTMLTextAreaElement):
                        textareas.append(element)
                    h += 1
                keys = form.keys()
                if "username" in keys and "password" in keys:
                    forms.append(form)
        return (forms, textareas)

    def get_hostname_uri(self, page):
        """
            Get form uri for page
            @param page as WebKit2WebExtension.WebPage
            @return str
            @raise Exception
        """
        page = self.__extension.get_page(self.__page_id)
        if page is None:
            raise Exception("Can't find page!")
        uri = page.get_uri()
        parsed = urlparse(uri)
        return "%s://%s" % (parsed.scheme, parsed.netloc)

    def get_form_uri(self, form):
        """
            Get form uri for form
            @param form as WebKit2WebExtension.DOMHTMLFormElement
            @return str
        """
        form_uri = form.get_action()
        if form_uri is None:
            page = self.__extension.get_page(self.__page_id)
            return self.get_hostname_uri(page)
        else:
            parsed_form_uri = urlparse(form_uri)
            return "%s://%s" % (parsed_form_uri.scheme, parsed_form_uri.netloc)

    @property
    def pending_credentials(self):
        """
            Get credentials
            @return (str, str, str, str, str, str)/None/Type.NONE
        """
        return self.__pending_credentials

#######################
# PRIVATE             #
#######################

    def __on_get_password(self, attributes, password, form_uri, index, count,
                          user_form_name, user_form_value, pass_form_name,
                          pass_form_value, hostname_uri, page_id):
        """
            Ask for credentials through DBus
            @param attributes as {}
            @param password as str
            @param form_uri as str
            @param index as int
            @param count as int
            @param user_form_name as str
            @param user_form_value as str
            @param pass_form_name as str
            @param pass_form_value as str
            @param hostname_uri as str
            @param page_id as int
        """
        try:
            # If credentials not found (!=Type.NONE) and something new
            # is submitted
            if self.__pending_credentials != Type.NONE and (
                    attributes is None
                    or attributes["login"] != user_form_value
                    or password != pass_form_value):
                if attributes is None or\
                        attributes["login"] != user_form_value:
                    uuid = ""
                else:
                    uuid = attributes["uuid"]
                self.__pending_credentials = (uuid, user_form_name,
                                              user_form_value, pass_form_name,
                                              pass_form_value, hostname_uri,
                                              form_uri)
            else:
                # Found, no more lookup
                self.__pending_credentials = Type.NONE
            # Last found credentials
            if count < 1 or index == count - 1:
                # Reset pending
                if self.__pending_credentials == Type.NONE:
                    self.__pending_credentials = None
                # Ask for user input
                elif self.__pending_credentials not in [None, Type.NONE]:
                    (uuid, user_form_name, user_form_value, pass_form_name,
                     pass_form_value, hostname_uri,
                     form_uri) = self.__pending_credentials
                    args = (uuid, user_form_name, user_form_value,
                            pass_form_name, hostname_uri, form_uri)
                    variant = GLib.Variant.new_tuple(
                        GLib.Variant("(ssssss)", args))
                    self.emit("submit-form", variant)
        except Exception as e:
            Logger.error("FormsExtension::__on_get_password(): %s", e)

    def __on_will_submit_form(self, webpage, form, step, source, target, names,
                              values):
        """
            @param webpage as WebKit2WebExtension.WebPage
            @param form as WebKit2WebExtension.DOMHTMLFormElement
            @param step as WebKit2WebExtension.FormSubmissionStep
            @param source as WebKit2WebExtension.Frame
            @param target as WebKit2WebExtension.Frame
            @param names as [str]
            @param values as [str]
        """
        if step != WebKit2WebExtension.FormSubmissionStep.SEND_DOM_EVENT or\
                not names or not values:
            return
        try:
            # Check elements
            document = webpage.get_dom_document()
            username_idx = None
            password_idx = None
            idx = 0
            for name in names:
                if username_idx is not None and password_idx is not None:
                    break
                elements = document.get_elements_by_name(name)
                for elements_idx in range(0, elements.get_length()):
                    element = elements.item(elements_idx)
                    if isinstance(element,
                                  WebKit2WebExtension.DOMHTMLInputElement):
                        if element.get_input_type() == "password" and\
                                element.get_name() is not None:
                            password_idx = idx
                            break
                        elif element.get_input_type() in ["text",
                                                          "email",
                                                          "search"] and\
                                element.get_name() is not None:
                            username_idx = idx
                            break
                idx += 1
            if username_idx is not None and password_idx is not None:
                hostname_uri = self.get_hostname_uri(webpage)
                form_uri = self.get_form_uri(form)
                user_form_name = names[username_idx]
                user_form_value = values[username_idx]
                pass_form_name = names[password_idx]
                pass_form_value = values[password_idx]
                self.__helper.get(form_uri, user_form_name, pass_form_name,
                                  self.__on_get_password, user_form_name,
                                  user_form_value, pass_form_name,
                                  pass_form_value, hostname_uri,
                                  self.__page_id)
        except Exception as e:
            print("FormsExtension::__on_will_submit_form():", e)

    def __on_page_created(self, extension, webpage):
        """
            Connect to send request
            @param extension as WebKit2WebExtension
            @param webpage as WebKit2WebExtension.WebPage
        """
        self.__page_id = webpage.get_id()
        webpage.connect("will-submit-form", self.__on_will_submit_form)
예제 #18
0
class PasswordsPopover(Gtk.Popover):
    """
        Show saved passwords
    """
    def __init__(self):
        """
            Init popover
        """
        Gtk.Popover.__init__(self)
        self.__filter = ""
        self.__helper = PasswordsHelper()
        self.set_position(Gtk.PositionType.BOTTOM)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/PopoverPasswords.ui')
        builder.connect_signals(self)
        self.__listbox = builder.get_object("listbox")
        self.__listbox.set_filter_func(self.__filter_func)
        self.__listbox.set_sort_func(self.__sort_func)
        self.add(builder.get_object('widget'))
        self.set_size_request(400, 300)

    def populate(self):
        """
            Populate popover
        """
        self.__helper.get_all(self.__add_password)

#######################
# PROTECTED           #
#######################

    def _on_search_changed(self, entry):
        """
            Update filter
            @param entry as Gtk.Entry
        """
        self.__filter = entry.get_text()
        self.__listbox.invalidate_filter()

    def _on_remove_all_clicked(self, button):
        """
            Remove all passwords
            @param button as Gtk.Button
        """
        for child in self.__listbox.get_children():
            child.delete()

#######################
# PRIVATE             #
#######################

    def __filter_func(self, row):
        """
            Filter rows
            @param row as Row
        """
        return self.__filter in row.item.get_property("uri")

    def __sort_func(self, row1, row2):
        """
            Sort rows
            @param row1 as Row
            @param row2 as Row
        """
        return row2.item.get_property("username") <\
            row1.item.get_property("username")

    def __add_password(self, attributes, password, uri, index, count):
        """
            Add password to model
            @param attributes as {}
            @param password as str
            @param uri as None
            @param index as int
            @param count as int
        """
        if attributes is None:
            return
        try:
            item = Item()
            item.set_property("username", attributes["login"])
            item.set_property("uri", attributes["formSubmitURL"])
            item.set_property("uuid", attributes["uuid"])
            child = Row(item, self.__helper)
            child.show()
            self.__listbox.add(child)
        except:
            # Here because firsts Eolie releases do not
            # provide formSubmitURL
            # FIXME Remove later
            pass
예제 #19
0
class FormsExtension:
    """
        Handle forms prefill
    """

    def __init__(self, extension, settings):
        """
            Connect wanted signal
            @param extension as WebKit2WebExtension
            @param settings as Settings
        """
        self.__helper = PasswordsHelper()
        self.__settings = settings
        self.__input_logins = []
        self.__input_passwords = []
        extension.connect("page-created", self.__on_page_created)

    def set_credentials(self, webpage):
        """
            Set credentials on page
            @param webpage as WebKit2WebExtension.WebPage
        """
        forms = self.update_inputs_list(webpage)
        for form in forms:
            self.__helper.get(form.get_action(),
                              self.set_input_forms,
                              webpage)

    def get_input_forms(self, webpage):
        """
            Return forms for webpage
            @param webpage as WebKit2WebExtension.WebPage
            @return [WebKit2WebExtension.DOMHTMLInputElement]
        """
        forms = []
        dom_document = webpage.get_dom_document()
        inputs = dom_document.get_elements_by_tag_name("input")
        i = 0
        while i < inputs.get_length():
            if inputs.item(i).get_input_type() in ["text", "email", "search"]:
                forms.append(inputs.item(i))
            i += 1
        return forms

    def get_textarea_forms(self, webpage):
        """
            Return forms for webpage
            @param webpage as WebKit2WebExtension.WebPage
            @return [WebKit2WebExtension.DOMHTMLInputElement]
        """
        forms = []
        dom_document = webpage.get_dom_document()
        textareas = dom_document.get_elements_by_tag_name("textarea")
        i = 0
        while i < textareas.get_length():
            forms.append(textareas.item(i))
            i += 1
        return forms

    def get_password_inputs(self, webpage):
        """
            Return password inputs
            @param webpage as WebKit2WebExtension.WebPage
            @return [WebKit2WebExtension.DOMHTMLInputElement]
        """
        return self.__input_passwords

    def is_password_input(self, name, webpage):
        """
            Return True if a password input
            @param name as str
            @param webpage as WebKit2WebExtension.WebPage
            @return WebKit2WebExtension.DOMHTMLInputElement/None
        """
        for input_password in self.__input_passwords:
            input_name = input_password.get_attribute("name")
            input_id = input_password.get_attribute("id")
            # We search for wanted name
            if name and (name == input_name or name == input_id):
                return True
        return False

    def set_input_forms(self, attributes, password,
                        uri, index, count, webpage, login=None):
        """
            Set login/password input
            @param attributes as {}
            @param password as str
            @param uri as str
            @param index as int
            @param count as int
            @param webpage as WebKit2WebExtension.WebPage
            @param login as str/None
        """
        # We only set first available password
        if (index != 0 or count > 1) and login is None:
            return
        parsed = urlparse(uri)
        # Allow unsecure completion if wanted by user
        if parsed.scheme != "https" and login is None:
            return
        submit_uri = "%s://%s" % (parsed.scheme, parsed.netloc)
        # Do not set anything if no attributes or
        # If we have already text in input
        if attributes is None or\
                (login is not None and attributes["login"] != login) or\
                attributes["formSubmitURL"] != submit_uri:
            return
        try:
            wanted_input_login = None
            name = attributes["userform"]
            for input_login in self.__input_logins:
                input_name = input_login.get_attribute("name")
                input_id = input_login.get_attribute("id")
                # We search for wanted name
                if name and (name == input_name or name == input_id):
                    wanted_input_login = input_login
                    break
            if wanted_input_login is None:
                return
            wanted_input_password = None
            name = attributes["passform"]
            for input_password in self.__input_passwords:
                input_name = input_password.get_attribute("name")
                input_id = input_password.get_attribute("id")
                if not name or name == input_name or name == input_id:
                    wanted_input_password = input_password
                    break
            if wanted_input_password is None:
                return
            wanted_input_login.set_value(attributes["login"])
            wanted_input_password.set_value(password)
        except Exception as e:
            print("FormsExtension::set_input_forms()", e)

    def is_login_form(self, form):
        """
            Return True if form is a login form
            @param form as WebKit2WebExtension.DOMHTMLInputElement
            @return bool
        """
        input_name = form.get_attribute("name")
        input_id = form.get_attribute("id")
        # We search for common name
        for search in LOGINS:
            if (input_name is not None and
                    input_name.lower().find(search) != -1) or\
                    (input_id is not None and
                        input_id.lower().find(search) != -1):
                return True
        return False

    def update_inputs_list(self, webpage):
        """
            Update login and password inputs
            @param webpage as WebKit2WebExtension.WebPage
            @return forms with a password input
        """
        self.__input_logins = []
        self.__input_passwords = []
        forms = []
        collection = webpage.get_dom_document().get_forms()
        i = 0
        while i < collection.get_length():
            form = collection.item(i)
            if form.get_method() == "post":
                elements_collection = form.get_elements()
                h = 0
                while h < elements_collection.get_length():
                    element = elements_collection.item(h)
                    if not isinstance(element,
                                      WebKit2WebExtension.DOMHTMLInputElement):
                        h += 1
                        continue
                    if element.get_input_type() == "password":
                        self.__input_passwords.append(element)
                        if form not in forms:
                            forms.append(form)
                    elif element.get_input_type() in ["text",
                                                      "email",
                                                      "search"]:
                        self.__input_logins.append(element)
                    h += 1
            i += 1
        return forms

#######################
# PRIVATE             #
#######################
    def __on_page_created(self, extension, webpage):
        """
            Connect to send request
            @param extension as WebKit2WebExtension
            @param webpage as WebKit2WebExtension.WebPage
        """
        webpage.connect("document-loaded", self.__on_document_loaded)

    def __on_document_loaded(self, webpage):
        """
            Restore forms
            @param webpage as WebKit2WebExtension.WebPage
        """
        if not self.__settings.get_value("remember-passwords"):
            return
        self.set_credentials(webpage)
예제 #20
0
class FormsExtension(GObject.Object):
    """
        Handle forms prefill
    """

    __gsignals__ = {
        'submit-form': (GObject.SignalFlags.RUN_FIRST, None, (GLib.Variant, ))
    }

    def __init__(self, extension, settings):
        """
            Connect wanted signal
            @param extension as WebKit2WebExtension
            @param settings as Settings
        """
        GObject.Object.__init__(self)
        self.__helper = PasswordsHelper()
        self.__extension = extension
        self.__settings = settings
        self.__elements_uri = None
        self.__pending_credentials = None
        self.__page_id = None
        extension.connect("page-created", self.__on_page_created)

    def set_credentials(self, form, webpage):
        """
            Set credentials on page
            @param form as {}
            @param webpage as WebKit2WebExtension.WebPage
        """
        if self.__settings.get_value("remember-passwords"):
            form_input_username = form["username"].get_name()
            form_input_password = form["password"].get_name()
            if form_input_username is not None and\
                    form_input_password is not None:
                self.__helper.get(form["element"].get_action(),
                                  form_input_username, form_input_password,
                                  self.set_input_forms, webpage, form)

    def set_input_forms(self,
                        attributes,
                        password,
                        uri,
                        index,
                        count,
                        webpage,
                        form,
                        username=None):
        """
            Set login/password input
            @param attributes as {}
            @param password as str
            @param uri as str
            @param index as int
            @param count as int
            @param webpage as WebKit2WebExtension.WebPage
            @param form as {}
            @param username as str
        """
        if attributes is None:
            return
        # We only set first available password
        if (index != 0 or count > 1) and username is None:
            return
        parsed = urlparse(form["element"].get_action())
        # Allow unsecure completion if wanted by user
        if parsed.scheme != "https" and username is None:
            return
        # We want a user, check if it wanted password
        if username is not None and username != attributes["login"]:
            return
        try:
            form["username"].set_value(attributes["login"])
            form["password"].set_value(password)
        except Exception as e:
            print("FormsExtension::set_input_forms()", e)

    def get_elements(self, elements):
        """
            Get forms as dict and textareas for elements
            @param elements as [WebKit2WebExtension.DOMElement]
            @return elements as ([{}],
                                 [WebKit2WebExtension.DOMHTMLTextAreaElement])
        """
        forms = []
        textareas = []
        for element in elements:
            if isinstance(element, WebKit2WebExtension.DOMHTMLTextAreaElement):
                textareas.append(element)
            elif isinstance(element, WebKit2WebExtension.DOMHTMLFormElement):
                form = {"element": element}
                elements_collection = element.get_elements()
                h = 0
                while h < elements_collection.get_length():
                    element = elements_collection.item(h)
                    if isinstance(element,
                                  WebKit2WebExtension.DOMHTMLInputElement):
                        if element.get_input_type() == "password" and\
                                element.get_name() is not None:
                            form["password"] = element
                        elif element.get_input_type() in ["text",
                                                          "email",
                                                          "search"] and\
                                element.get_name() is not None:
                            form["username"] = element
                    elif isinstance(
                            element,
                            WebKit2WebExtension.DOMHTMLTextAreaElement):
                        textareas.append(element)
                    h += 1
                keys = form.keys()
                if "username" in keys and "password" in keys:
                    forms.append(form)
        return (forms, textareas)

    def on_form_submit(self, element, event):
        """
            Ask user for saving credentials
            @param element as WebKit2WebExtension.DOMElement
            @param event as WebKit2WebExtension.DOMUIEvent
        """
        page = self.__extension.get_page(self.__page_id)
        if page is None:
            return
        (forms, textareas) = self.get_elements([element])
        if not forms or not forms[0]["password"].get_value():
            return
        try:
            form = forms[0]
            uri = page.get_uri()
            form_uri = form["element"].get_action()
            parsed_form_uri = urlparse(form_uri)
            form_uri = "%s://%s" % (parsed_form_uri.scheme,
                                    parsed_form_uri.netloc)
            user_form_name = form["username"].get_name()
            user_form_value = form["username"].get_value()
            pass_form_name = form["password"].get_name()
            pass_form_value = form["password"].get_value()
            self.__helper.get(form_uri, user_form_name, pass_form_name,
                              self.__on_get_password, user_form_name,
                              user_form_value, pass_form_name, pass_form_value,
                              uri, self.__page_id)
        except Exception as e:
            print("FormsExtension::on_form_submit():", e)

    @property
    def pending_credentials(self):
        """
            Get credentials
            @return (str, str, str, str, str, str)/None/Type.NONE
        """
        return self.__pending_credentials

#######################
# PRIVATE             #
#######################

    def __on_get_password(self, attributes, password, form_uri, index, count,
                          user_form_name, user_form_value, pass_form_name,
                          pass_form_value, uri, page_id):
        """
            Ask for credentials through DBus
            @param attributes as {}
            @param password as str
            @param form_uri as str
            @param index as int
            @param count as int
            @param user_form_name as str
            @param user_form_value as str
            @param pass_form_name as str
            @param pass_form_value as str
            @param uri as str
            @param page_id as int
        """
        try:
            # If credentials not found (!=Type.NONE) and something new
            # is submitted
            if self.__pending_credentials != Type.NONE and (
                    attributes is None
                    or attributes["login"] != user_form_value
                    or password != pass_form_value):
                if attributes is None or\
                        attributes["login"] != user_form_value:
                    uuid = ""
                else:
                    uuid = attributes["uuid"]
                self.__pending_credentials = (uuid, user_form_name,
                                              user_form_value, pass_form_name,
                                              pass_form_value, uri, form_uri)
            else:
                # Found, no more lookup
                self.__pending_credentials = Type.NONE
            # Last found credentials
            if count < 1 or index == count - 1:
                # Reset pending
                if self.__pending_credentials == Type.NONE:
                    self.__pending_credentials = None
                # Ask for user input
                elif self.__pending_credentials not in [None, Type.NONE]:
                    (uuid, user_form_name, user_form_value, pass_form_name,
                     pass_form_value, uri,
                     form_uri) = self.__pending_credentials
                    args = (uuid, user_form_name, user_form_value,
                            pass_form_name, uri, form_uri)
                    variant = GLib.Variant.new_tuple(
                        GLib.Variant("(ssssss)", args))
                    self.emit("submit-form", variant)
        except Exception as e:
            print("FormsExtension::__on_get_password()", e)

    def __on_page_created(self, extension, webpage):
        """
            Connect to send request
            @param extension as WebKit2WebExtension
            @param webpage as WebKit2WebExtension.WebPage
        """
        self.__page_id = webpage.get_id()
예제 #21
0
class CredentialsPopover(Gtk.Popover):
    """
        Tell user to save form credentials
    """
    def __init__(self, username, userform, password, passform, uri, window):
        """
            Init popover
            @param username as str
            @param password as str
            @param netloc as str
            @param window as Window
        """
        Gtk.Popover.__init__(self)
        self.set_modal(False)
        window.register(self)
        self.__helper = PasswordsHelper()
        self.__username = username
        self.__userform = userform
        self.__password = password
        self.__passform = passform
        self.__uri = uri
        self.__uuid = None
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/PopoverCredentials.ui')
        builder.connect_signals(self)
        self.__label = builder.get_object('label')
        parsed = urlparse(uri)
        builder.get_object('uri').set_text(parsed.netloc)
        builder.get_object('username').set_text(username)
        builder.get_object('password').set_text(password)
        self.add(builder.get_object('widget'))

#######################
# PROTECTED           #
#######################

    def _on_save_clicked(self, button):
        """
            Save username and password
            @param button as Gtk.Button
        """
        try:
            parsed = urlparse(self.__uri)
            uri = "%s://%s" % (parsed.scheme, parsed.netloc)
            self.__helper.clear(self.__username, uri)
            if self.__uuid is None:
                self.__uuid = str(uuid3(NAMESPACE_DNS, parsed.netloc))
            self.__helper.store(self.__username, self.__password, uri,
                                self.__uuid, self.__userform, self.__passform,
                                None)
            if El().sync_worker is not None:
                El().sync_worker.push_password(self.__username,
                                               self.__userform,
                                               self.__password,
                                               self.__passform, uri,
                                               self.__uuid)
            self.destroy()
        except Exception as e:
            print("CredentialsPopover::_on_save_clicked()", e)

    def popup(self):
        """
            Overwrite popup
        """
        self.__helper.get(self.__uri, self.__on_get_password)

#######################
# PRIVATE             #
#######################

    def __on_get_password(self, attributes, password, uri, index, count):
        """
            Set username/password input
            @param attributes as {}
            @param password as str
            @param uri as str
            @param index as int
            @param count as int
        """
        try:
            # No saved password
            if attributes is None:
                Gtk.Popover.popup(self)
            # Password saved and unchanged
            elif attributes["login"] == self.__username and\
                    self.__password == password and\
                    attributes["userform"] == self.__userform and\
                    attributes["passform"] == self.__passform:
                self.emit("closed")
                self.set_relative_to(None)  # Prevent popover to be displayed
            # Password changed
            elif attributes["login"] == self.__username:
                Gtk.Popover.popup(self)
                self.__uuid = attributes["uuid"]
                self.__label.set_text(
                    _("Do you want to modify this password?"))
            # Last password, it's a new login/password
            elif index == count - 1:
                Gtk.Popover.popup(self)
        except Exception as e:
            print("CredentialsPopover::__on_get_password()", e)
예제 #22
0
class FormsExtension:
    """
        Handle forms prefill
    """

    def __init__(self, extension, settings):
        """
            Connect wanted signal
            @param extension as WebKit2WebExtension
            @param settings as Settings
        """
        self.__helper = PasswordsHelper()
        self.__settings = settings
        extension.connect("page-created", self.__on_page_created)

    def get_forms(self, webpage):
        """
            Return forms for webpage
            @param webpage as WebKit2WebExtension.WebPage
            @return (WebKit2WebExtension.DOMElement,
                     WebKit2WebExtension.DOMElement)
        """
        inputs = webpage.get_dom_document().get_elements_by_tag_name('input')
        i = 0
        username_input = None
        password_input = None
        while i < inputs.get_length():
            name = inputs.item(i).get_attribute('name')
            if name is None:
                i += 1
                continue
            if password_input is None and\
                    inputs.item(i).get_input_type() == "password":
                password_input = inputs.item(i)
                i += 1
                continue
            if username_input is None and\
                    inputs.item(i).get_input_type() != "hidden":
                for search in LOGINS:
                    if name.lower().find(search) != -1:
                        username_input = inputs.item(i)
                        break
            i += 1
        return (username_input, password_input)

#######################
# PRIVATE             #
#######################
    def __on_page_created(self, extension, webpage):
        """
            Connect to send request
            @param extension as WebKit2WebExtension
            @param webpage as WebKit2WebExtension.WebPage
        """
        webpage.connect("document-loaded", self.__on_document_loaded)

    def __on_document_loaded(self, webpage):
        """
            Restore forms
            @param webpage as WebKit2WebExtension.WebPage
        """
        if not self.__settings.get_value("remember-passwords"):
            return

        (username_input, password_input) = self.get_forms(webpage)

        if username_input is None or password_input is None:
            return
        self.__helper.get(webpage.get_uri(),
                          self.__set_input,
                          username_input,
                          password_input)

    def __set_input(self, attributes, password, uri,
                    username_input, password_input):
        """
            Set username/password input
            @param attributes as {}
            @param password as str
            @param uri as str
            @param username_input as WebKit2WebExtension.DOMElement
            @param password_input as WebKit2WebExtension.DOMElement
        """
        # Do not set anything if no attributes or
        # If we have already text in input and we are not a perfect completion
        if attributes is None or (
                password_input.get_value() and
                uri != attributes["formSubmitURL"]):
            return
        try:
            username_input.set_value(attributes["login"])
            password_input.set_value(password)
        except Exception as e:
            print("FormsExtension::__set_input()", e)
예제 #23
0
class SyncWorker:
    """
       Manage sync with mozilla server, will start syncing on init
    """

    def check_modules():
        """
            True if deps are installed
            @return bool
        """
        from importlib import util
        fxa = util.find_spec("fxa")
        crypto = util.find_spec("Crypto")
        return fxa is not None and crypto is not None

    def __init__(self):
        """
            Init worker
        """
        self.__syncing = False
        self.__sync_cancellable = Gio.Cancellable()
        self.__username = ""
        self.__password = ""
        self.__token = ""
        self.__uid = ""
        self.__keyB = b""
        self.__mtimes = {"bookmarks": 0.1, "history": 0.1}
        # We do not create this here because it's slow down Eolie startup
        # See __mozilla_sync property
        self.__mz = None
        self.__state_lock = True
        self.__session = None
        self.__helper = PasswordsHelper()
        self.set_credentials()

    def login(self, attributes, password):
        """
            Login to service
            @param attributes as {}
            @param password as str
            @raise exceptions
        """
        self.__username = ""
        self.__password = ""
        self.__uid = ""
        self.__token = ""
        self.__keyB = b""
        if attributes is None or not attributes["login"] or not password:
            print("SyncWorker::login():", attributes)
            return
        from base64 import b64encode
        session = None
        self.__username = attributes["login"]
        self.__password = password
        # Connect to mozilla sync
        try:
            session = self.__mozilla_sync.login(self.__username, password)
            bid_assertion, key = self.__mozilla_sync.\
                get_browserid_assertion(session)
            self.__token = session.token
            self.__uid = session.uid
            self.__keyB = session.keys[1]
            keyB_encoded = b64encode(self.__keyB).decode("utf-8")
            self.__helper.clear_sync(self.__helper.store_sync,
                                     self.__username,
                                     password,
                                     self.__uid,
                                     self.__token,
                                     keyB_encoded,
                                     self.on_password_stored,
                                     True)
        except Exception as e:
            self.__helper.clear_sync(self.__helper.store_sync,
                                     attributes["login"],
                                     password,
                                     "", "", "")
            raise e

    def new_session(self):
        """
            Start a new session
        """
        # Just reset session, will be set by get_session_bulk_keys()
        self.__session = None

    def set_credentials(self):
        """
            Set credentials using Secret
        """
        self.__helper.get_sync(self.__set_credentials)

    def sync(self, loop=False, first_sync=False):
        """
            Start syncing, you need to check sync_status property
            @param loop as bool -> for GLib.timeout_add()
            @param first_sync as bool
        """
        if Gio.NetworkMonitor.get_default().get_network_available() and\
                self.__username and self.__password and not self.syncing:
            task_helper = TaskHelper()
            task_helper.run(self.__sync, first_sync)
        return loop

    def push_history(self, history_ids):
        """
            Push history ids
            @param history_ids as [int]
        """
        if Gio.NetworkMonitor.get_default().get_network_available() and\
                self.__username and self.__password:
            task_helper = TaskHelper()
            task_helper.run(self.__push_history, history_ids)

    def push_password(self, user_form_name, user_form_value, pass_form_name,
                      pass_form_value, uri, form_uri, uuid):
        """
            Push password
            @param user_form_name as str
            @param user_form_value as str
            @param pass_form_name as str
            @param pass_form_value as str
            @param uri as str
            @param form_uri as str
            @param uuid as str
        """
        if Gio.NetworkMonitor.get_default().get_network_available() and\
                self.__username and self.__password:
            task_helper = TaskHelper()
            task_helper.run(self.__push_password,
                            user_form_name, user_form_value, pass_form_name,
                            pass_form_value, uri, form_uri, uuid)

    def remove_from_history(self, guid):
        """
            Remove history guid from remote history
            @param guid as str
        """
        if Gio.NetworkMonitor.get_default().get_network_available() and\
                self.__username and self.__password:
            task_helper = TaskHelper()
            task_helper.run(self.__remove_from_history, guid)

    def remove_from_bookmarks(self, guid):
        """
            Remove bookmark guid from remote bookmarks
            @param guid as str
        """
        if Gio.NetworkMonitor.get_default().get_network_available() and\
                self.__username and self.__password:
            task_helper = TaskHelper()
            task_helper.run(self.__remove_from_bookmarks, guid)

    def remove_from_passwords(self, uuid):
        """
            Remove password from passwords collection
            @param uuid as str
        """
        if Gio.NetworkMonitor.get_default().get_network_available() and\
                self.__username and self.__password:
            task_helper = TaskHelper()
            task_helper.run(self.__remove_from_passwords, uuid)

    def delete_secret(self):
        """
            Delete sync secret
        """
        self.__username = ""
        self.__password = ""
        self.__session = None
        self.__sync_cancellable.reset()
        self.__helper.clear_sync(None)

    def stop(self, force=False):
        """
            Stop update, if force, kill session too
            @param force as bool
        """
        self.__sync_cancellable.cancel()
        if force:
            self.__session = None

    def on_password_stored(self, secret, result, sync):
        """
            Update credentials
            @param secret as Secret
            @param result as Gio.AsyncResult
            @param sync as bool
        """
        self.set_credentials()
        if sync:
            # Wait for credentials (server side)
            GLib.timeout_add(10, self.sync, True)

    @property
    def mtimes(self):
        """
            Sync engine modification times
            @return {}
        """
        return self.__mtimes

    @property
    def syncing(self):
        """
            True if sync is running
            @return bool
        """
        return self.__syncing

    @property
    def status(self):
        """
            True if sync is working
            @return bool
        """
        try:
            if self.__username:
                self.__get_session_bulk_keys()
                self.__mozilla_sync.client.info_collections()
                return True
        except Exception as e:
            print("SyncWorker::status(): %s" % e)

    @property
    def username(self):
        """
            Get username
            @return str
        """
        return self.__username

#######################
# PRIVATE             #
#######################
    @property
    def __mozilla_sync(self):
        """
            Get mozilla sync, create if None
        """
        if self.__mz is None:
            self.__mz = MozillaSync()
        return self.__mz

    def __get_session_bulk_keys(self):
        """
            Get session decrypt keys
            @return keys as (b"", b"")
        """
        if self.__session is None:
            from fxa.core import Session as FxASession
            from fxa.crypto import quick_stretch_password
            self.__session = FxASession(self.__mozilla_sync.fxa_client,
                                        self.__username,
                                        quick_stretch_password(
                                                        self.__username,
                                                        self.__password),
                                        self.__uid,
                                        self.__token)
            self.__session.keys = [b"", self.__keyB]
        self.__session.check_session_status()
        bid_assertion, key = self.__mozilla_sync.get_browserid_assertion(
                                                                self.__session)
        bulk_keys = self.__mozilla_sync.connect(bid_assertion, key)
        return bulk_keys

    def __update_state(self):
        """
            Update state file
        """
        try:
            # If syncing, state will be written by self.__sync()
            if not self.syncing:
                f = open(EOLIE_DATA_PATH + "/mozilla_sync.bin", "wb")
                # Lock file
                flock(f, LOCK_EX | LOCK_NB)
                self.__mtimes = self.__mozilla_sync.client.info_collections()
                dump(self.__mtimes, f)
                # Unlock file
                flock(f, LOCK_UN)
        except Exception as e:
            debug("SyncWorker::__update_state(): %s" % e)

    def __push_history(self, history_ids):
        """
            Push history ids if atime is available, else, ask to remove
            @param history ids as [int]
        """
        try:
            bulk_keys = self.__get_session_bulk_keys()
            for history_id in history_ids:
                self.__check_worker()
                sleep(0.01)
                record = {}
                atimes = El().history.get_atimes(history_id)
                guid = El().history.get_guid(history_id)
                if atimes:
                    record["histUri"] = El().history.get_uri(history_id)
                    record["id"] = guid
                    record["title"] = El().history.get_title(history_id)
                    record["visits"] = []
                    for atime in atimes:
                        record["visits"].append({"date": atime*1000000,
                                                 "type": 1})
                    debug("pushing %s" % record)
                    self.__mozilla_sync.add(record, "history", bulk_keys)
                else:
                    record["id"] = guid
                    record["type"] = "item"
                    record["deleted"] = True
                    debug("deleting %s" % record)
                    self.__mozilla_sync.add(record, "history", bulk_keys)
                self.__update_state()
        except Exception as e:
            debug("SyncWorker::__push_history(): %s" % e)

    def __push_password(self, user_form_name, user_form_value, pass_form_name,
                        pass_form_value, uri, form_uri, uuid):
        """
            Push password
            @param user_form_name as str
            @param user_form_value as str
            @param pass_form_name as str
            @param pass_form_value as str
            @param uri as str
            @param uuid as str
        """
        try:
            self.__check_worker()
            bulk_keys = self.__get_session_bulk_keys()
            record = {}
            record["id"] = "{%s}" % uuid
            record["hostname"] = uri
            record["formSubmitURL"] = form_uri
            record["httpRealm"] = None
            record["username"] = user_form_value
            record["password"] = pass_form_value
            record["usernameField"] = user_form_name
            record["passwordField"] = pass_form_name
            mtime = int(time()*1000)
            record["timeCreated"] = mtime
            record["timePasswordChanged"] = mtime
            debug("pushing %s" % record)
            self.__mozilla_sync.add(record, "passwords", bulk_keys)
            self.__update_state()
        except Exception as e:
            print("SyncWorker::__push_password():", e)

    def __remove_from_history(self, guid):
        """
            Remove from history
            @param guid as str
        """
        try:
            self.__check_worker()
            bulk_keys = self.__get_session_bulk_keys()
            record = {}
            record["id"] = guid
            record["type"] = "item"
            record["deleted"] = True
            debug("deleting %s" % record)
            self.__mozilla_sync.add(record, "history", bulk_keys)
            self.__update_state()
        except Exception as e:
            debug("SyncWorker::__remove_from_history(): %s" % e)

    def __remove_from_bookmarks(self, guid):
        """
            Remove from history
            @param guid as str
        """
        try:
            self.__check_worker()
            bulk_keys = self.__get_session_bulk_keys()
            record = {}
            record["id"] = guid
            record["type"] = "bookmark"
            record["deleted"] = True
            debug("deleting %s" % record)
            self.__mozilla_sync.add(record, "bookmark", bulk_keys)
            self.__update_state()
        except Exception as e:
            debug("SyncWorker::__remove_from_bookmarks(): %s" % e)

    def __remove_from_passwords(self, uuid):
        """
            Remove password from passwords collection
            @param uuid as str
        """
        try:
            self.__check_worker()
            bulk_keys = self.__get_session_bulk_keys()
            record = {}
            record["id"] = uuid
            record["deleted"] = True
            debug("deleting %s" % record)
            self.__mozilla_sync.add(record, "passwords", bulk_keys)
            self.__update_state()
        except Exception as e:
            debug("SyncWorker::__remove_from_passwords(): %s" % e)

    def __sync(self, first_sync):
        """
            Sync Eolie objects (bookmarks, history, ...) with Mozilla Sync
            @param first_sync as bool
        """
        debug("Start syncing")
        self.__syncing = True
        self.__sync_cancellable.reset()
        try:
            self.__mtimes = load(open(EOLIE_DATA_PATH + "/mozilla_sync.bin",
                                 "rb"))
        except:
            self.__mtimes = {"bookmarks": 0.1,
                             "history": 0.1,
                             "passwords": 0.1}
        try:
            self.__check_worker()

            bulk_keys = self.__get_session_bulk_keys()
            new_mtimes = self.__mozilla_sync.client.info_collections()

            self.__check_worker()
            ########################
            # Passwords Management #
            ########################
            try:
                debug("local passwords: %s, remote passwords: %s" % (
                                                    self.__mtimes["passwords"],
                                                    new_mtimes["passwords"]))
                # Only pull if something new available
                if self.__mtimes["passwords"] != new_mtimes["passwords"]:
                    self.__pull_passwords(bulk_keys)
            except:
                pass  # No passwords in sync

            self.__check_worker()
            ######################
            # History Management #
            ######################
            try:
                debug("local history: %s, remote history: %s" % (
                                                     self.__mtimes["history"],
                                                     new_mtimes["history"]))
                # Only pull if something new available
                if self.__mtimes["history"] != new_mtimes["history"]:
                    self.__pull_history(bulk_keys)
            except:
                pass  # No history in sync

            self.__check_worker()
            ########################
            # Bookmarks Management #
            ########################
            try:
                debug("local bookmarks: %s, remote bookmarks: %s" % (
                                                    self.__mtimes["bookmarks"],
                                                    new_mtimes["bookmarks"]))
                # Push new bookmarks
                self.__push_bookmarks(bulk_keys)
            except:
                pass  # No bookmarks in sync
            self.__check_worker()
            # Only pull if something new available
            if self.__mtimes["bookmarks"] != new_mtimes["bookmarks"]:
                self.__pull_bookmarks(bulk_keys, first_sync)
            # Update last sync mtime
            self.__syncing = False
            self.__update_state()
            debug("Stop syncing")
        except Exception as e:
            debug("SyncWorker::__sync(): %s" % e)
            if str(e) == "The authentication token could not be found":
                self.set_credentials()
            self.__syncing = False

    def __push_bookmarks(self, bulk_keys):
        """
            Push to bookmarks
            @param bulk keys as KeyBundle
            @param start time as float
            @raise StopIteration
        """
        debug("push bookmarks")
        parents = []
        for bookmark_id in El().bookmarks.get_ids_for_mtime(
                                                   self.__mtimes["bookmarks"]):
            self.__check_worker()
            sleep(0.01)
            parent_guid = El().bookmarks.get_parent_guid(bookmark_id)
            # No parent, move it to unfiled
            if parent_guid is None:
                parent_guid = "unfiled"
            parent_id = El().bookmarks.get_id_by_guid(parent_guid)
            if parent_id not in parents:
                parents.append(parent_id)
            record = {}
            record["bmkUri"] = El().bookmarks.get_uri(bookmark_id)
            record["id"] = El().bookmarks.get_guid(bookmark_id)
            record["title"] = El().bookmarks.get_title(bookmark_id)
            record["tags"] = El().bookmarks.get_tags(bookmark_id)
            record["parentid"] = parent_guid
            record["parentName"] = El().bookmarks.get_parent_name(bookmark_id)
            record["type"] = "bookmark"
            debug("pushing %s" % record)
            self.__mozilla_sync.add(record, "bookmarks", bulk_keys)
        # Del old bookmarks
        for bookmark_id in El().bookmarks.get_deleted_ids():
            self.__check_worker()
            sleep(0.01)
            parent_guid = El().bookmarks.get_parent_guid(bookmark_id)
            parent_id = El().bookmarks.get_id_by_guid(parent_guid)
            if parent_id not in parents:
                parents.append(parent_id)
            record = {}
            record["id"] = El().bookmarks.get_guid(bookmark_id)
            record["type"] = "bookmark"
            record["deleted"] = True
            debug("deleting %s" % record)
            self.__mozilla_sync.add(record, "bookmarks", bulk_keys)
            El().bookmarks.remove(bookmark_id)
        # Push parents in this order, parents near root are handled later
        # Otherwise, order will be broken by new children updates
        while parents:
            parent_id = parents.pop(0)
            parent_guid = El().bookmarks.get_guid(parent_id)
            parent_name = El().bookmarks.get_title(parent_id)
            children = El().bookmarks.get_children(parent_guid)
            # So search if children in parents
            found = False
            for child_guid in children:
                child_id = El().bookmarks.get_id_by_guid(child_guid)
                if child_id in parents:
                    found = True
                    break
            # Handle children first
            if found:
                parents.append(parent_id)
                debug("later: %s" % parent_name)
                continue
            record = {}
            record["id"] = parent_guid
            record["type"] = "folder"
            # A parent with parent as unfiled needs to be moved to places
            # Firefox internal
            grand_parent_guid = El().bookmarks.get_parent_guid(parent_id)
            if grand_parent_guid == "unfiled":
                grand_parent_guid = "places"
            record["parentid"] = grand_parent_guid
            record["parentName"] = El().bookmarks.get_parent_name(parent_id)
            record["title"] = parent_name
            record["children"] = children
            debug("pushing parent %s" % record)
            self.__mozilla_sync.add(record, "bookmarks", bulk_keys)
        El().bookmarks.clean_tags()

    def __pull_bookmarks(self, bulk_keys, first_sync):
        """
            Pull from bookmarks
            @param bulk_keys as KeyBundle
            @param first_sync as bool
            @raise StopIteration
        """
        debug("pull bookmarks")
        SqlCursor.add(El().bookmarks)
        records = self.__mozilla_sync.get_records("bookmarks", bulk_keys)
        children_array = []
        for record in records:
            self.__check_worker()
            if record["modified"] < self.__mtimes["bookmarks"]:
                continue
            sleep(0.01)
            bookmark = record["payload"]
            bookmark_id = El().bookmarks.get_id_by_guid(bookmark["id"])
            # Nothing to apply, continue
            if El().bookmarks.get_mtime(bookmark_id) >= record["modified"]:
                continue
            debug("pulling %s" % record)
            # Deleted bookmark
            if "deleted" in bookmark.keys():
                El().bookmarks.remove(bookmark_id)
            # Keep folder only for firefox compatiblity
            elif "type" in bookmark.keys() and bookmark["type"] == "folder"\
                    and bookmark["id"] is not None\
                    and bookmark["title"]:
                if bookmark_id is None:
                    bookmark_id = El().bookmarks.add(bookmark["title"],
                                                     bookmark["id"],
                                                     bookmark["id"],
                                                     [],
                                                     0,
                                                     False)
                # Will calculate position later
                if "children" in bookmark.keys():
                    children_array.append(bookmark["children"])
            # We have a bookmark, add it
            elif "type" in bookmark.keys() and bookmark["type"] == "bookmark"\
                    and bookmark["id"] is not None\
                    and bookmark["title"]:
                # Add a new bookmark
                if bookmark_id is None:
                    # Use parent name if no bookmarks tags
                    if "tags" not in bookmark.keys() or\
                            not bookmark["tags"]:
                        if "parentName" in bookmark.keys() and\
                                bookmark["parentName"]:
                            bookmark["tags"] = [bookmark["parentName"]]
                        else:
                            bookmark["tags"] = []
                    bookmark_id = El().bookmarks.add(bookmark["title"],
                                                     bookmark["bmkUri"],
                                                     bookmark["id"],
                                                     bookmark["tags"],
                                                     0,
                                                     False)
                # Update bookmark
                else:
                    El().bookmarks.set_title(bookmark_id,
                                             bookmark["title"],
                                             False)
                    El().bookmarks.set_uri(bookmark_id,
                                           bookmark["bmkUri"],
                                           False)
                    # Update tags
                    current_tags = El().bookmarks.get_tags(bookmark_id)
                    for tag in El().bookmarks.get_tags(bookmark_id):
                        if "tags" in bookmark.keys() and\
                                tag not in bookmark["tags"]:
                            tag_id = El().bookmarks.get_tag_id(tag)
                            current_tags.remove(tag)
                            El().bookmarks.del_tag_from(tag_id,
                                                        bookmark_id,
                                                        False)
                    if "tags" in bookmark.keys():
                        for tag in bookmark["tags"]:
                            # Tag already associated
                            if tag in current_tags:
                                continue
                            tag_id = El().bookmarks.get_tag_id(tag)
                            if tag_id is None:
                                tag_id = El().bookmarks.add_tag(tag, False)
                            El().bookmarks.add_tag_to(tag_id,
                                                      bookmark_id,
                                                      False)
            # Update parent name if available
            if bookmark_id is not None and "parentName" in bookmark.keys():
                El().bookmarks.set_parent(bookmark_id,
                                          bookmark["parentid"],
                                          bookmark["parentName"],
                                          False)
            El().bookmarks.set_mtime(bookmark_id,
                                     record["modified"],
                                     False)
        # Update bookmark position
        for children in children_array:
            position = 0
            for child in children:
                bid = El().bookmarks.get_id_by_guid(child)
                El().bookmarks.set_position(bid,
                                            position,
                                            False)
                position += 1
        El().bookmarks.clean_tags()  # Will commit
        SqlCursor.remove(El().bookmarks)

    def __pull_passwords(self, bulk_keys):
        """
            Pull from passwords
            @param bulk_keys as KeyBundle
            @raise StopIteration
        """
        debug("pull passwords")
        records = self.__mozilla_sync.get_records("passwords", bulk_keys)
        for record in records:
            self.__check_worker()
            if record["modified"] < self.__mtimes["passwords"]:
                continue
            sleep(0.01)
            debug("pulling %s" % record)
            password = record["payload"]
            password_id = password["id"].strip("{}")
            if "formSubmitURL" in password.keys():
                self.__helper.clear(password_id,
                                    self.__helper.store,
                                    password["usernameField"],
                                    password["username"],
                                    password["passwordField"],
                                    password["password"],
                                    password["hostname"],
                                    password["formSubmitURL"],
                                    password_id,
                                    None)
            elif "deleted" in password.keys():  # We assume True
                self.__helper.clear(password_id)

    def __pull_history(self, bulk_keys):
        """
            Pull from history
            @param bulk_keys as KeyBundle
            @raise StopIteration
        """
        debug("pull history")
        records = self.__mozilla_sync.get_records("history", bulk_keys)
        for record in records:
            self.__check_worker()
            if record["modified"] < self.__mtimes["history"]:
                continue
            sleep(0.01)
            El().history.thread_lock.acquire()
            history = record["payload"]
            keys = history.keys()
            history_id = El().history.get_id_by_guid(history["id"])
            # Check we have a valid history item
            if "histUri" in keys and\
                    "title" in keys and\
                    history["title"] and\
                    El().history.get_mtime(history_id) < record["modified"]:
                # Try to get visit date
                atimes = []
                try:
                    for visit in history["visits"]:
                        atimes.append(round(int(visit["date"]) / 1000000, 2))
                except:
                    El().history.thread_lock.release()
                    continue
                debug("pulling %s" % record)
                title = history["title"].rstrip().lstrip()
                history_id = El().history.add(title,
                                              history["histUri"],
                                              record["modified"],
                                              history["id"],
                                              atimes,
                                              True)
            elif "deleted" in keys:
                history_id = El().history.get_id_by_guid(history_id)
                El().history.remove(history_id)
            El().history.thread_lock.release()

    def __set_credentials(self, attributes, password, uri, index, count):
        """
            Set credentials
            @param attributes as {}
            @param password as str
            @param uri as None
            @param index as int
            @param count as int
        """
        if attributes is None:
            return
        from base64 import b64decode
        try:
            self.__username = attributes["login"]
            self.__password = password
            self.__token = attributes["token"]
            self.__uid = attributes["uid"]
            self.__keyB = b64decode(attributes["keyB"])
            # Force login if no token
            if not self.__token:
                self.login(attributes, password)
        except Exception as e:
            debug("SyncWorker::__set_credentials(): %s" % e)

    def __check_worker(self):
        """
            Raise an exception if worker should not be syncing: error&cancel
        """
        if self.__sync_cancellable.is_cancelled():
            raise StopIteration("SyncWorker: cancelled")
        elif not self.__username:
            raise StopIteration("SyncWorker: missing username")
        elif not self.__password:
            raise StopIteration("SyncWorker: missing password")
        elif not self.__token:
            raise StopIteration("SyncWorker: missing token")
예제 #24
0
class ProxyExtensionServer(Server):
    '''
    <!DOCTYPE node PUBLIC
    '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
    'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
    <node>
    <interface name="org.gnome.Eolie.Proxy">

    <method name="FormsFilled">
        <arg type="b" name="results" direction="out" />
    </method>
    <method name="SetPreviousElementValue">
    </method>
    <method name="SetNextElementValue">
    </method>
    <method name="SaveCredentials">
      <arg type="s" name="uuid" direction="in" />
      <arg type="s" name="user_form_name" direction="in" />
      <arg type="s" name="pass_form_name" direction="in" />
      <arg type="s" name="uri" direction="in" />
      <arg type="s" name="form_uri" direction="in" />
    </method>
    <method name="SetAuthForms">
      <arg type="s" name="username" direction="in" />
      <arg type="s" name="username" direction="in" />
    </method>
    <method name="GetScripts">
      <arg type="as" name="results" direction="out" />
    </method>
    <method name="GetImages">
      <arg type="as" name="results" direction="out" />
    </method>
    <method name="GetVideos">
      <arg type="aas" name="results" direction="out" />
    </method>
    <method name="GetImageLinks">
      <arg type="as" name="results" direction="out" />
    </method>
    <method name="GetSelection">
      <arg type="s" name="selection" direction="out" />
    </method>

    <signal name='UnsecureFormFocused'>
        <arg type="as" name="forms" direction="out" />
    </signal>
    <signal name='ShowCredentials'>
        <arg type="as" name="forms" direction="out" />
        <arg type="as" name="form_uri" direction="out" />
    </signal>
    <signal name='AskSaveCredentials'>
        <arg type="s" name="uuid" direction="out" />
        <arg type="s" name="user_form_value" direction="out" />
        <arg type="s" name="uri" direction="out" />
        <arg type="s" name="form_uri" direction="out" />
    </signal>
    </interface>
    </node>
    '''

    def __init__(self, extension, page, form_extension, jsblock_extension):
        """
            Init server
            @param extension as WebKit2WebExtension.WebExtension
            @param page as WebKit2WebExtension.WebPage
            @param form_extension as FormsExtension
            @param jsblock_extension as JSBlockExtension
        """
        self.__extension = extension
        self.__page = page
        self.__form_extension = form_extension
        self.__jsblock_extension = jsblock_extension
        self.__focused = None
        self.__on_input_timeout_id = None
        self.__elements_history = {}
        self.__send_requests = []
        self.__helper = PasswordsHelper()
        self.__proxy_bus = PROXY_BUS % self.__page.get_id()
        addr = Gio.dbus_address_get_for_bus_sync(Gio.BusType.SESSION, None)
        self.__bus = None
        Gio.DBusConnection.new_for_address(
                               addr,
                               Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT |
                               Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
                               None,
                               None,
                               self.__on_bus_new_for_address)
        form_extension.connect("submit-form", self.__on_submit_form)
        page.connect("send-request", self.__on_send_request)
        page.connect("context-menu", self.__on_context_menu)
        page.connect("notify::uri", self.__on_notify_uri)
        page.connect("form-controls-associated",
                     self.__on_form_control_associated)

    def FormsFilled(self):
        """
            True if form contains data
            @return bool
        """
        dom = self.__page.get_dom_document()
        collection = dom.get_elements_by_tag_name("textarea")
        for i in range(0, collection.get_length()):
            if collection.item(i).is_edited():
                return True
        return False

    def SaveCredentials(self, uuid, user_form_name,
                        pass_form_name, uri, form_uri):
        """
            Save credentials to org.freedesktop.Secrets
            @param uuid as str
            @param user_form_name as str
            @param pass_form_name as str
            @param uri as str
            @param form_uri as str
        """
        if self.__form_extension.pending_credentials in [None, Type.NONE]:
            return
        try:
            (_uuid, _user_form_name, user_form_value,
             _pass_form_name, pass_form_value,
             _uri, _form_uri) = self.__form_extension.pending_credentials
            if user_form_name != _user_form_name or\
                    pass_form_name != _pass_form_name or\
                    uri != _uri or\
                    form_uri != _form_uri:
                return
            parsed = urlparse(uri)
            uri = "%s://%s" % (parsed.scheme, parsed.netloc)
            if not uuid:
                uuid = str(uuid4())
                self.__helper.store(user_form_name,
                                    user_form_value,
                                    pass_form_name,
                                    pass_form_value,
                                    uri,
                                    form_uri,
                                    uuid,
                                    None)
            else:
                self.__helper.clear(uuid,
                                    self.__helper.store,
                                    user_form_name,
                                    user_form_value,
                                    pass_form_name,
                                    pass_form_value,
                                    uri,
                                    form_uri,
                                    uuid,
                                    None)
        except Exception as e:
            print("ProxyExtension::SaveCredentials():", e)

    def SetAuthForms(self, userform, username):
        """
            Get password forms
            @param userform as str
        """
        try:
            collection = self.__page.get_dom_document().get_forms()
            elements = []
            for i in range(0, collection.get_length()):
                elements.append(collection.item(i))
            (forms, textareas) = self.__form_extension.get_elements(elements)
            for form in forms:
                if form["username"].get_name() == userform:
                    self.__helper.get(form["element"].get_action(),
                                      userform,
                                      form["password"].get_name(),
                                      self.__form_extension.set_input_forms,
                                      self.__page,
                                      form,
                                      username)
                    return
        except Exception as e:
            print("ProxyExtension::SetAuthForms():", e)

    def GetScripts(self):
        """
            Get images
            @return [str]
        """
        try:
            return self.__jsblock_extension.scripts
        except Exception as e:
            print("ProxyExtension::GetScripts():", e)
        return []

    def GetImages(self):
        """
            Get images
            @return [str]
        """
        try:
            page = self.__extension.get_page(self.__page.get_id())
            if page is None:
                return []
            dom_list = page.get_dom_document().get_elements_by_tag_name("img")
            uris = []
            for i in range(0, dom_list.get_length()):
                uri = dom_list.item(i).get_src()
                if uri not in uris:
                    uris.append(uri)
            return uris
        except Exception as e:
            print("ProxyExtension::GetImages():", e)
        return []

    def GetVideos(self):
        """
            Get videos
            @return [str]
        """
        page = self.__extension.get_page(self.__page.get_id())
        if page is None:
            return []
        videos = []
        extensions = ["avi", "flv", "mp4", "mpg", "mpeg", "webm"]
        for uri in self.__send_requests:
            parsed = urlparse(uri)
            title = None
            # Search for video in page
            if uri.split(".")[-1] in extensions:
                title = uri
            elif parsed.netloc.endswith("googlevideo.com") and\
                    parsed.path == "/videoplayback":
                title = page.get_dom_document().get_title()
                if title is None:
                    title = uri
                # For youtube, we only want one video:
                return [(title, uri)]
            if title is not None and (title, uri) not in videos:
                videos.append((title, uri))
        return videos

    def GetImageLinks(self):
        """
            Get image links
            @return [str]
        """
        try:
            page = self.__extension.get_page(self.__page.get_id())
            if page is None:
                return []
            dom_list = page.get_dom_document().get_elements_by_tag_name("a")
            uris = []
            for i in range(0, dom_list.get_length()):
                uri = dom_list.item(i).get_href()
                if uri is None or uri in uris:
                    continue
                ext = uri.split(".")[-1]
                if ext in ["gif", "jpg", "png", "jpeg"]:
                    uris.append(uri)
            return uris
        except Exception as e:
            print("ProxyExtension::GetImagesLinks():", e)
        return []

    def GetSelection(self):
        """
            Get selected text
            @param page id as int
            @return str
        """
        webpage = self.__extension.get_page(self.__page.get_id())
        document = webpage.get_dom_document()
        if document is None:
            return ""
        window = document.get_default_view()
        if window is None:
            return ""
        selection = window.get_selection()
        if selection is None:
            return ""
        try:
            dom_range = selection.get_range_at(0)
        except:
            dom_range = None
        value = ""
        if dom_range is not None:
            value = dom_range.to_string()
        if value is None:
            value = ""
        return value

    def SetPreviousElementValue(self):
        """
            Set focused form to previous value
        """
        if self.__focused is None:
            return
        try:
            value = self.__focused.get_value().rstrip(" ")
            if self.__focused in self.__elements_history.keys():
                current = self.__elements_history[self.__focused]
                if current.prev is not None:
                    self.__elements_history[self.__focused] = current.prev
                    self.__focused.set_value(current.prev.value)
            elif value:
                next = LinkedList(value, None, None)
                current = LinkedList("", next, None)
                next.set_prev(current)
                self.__elements_history[self.__focused] = current
                self.__focused.set_value("")
        except Exception as e:
            print("ProxyExtension::SetPreviousForm():", e)

    def SetNextElementValue(self):
        """
            Set focused form to next value
        """
        if self.__focused is None:
            return
        try:
            if self.__focused in self.__elements_history.keys():
                current = self.__elements_history[self.__focused]
                if current.next is not None:
                    self.__elements_history[self.__focused] = current.next
                    self.__focused.set_value(current.next.value)
        except Exception as e:
            print("ProxyExtension::SetNextForm():", e)

#######################
# PRIVATE             #
#######################
    def __add_event_listeners(self, forms, textareas, webpage):
        """
            Add event listeners on inputs and textareas
            @param forms as {}
            @param textareas as [WebKit2WebExtension.DOMHTMLTextAreaElement]
            @param webpage as WebKit2WebExtension.WebPage
        """
        self.__focused = None
        self.__elements_history = {}

        parsed = urlparse(webpage.get_uri())

        # Manage forms events
        for form in forms:
            form["username"].add_event_listener("input",
                                                self.__on_input,
                                                False)
            form["username"].add_event_listener("focus",
                                                self.__on_focus,
                                                False)
            form["username"].add_event_listener("blur",
                                                self.__on_blur,
                                                False)
            form["username"].add_event_listener("mousedown",
                                                self.__on_mouse_down,
                                                False)
            # Check for unsecure content
            if parsed.scheme == "http":
                form["password"].add_event_listener("focus",
                                                    self.__on_focus,
                                                    False)
        # Manage textareas events
        for textarea in textareas:
            textarea.add_event_listener("input", self.__on_input, False)
            textarea.add_event_listener("focus", self.__on_focus, False)

    def __on_bus_new_for_address(self, source, result):
        """
            Init bus
            @param source as GObject.Object
            @param result as Gio.AsyncResult
        """
        self.__bus = source.new_for_address_finish(result)
        Gio.bus_own_name_on_connection(self.__bus,
                                       self.__proxy_bus,
                                       Gio.BusNameOwnerFlags.NONE,
                                       None,
                                       None)
        Server.__init__(self, self.__bus, PROXY_PATH)

    def __on_focus(self, element, event):
        """
            Keep last focused form
            @param element as WebKit2WebExtension.DOMElement
            @param event as WebKit2WebExtension.DOMUIEvent
        """
        if isinstance(element, WebKit2WebExtension.DOMHTMLInputElement):
            if element.get_input_type() == "password" and\
                    self.__bus is not None:
                self.__bus.emit_signal(
                              None,
                              PROXY_PATH,
                              self.__proxy_bus,
                              "UnsecureFormFocused",
                              None)
        self.__focused = element

    def __on_blur(self, element, event):
        """
            Reset focus
            @param element as WebKit2WebExtension.DOMElement
            @param event as WebKit2WebExtension.DOMUIEvent
        """
        if self.__focused == element:
            self.__focused = None

    def __on_mouse_down(self, element, event):
        """
           Emit Input mouse down signal
           @param element as WebKit2WebExtension.DOMHTMLInputElement
           @param event as WebKit2WebExtension.DOMUIEvent
        """
        if element.get_name() is None:
            return
        if self.__focused != element and\
                self.__bus is not None:
            form_uri = element.get_form().get_action()
            parsed_form_uri = urlparse(form_uri)
            form_uri = "%s://%s" % (parsed_form_uri.scheme,
                                    parsed_form_uri.netloc)
            args = GLib.Variant("(ss)", (element.get_name(), form_uri))
            self.__bus.emit_signal(
                              None,
                              PROXY_PATH,
                              self.__proxy_bus,
                              "ShowCredentials",
                              args)

    def __on_input(self, element, event):
        """
            Run a timeout before saving buffer to history
            @param element as WebKit2WebExtension.DOMElement
            @param event as WebKit2WebExtension.DOMUIEvent
        """
        if self.__on_input_timeout_id is not None:
            GLib.source_remove(self.__on_input_timeout_id)
        self.__on_input_timeout_id = GLib.timeout_add(500,
                                                      self.__on_input_timeout,
                                                      element)

    def __on_input_timeout(self, element):
        """
            Save buffer to history
            @param element as WebKit2WebExtension.DOMElement
        """
        self.__on_input_timeout_id = None
        new_value = element.get_value()
        item = LinkedList("", None, None)
        if element in self.__elements_history.keys():
            item = self.__elements_history[element]
        next = LinkedList(new_value.rstrip(" "), None, item)
        if item is not None:
            item.set_next(next)
        self.__elements_history[element] = next

    def __on_form_control_associated(self, webpage, elements):
        """
            Add elements to forms
            @param webpage as WebKit2WebExtension.WebPage
            @param elements as [WebKit2WebExtension.DOMElement]
        """
        (forms, textareas) = self.__form_extension.get_elements(elements)
        self.__add_event_listeners(forms, textareas, webpage)
        for form in forms:
            form["element"].add_event_listener(
                                          "submit",
                                          self.__form_extension.on_form_submit,
                                          False)
            self.__form_extension.set_credentials(form, webpage)

    def __on_context_menu(self, webpage, context_menu, hit):
        """
            Add selection to context menu user data
            @param webpage as WebKit2WebExtension.WebPage
            @param context_menu as WebKit2WebExtension.ContextMenu
            @param hit as WebKit2.HitTestResult
        """
        value = self.GetSelection()
        context_menu.set_user_data(GLib.Variant("s", value))

    def __on_submit_form(self, forms, variant):
        """
            Ask for credentials save
            @param forms as FormsExtension
            @param variant as GLib.Variant
        """
        if self.__bus is not None:
            self.__bus.emit_signal(
                                  None,
                                  PROXY_PATH,
                                  self.__proxy_bus,
                                  "AskSaveCredentials",
                                  variant)

    def __on_notify_uri(self, webpage, param):
        """
            Reset send requests
            @param webpage as WebKit2WebExtension.WebPage
            @param uri as GObject.ParamSpec
        """
        self.__send_requests = []

    def __on_send_request(self, webpage, request, redirect):
        """
            Keep send requests
            @param webpage as WebKit2WebExtension.WebPage
            @param request as WebKit2.URIRequest
            @param redirect as WebKit2WebExtension.URIResponse
        """
        self.__send_requests.append(request.get_uri())
예제 #25
0
class PasswordsPopover(Gtk.Popover):
    """
        Show saved passwords
    """
    def __init__(self):
        """
            Init popover
        """
        Gtk.Popover.__init__(self)
        self.__filter = ""
        self.__helper = PasswordsHelper()
        self.set_position(Gtk.PositionType.BOTTOM)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/PopoverPasswords.ui')
        builder.connect_signals(self)
        self.__listbox = builder.get_object("listbox")
        self.__listbox.set_filter_func(self.__filter_func)
        self.add(builder.get_object('widget'))
        self.set_size_request(300, 300)

    def populate(self):
        """
            Populate popover
        """
        self.__helper.get_all(self.__add_password)

#######################
# PROTECTED           #
#######################

    def _on_search_changed(self, entry):
        """
            Update filter
            @param entry as Gtk.Entry
        """
        self.__filter = entry.get_text()
        self.__listbox.invalidate_filter()

    def _on_remove_all_clicked(self, button):
        """
            Remove all passwords
            @param button as Gtk.Button
        """
        for child in self.__listbox.get_children():
            child.delete()

#######################
# PRIVATE             #
#######################

    def __filter_func(self, row):
        """
            Filter rows
            @param row as Row
        """
        return self.__filter in row.item.get_property("uri")

    def __add_password(self, attributes, password, uri):
        """
            Add password to model
            @param attributes as {}
            @param password as str
            @param uri as None
        """
        if attributes is None:
            return
        item = Item()
        item.set_property("uri", attributes["formSubmitURL"])
        child = Row(item, self.__helper)
        child.show()
        self.__listbox.add(child)
예제 #26
0
파일: settings.py 프로젝트: City-busz/eolie
    def __init__(self, window):
        """
            Init dialog
            @param window as Window
        """
        self.__helper = PasswordsHelper()
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Eolie/SettingsDialog.ui")

        self.__settings_dialog = builder.get_object("settings_dialog")
        self.__settings_dialog.set_transient_for(window)
        # self.__settings_dialog.connect("destroy", self.__on_destroy)

        if False:
            self.__settings_dialog.set_title(_("Preferences"))
        else:
            headerbar = builder.get_object("header_bar")
            headerbar.set_title(_("Preferences"))
            self.__settings_dialog.set_titlebar(headerbar)

        download_chooser = builder.get_object("download_chooser")
        dir_uri = El().settings.get_value("download-uri").get_string()
        if not dir_uri:
            directory = GLib.get_user_special_dir(
                                         GLib.UserDirectory.DIRECTORY_DOWNLOAD)
            if directory is not None:
                dir_uri = GLib.filename_to_uri(directory, None)
        if dir_uri:
            download_chooser.set_uri(dir_uri)
        else:
            download_chooser.set_uri("file://" + GLib.getenv("HOME"))

        open_downloads = builder.get_object("open_downloads_check")
        open_downloads.set_active(
                                El().settings.get_value("open-downloads"))

        self.__start_page_uri = builder.get_object("start_page_uri")
        combo_start = builder.get_object("combo_start")
        start_page = El().settings.get_value("start-page").get_string()
        if start_page.startswith("http"):
            combo_start.set_active_id("address")
            self.__start_page_uri.set_text(start_page)
            self.__start_page_uri.show()
        else:
            combo_start.set_active_id(start_page)

        remember_session = builder.get_object("remember_sessions_check")
        remember_session.set_active(
                                El().settings.get_value("remember-session"))

        enable_plugins = builder.get_object("plugins_check")
        enable_plugins.set_active(
                                El().settings.get_value("enable-plugins"))

        self.__fonts_grid = builder.get_object("fonts_grid")
        use_system_fonts = builder.get_object("system_fonts_check")
        use_system_fonts.set_active(
                                El().settings.get_value("use-system-fonts"))
        self.__fonts_grid.set_sensitive(
                            not El().settings.get_value("use-system-fonts"))

        sans_serif_button = builder.get_object("sans_serif_button")
        sans_serif_button.set_font_name(
                       El().settings.get_value("font-sans-serif").get_string())
        serif_button = builder.get_object("serif_button")
        serif_button.set_font_name(
                       El().settings.get_value("font-serif").get_string())
        monospace_button = builder.get_object("monospace_button")
        monospace_button.set_font_name(
                       El().settings.get_value("font-monospace").get_string())

        min_font_size_spin = builder.get_object("min_font_size_spin")
        min_font_size_spin.set_value(
                       El().settings.get_value("min-font-size").get_int32())

        monitor_model = get_current_monitor_model(window)
        zoom_levels = El().settings.get_value("default-zoom-level")
        wanted_zoom_level = 1.0
        try:
            for zoom_level in zoom_levels:
                zoom_splited = zoom_level.split('@')
                if zoom_splited[0] == monitor_model:
                    wanted_zoom_level = float(zoom_splited[1])
        except:
            pass
        default_zoom_level = builder.get_object("default_zoom_level")
        default_zoom_level.set_value(float(wanted_zoom_level))

        cookies_combo = builder.get_object("cookies_combo")
        storage = El().settings.get_enum("cookie-storage")
        cookies_combo.set_active_id(str(storage))

        history_combo = builder.get_object("history_combo")
        storage = El().settings.get_enum("history-storage")
        history_combo.set_active_id(str(storage))

        self.__populars_count = builder.get_object("populars_count")
        if start_page == "popular":
            self.__populars_count.show()
        max_popular_items = El().settings.get_value(
                                              "max-popular-items").get_int32()
        builder.get_object("popular_spin_button").set_value(max_popular_items)
        remember_passwords = builder.get_object("remember_passwords_check")
        remember_passwords.set_active(
                                El().settings.get_value("remember-passwords"))

        tracking_check = builder.get_object("tracking_check")
        tracking_check.set_active(
                                El().settings.get_value("do-not-track"))
        self.__result_label = builder.get_object("result_label")
        self.__sync_button = builder.get_object("sync_button")
        self.__login_entry = builder.get_object("login_entry")
        self.__password_entry = builder.get_object("password_entry")
        self.__result_image = builder.get_object("result_image")
        builder.connect_signals(self)
        self.__helper.get_sync(self.__on_get_sync)

        thread = Thread(target=self.__get_sync_status)
        thread.daemon = True
        thread.start()
예제 #27
0
파일: settings.py 프로젝트: City-busz/eolie
class SettingsDialog:
    """
        Dialog showing eolie options
    """

    def __init__(self, window):
        """
            Init dialog
            @param window as Window
        """
        self.__helper = PasswordsHelper()
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Eolie/SettingsDialog.ui")

        self.__settings_dialog = builder.get_object("settings_dialog")
        self.__settings_dialog.set_transient_for(window)
        # self.__settings_dialog.connect("destroy", self.__on_destroy)

        if False:
            self.__settings_dialog.set_title(_("Preferences"))
        else:
            headerbar = builder.get_object("header_bar")
            headerbar.set_title(_("Preferences"))
            self.__settings_dialog.set_titlebar(headerbar)

        download_chooser = builder.get_object("download_chooser")
        dir_uri = El().settings.get_value("download-uri").get_string()
        if not dir_uri:
            directory = GLib.get_user_special_dir(
                                         GLib.UserDirectory.DIRECTORY_DOWNLOAD)
            if directory is not None:
                dir_uri = GLib.filename_to_uri(directory, None)
        if dir_uri:
            download_chooser.set_uri(dir_uri)
        else:
            download_chooser.set_uri("file://" + GLib.getenv("HOME"))

        open_downloads = builder.get_object("open_downloads_check")
        open_downloads.set_active(
                                El().settings.get_value("open-downloads"))

        self.__start_page_uri = builder.get_object("start_page_uri")
        combo_start = builder.get_object("combo_start")
        start_page = El().settings.get_value("start-page").get_string()
        if start_page.startswith("http"):
            combo_start.set_active_id("address")
            self.__start_page_uri.set_text(start_page)
            self.__start_page_uri.show()
        else:
            combo_start.set_active_id(start_page)

        remember_session = builder.get_object("remember_sessions_check")
        remember_session.set_active(
                                El().settings.get_value("remember-session"))

        enable_plugins = builder.get_object("plugins_check")
        enable_plugins.set_active(
                                El().settings.get_value("enable-plugins"))

        self.__fonts_grid = builder.get_object("fonts_grid")
        use_system_fonts = builder.get_object("system_fonts_check")
        use_system_fonts.set_active(
                                El().settings.get_value("use-system-fonts"))
        self.__fonts_grid.set_sensitive(
                            not El().settings.get_value("use-system-fonts"))

        sans_serif_button = builder.get_object("sans_serif_button")
        sans_serif_button.set_font_name(
                       El().settings.get_value("font-sans-serif").get_string())
        serif_button = builder.get_object("serif_button")
        serif_button.set_font_name(
                       El().settings.get_value("font-serif").get_string())
        monospace_button = builder.get_object("monospace_button")
        monospace_button.set_font_name(
                       El().settings.get_value("font-monospace").get_string())

        min_font_size_spin = builder.get_object("min_font_size_spin")
        min_font_size_spin.set_value(
                       El().settings.get_value("min-font-size").get_int32())

        monitor_model = get_current_monitor_model(window)
        zoom_levels = El().settings.get_value("default-zoom-level")
        wanted_zoom_level = 1.0
        try:
            for zoom_level in zoom_levels:
                zoom_splited = zoom_level.split('@')
                if zoom_splited[0] == monitor_model:
                    wanted_zoom_level = float(zoom_splited[1])
        except:
            pass
        default_zoom_level = builder.get_object("default_zoom_level")
        default_zoom_level.set_value(float(wanted_zoom_level))

        cookies_combo = builder.get_object("cookies_combo")
        storage = El().settings.get_enum("cookie-storage")
        cookies_combo.set_active_id(str(storage))

        history_combo = builder.get_object("history_combo")
        storage = El().settings.get_enum("history-storage")
        history_combo.set_active_id(str(storage))

        self.__populars_count = builder.get_object("populars_count")
        if start_page == "popular":
            self.__populars_count.show()
        max_popular_items = El().settings.get_value(
                                              "max-popular-items").get_int32()
        builder.get_object("popular_spin_button").set_value(max_popular_items)
        remember_passwords = builder.get_object("remember_passwords_check")
        remember_passwords.set_active(
                                El().settings.get_value("remember-passwords"))

        tracking_check = builder.get_object("tracking_check")
        tracking_check.set_active(
                                El().settings.get_value("do-not-track"))
        self.__result_label = builder.get_object("result_label")
        self.__sync_button = builder.get_object("sync_button")
        self.__login_entry = builder.get_object("login_entry")
        self.__password_entry = builder.get_object("password_entry")
        self.__result_image = builder.get_object("result_image")
        builder.connect_signals(self)
        self.__helper.get_sync(self.__on_get_sync)

        thread = Thread(target=self.__get_sync_status)
        thread.daemon = True
        thread.start()

    def show(self):
        """
            Show dialog
        """
        self.__settings_dialog.show()

#######################
# PROTECTED           #
#######################
    def _on_popular_spin_value_changed(self, button):
        """
            Save value
            @param button as Gtk.SpinButton
        """
        value = GLib.Variant("i", button.get_value())
        El().settings.set_value("max-popular-items", value)

    def _on_configure_engines_clicked(self, button):
        """
            Show Web engines configurator
            @param button as Gtk.Button
        """
        from eolie.dialog_search_engine import SearchEngineDialog
        dialog = SearchEngineDialog(self.__settings_dialog)
        dialog.run()

    def _on_clear_personnal_data_clicked(self, button):
        """
            Show clear personnal data dialog
            @param button as Gtk.button
        """
        from eolie.dialog_clear_data import ClearDataDialog
        dialog = ClearDataDialog(self.__settings_dialog)
        dialog.run()

    def _on_manage_cookies_clicked(self, button):
        """
            Show cookies popover
            @param button as Gtk.button
        """
        from eolie.popover_cookies import CookiesPopover
        popover = CookiesPopover()
        popover.populate()
        popover.set_relative_to(button)
        popover.popup()

    def _on_manage_passwords_clicked(self, button):
        """
            Launch searhorse
            @param button as Gtk.Button
        """
        from eolie.popover_passwords import PasswordsPopover
        popover = PasswordsPopover()
        popover.populate()
        popover.set_relative_to(button)
        popover.popup()

    def _on_tracking_toggled(self, button):
        """
            Save state
            @param button as Gtk.ToggleButton
        """
        El().settings.set_value("do-not-track",
                                GLib.Variant("b", button.get_active()))

    def _on_cookies_changed(self, combo):
        """
            Save cookies setting
            @param combo as Gtk.ComboBoxText
        """
        El().settings.set_enum("cookie-storage", int(combo.get_active_id()))
        for window in El().windows:
            for view in window.container.views:
                context = view.webview.get_context()
                cookie_manager = context.get_cookie_manager()
                cookie_manager.set_accept_policy(
                                     El().settings.get_enum("cookie-storage"))

    def _on_history_changed(self, combo):
        """
            Save history keep setting
            @param combo as Gtk.ComboBoxText
        """
        El().settings.set_enum("history-storage", int(combo.get_active_id()))

    def _on_default_zoom_changed(self, button):
        """
            Save size
            @param button as Gtk.SpinButton
        """
        monitor_model = get_current_monitor_model(
                                    self.__settings_dialog.get_transient_for())
        try:
            # Add current value less monitor model
            zoom_levels = []
            for zoom_level in El().settings.get_value("default-zoom-level"):
                zoom_splited = zoom_level.split('@')
                if zoom_splited[0] == monitor_model:
                    continue
                else:
                    zoom_levels.append("%s@%s" % (zoom_splited[0],
                                                  zoom_splited[1]))
            # Add new zoom value for monitor model
            zoom_levels.append("%s@%s" % (monitor_model, button.get_value()))
            El().settings.set_value("default-zoom-level",
                                    GLib.Variant("as", zoom_levels))
            for window in El().windows:
                window.update_zoom_level(True)
        except Exception as e:
            print("SettingsDialog::_on_default_zoom_changed():", e)

    def _on_min_font_size_changed(self, button):
        """
            Save size
            @param button as Gtk.SpinButton
        """
        value = GLib.Variant("i", button.get_value())
        El().settings.set_value("min-font-size", value)
        El().set_setting("minimum-font-size", button.get_value())

    def _on_system_fonts_toggled(self, button):
        """
            Save state
            @param button as Gtk.ToggleButton
        """
        self.__fonts_grid.set_sensitive(not button.get_active())
        El().settings.set_value("use-system-fonts",
                                GLib.Variant("b", button.get_active()))

    def _on_font_sans_serif_set(self, fontbutton):
        """
            Save font setting
            @param fontchooser as Gtk.FontButton
        """
        value = GLib.Variant("s", fontbutton.get_font_name())
        El().settings.set_value("font-sans-serif", value)
        El().set_setting("sans-serif-font-family", fontbutton.get_font_name())

    def _on_font_serif_set(self, fontbutton):
        """
            Save font setting
            @param fontchooser as Gtk.FontButton
        """
        value = GLib.Variant("s", fontbutton.get_font_name())
        El().settings.set_value("font-serif", value)
        El().set_setting("serif-font-family", fontbutton.get_font_name())

    def _on_font_monospace_set(self, fontbutton):
        """
            Save font setting
            @param fontchooser as Gtk.FontButton
        """
        value = GLib.Variant("s", fontbutton.get_font_name())
        El().settings.set_value("font-monospace", value)
        El().set_setting("monospace-font-family", fontbutton.get_font_name())

    def _on_plugins_toggled(self, button):
        """
            Save state
            @param button as Gtk.ToggleButton
        """
        value = GLib.Variant("b", button.get_active())
        El().settings.set_value("enable-plugins", value)
        El().set_setting("enable-plugins", button.get_active())

    def _on_remember_passwords_toggled(self, button):
        """
            Save state
            @param button as Gtk.ToggleButton
        """
        El().settings.set_value("remember-passwords",
                                GLib.Variant("b", button.get_active()))

    def _on_remember_sessions_toggled(self, button):
        """
            Save state
            @param button as Gtk.ToggleButton
        """
        El().settings.set_value("remember-session",
                                GLib.Variant("b", button.get_active()))

    def _on_start_page_uri_changed(self, entry):
        """
            Save startup page
            @param entry as Gtk.Entry
        """
        El().settings.set_value("start-page",
                                GLib.Variant("s", entry.get_text()))

    def _on_start_changed(self, combo):
        """
            Save startup page
            @param combo as Gtk.ComboBoxText
        """
        self.__start_page_uri.hide()
        self.__populars_count.hide()
        if combo.get_active_id() == "address":
            self.__start_page_uri.show()
        elif combo.get_active_id() == "popular":
            self.__populars_count.show()
        El().settings.set_value("start-page",
                                GLib.Variant("s", combo.get_active_id()))

    def _on_engine_changed(self, combo):
        """
            Save engine
            @param combo as Gtk.ComboBoxText
        """
        El().settings.set_value("search-engine",
                                GLib.Variant("s", combo.get_active_id()))
        El().search.update_default_engine()

    def _on_open_downloads_toggled(self, button):
        """
            Save state
            @param button as Gtk.ToggleButton
        """
        El().settings.set_value("open-downloads",
                                GLib.Variant("b", button.get_active()))

    def _on_selection_changed(self, chooser):
        """
            Save uri
            @chooser as Gtk.FileChooserButton
        """
        uri = chooser.get_uri()
        if uri is None:
            uri = ""
        El().settings.set_value("download-uri", GLib.Variant("s", uri))

    def _on_key_release_event(self, widget, event):
        """
            Destroy window if Esc
            @param widget as Gtk.Widget
            @param event as Gdk.event
        """
        if event.keyval == Gdk.KEY_Escape:
            self.__settings_dialog.destroy()

    def _on_sync_button_clicked(self, button):
        """
            Connect to Mozilla Sync to get tokens
            @param button as Gtk.Button
        """
        icon_name = self.__result_image.get_icon_name()[0]
        if icon_name == "network-transmit-receive-symbolic":
            El().sync_worker.stop(True)
            El().sync_worker.delete_secret()
            self.__setup_sync_button(False)
        else:
            El().sync_worker.delete_secret()
            self.__result_label.set_text(_("Connecting…"))
            button.set_sensitive(False)
            self.__result_image.set_from_icon_name("content-loading-symbolic",
                                                   Gtk.IconSize.MENU)
            thread = Thread(target=self.__connect_mozilla_sync,
                            args=(self.__login_entry.get_text(),
                                  self.__password_entry.get_text()))
            thread.daemon = True
            thread.start()

#######################
# PRIVATE             #
#######################
    def __get_sync_status(self):
        """
            Get sync status
            @thread safe
        """
        if El().sync_worker is not None:
            status = El().sync_worker.status
            GLib.idle_add(self.__setup_sync_button, status)
        else:
            GLib.idle_add(self.__missing_fxa)

    def __setup_sync_button(self, status):
        """
            Setup sync button based on current sync status
            @param status as bool
        """
        self.__sync_button.set_sensitive(True)
        self.__sync_button.get_style_context().remove_class(
                                                          "destructive-action")
        self.__sync_button.get_style_context().remove_class(
                                                          "suggested-action")
        if status:
            self.__result_label.set_text(_("Synchronization is working"))
            self.__result_image.set_from_icon_name(
                                     "network-transmit-receive-symbolic",
                                     Gtk.IconSize.MENU)
            self.__sync_button.get_style_context().add_class(
                                                      "destructive-action")
            self.__sync_button.set_label(_("Cancel synchronization"))
        else:
            self.__result_label.set_text(
                                       _("Synchronization is not working"))
            self.__result_image.set_from_icon_name(
                                     "computer-fail-symbolic",
                                     Gtk.IconSize.MENU)
            self.__sync_button.get_style_context().add_class(
                                                      "suggested-action")
            self.__sync_button.set_label(_("Allow synchronization"))

    def __missing_fxa(self):
        """
            Show a message about missing fxa module
        """
        try:
            from eolie.mozilla_sync import SyncWorker
            SyncWorker  # Just make PEP8 happy
        except Exception as e:
            self.__result_label.set_text(
                  _("Synchronization is not available"
                    " on your computer:\n %s") % e)
            self.__sync_button.set_sensitive(False)

    def __connect_mozilla_sync(self, username, password):
        """
            Connect to mozilla sync
            @param username as str
            @param password as str
            @thread safe
        """
        try:
            El().sync_worker.login({"login": username}, password)
            GLib.idle_add(self.__setup_sync_button, True)
        except Exception as e:
            print("SettingsDialog::__connect_mozilla_sync():", e)
            GLib.idle_add(self.__sync_button.set_sensitive, True)
            if str(e) == "Unverified account":
                GLib.timeout_add(1000, self.__settings_dialog.destroy)
                # Try to go to webmail
                split = username.split("@")
                GLib.idle_add(El().active_window.container.add_webview,
                              "https://%s" % split[1],
                              Gdk.WindowType.CHILD)
                GLib.idle_add(
                    El().active_window.toolbar.title.show_message,
                    El().active_window.container.current.webview,
                    _("You've received an email"
                      " to validate synchronization"))
                self.__helper.store_sync(username,
                                         password,
                                         "",
                                         "",
                                         "",
                                         El().sync_worker.on_password_stored,
                                         False)
            else:
                GLib.idle_add(self.__result_label.set_text, str(e))
                GLib.idle_add(self.__result_image.set_from_icon_name,
                              "computer-fail-symbolic",
                              Gtk.IconSize.MENU)

    def __on_get_sync(self, attributes, password, uri, index, count):
        """
            Set username and password
            @param attributes as {}
            @param password as str
            @param uri as None
            @param index as int
            @param count as int
        """
        if attributes is None:
            return
        try:
            self.__login_entry.set_text(attributes["login"])
            self.__password_entry.set_text(password)
        except Exception as e:
            print("SettingsDialog::__on_get_sync()", e)
예제 #28
0
class SyncWorker(GObject.GObject):
    """
       Manage sync with mozilla server, will start syncing on init
    """
    __gsignals__ = {"sync-finished": (GObject.SignalFlags.RUN_FIRST, None, ())}

    def __init__(self):
        """
            Init worker
        """
        GObject.GObject.__init__(self)
        self.__stop = True
        self.__username = ""
        self.__password = ""
        self.__mtimes = {"bookmarks": 0.1, "history": 0.1}
        self.__mozilla_sync = MozillaSync()
        self.__session = None
        self.__helper = PasswordsHelper()

    def login(self, attributes, password, uri):
        """
            Login to service
            @param attributes as {}
            @param password as str
            @param uri as None
            @raise exceptions
        """
        if attributes is None:
            return
        keyB = ""
        session = None
        # Connect to mozilla sync
        session = self.__mozilla_sync.login(attributes["login"], password)
        bid_assertion, key = self.__mozilla_sync.get_browserid_assertion(
            session)
        keyB = base64.b64encode(session.keys[1]).decode("utf-8")
        # Store credentials
        if session is None:
            uid = ""
            token = ""
        else:
            uid = session.uid
            token = session.token
        self.__helper.store_sync(attributes["login"], password, uid, token,
                                 keyB, lambda x, y: self.sync(True))

    def sync(self, first_sync=False):
        """
            Start syncing, you need to check sync_status property
            @param first_sync as bool
        """
        if self.syncing or\
                not Gio.NetworkMonitor.get_default().get_network_available():
            return
        self.__username = ""
        self.__password = ""
        self.__stop = False
        # We force session reset to user last stored token
        if first_sync:
            self.__session = None
        self.__helper.get_sync(self.__start_sync, first_sync)

    def push_history(self, history_ids):
        """
            Push history ids
            @param history_ids as [int]
        """
        if Gio.NetworkMonitor.get_default().get_network_available():
            thread = Thread(target=self.__push_history, args=(history_ids, ))
            thread.daemon = True
            thread.start()

    def push_password(self, username, userform, password, passform, uri, uuid):
        """
            Push password
            @param username as str
            @param userform as str
            @param password as str
            @param passform as str
            @param uri as str
            @param uuid as str
        """
        if Gio.NetworkMonitor.get_default().get_network_available():
            thread = Thread(target=self.__push_password,
                            args=(username, userform, password, passform, uri,
                                  uuid))
            thread.daemon = True
            thread.start()

    def remove_from_history(self, guid):
        """
            Remove history id from remote history
            A first call to sync() is needed to populate secrets
            @param guid as str
        """
        if Gio.NetworkMonitor.get_default().get_network_available():
            thread = Thread(target=self.__remove_from_history, args=(guid, ))
            thread.daemon = True
            thread.start()

    def remove_from_passwords(self, uri):
        """
            Remove password from passwords collection
            @param uri as str
        """
        if Gio.NetworkMonitor.get_default().get_network_available():
            self.__helper.get(uri, self.__remove_from_passwords_thread)

    def delete_secret(self):
        """
            Delete sync secret
        """
        self.__username = ""
        self.__password = ""
        self.__session = None
        self.__stop = True
        self.__helper.clear_sync()

    def stop(self):
        """
            Stop update
        """
        self.__stop = True

    @property
    def mtimes(self):
        """
            Sync engine modification times
            @return {}
        """
        return self.__mtimes

    @property
    def syncing(self):
        """
            True if sync is running
            @return bool
        """
        return not self.__stop

    @property
    def status(self):
        """
            True if sync is working
            @return bool
        """
        try:
            self.__mozilla_sync.client.info_collections()
            return True
        except:
            return False

    @property
    def username(self):
        """
            Get username
            @return str
        """
        return self.__username


#######################
# PRIVATE             #
#######################

    def __get_session_bulk_keys(self):
        """
            Get session decrypt keys
            @return keys as (b"", b"")
        """
        if self.__session is None:
            self.__session = FxASession(
                self.__mozilla_sync.fxa_client, self.__username,
                quick_stretch_password(self.__username, self.__password),
                self.__uid, self.__token)
            self.__session.keys = [b"", self.__keyB]
        self.__session.check_session_status()
        bid_assertion, key = self.__mozilla_sync.get_browserid_assertion(
            self.__session)
        bulk_keys = self.__mozilla_sync.connect(bid_assertion, key)
        return bulk_keys

    def __push_history(self, history_ids):
        """
            Push history ids if atime is available, else, ask to remove
            @param history ids as [int]
        """
        if not self.__username or not self.__password:
            return
        try:
            bulk_keys = self.__get_session_bulk_keys()
            for history_id in history_ids:
                sleep(0.01)
                record = {}
                atimes = El().history.get_atimes(history_id)
                guid = El().history.get_guid(history_id)
                if atimes:
                    record["histUri"] = El().history.get_uri(history_id)
                    record["id"] = guid
                    record["title"] = El().history.get_title(history_id)
                    record["visits"] = []
                    for atime in atimes:
                        record["visits"].append({
                            "date": atime * 1000000,
                            "type": 1
                        })
                    debug("pushing %s" % record)
                    self.__mozilla_sync.add(record, "history", bulk_keys)
                else:
                    record["id"] = guid
                    record["type"] = "item"
                    record["deleted"] = True
                    debug("deleting %s" % record)
                    self.__mozilla_sync.add(record, "history", bulk_keys)
                self.__mtimes = self.__mozilla_sync.client.info_collections()
                dump(self.__mtimes, open(LOCAL_PATH + "/mozilla_sync.bin",
                                         "wb"))
        except Exception as e:
            print("SyncWorker::__push_history():", e)

    def __push_password(self, username, userform, password, passform, uri,
                        uuid):
        """
            Push password
            @param username as str
            @param userform as str
            @param password as str
            @param passform as str
            @param uri as str
            @param uuid as str
        """
        if not self.__username or not self.__password:
            return
        try:
            bulk_keys = self.__get_session_bulk_keys()
            record = {}
            record["id"] = "{%s}" % uuid
            record["hostname"] = uri
            record["formSubmitURL"] = uri
            record["httpRealm"] = None
            record["username"] = username
            record["password"] = password
            record["usernameField"] = userform
            record["passwordField"] = passform
            mtime = int(time() * 1000)
            record["timeCreated"] = mtime
            record["timePasswordChanged"] = mtime
            debug("pushing %s" % record)
            self.__mozilla_sync.add(record, "passwords", bulk_keys)
        except Exception as e:
            print("SyncWorker::__push_password():", e)

    def __remove_from_history(self, guid):
        """
            Remove from history
            @param guid as str
        """
        if not self.__username or not self.__password:
            return
        try:
            bulk_keys = self.__get_session_bulk_keys()
            record = {}
            record["id"] = guid
            record["type"] = "item"
            record["deleted"] = True
            debug("deleting %s" % record)
            self.__mozilla_sync.add(record, "history", bulk_keys)
        except Exception as e:
            print("SyncWorker::__remove_from_history():", e)

    def __remove_from_passwords(self, attributes, password, uri):
        """
            Remove password from passwords collection
            @param attributes as {}
            @param password as str
            @param uri as str
        """
        if not self.__username or not self.__password:
            return
        try:
            bulk_keys = self.__get_session_bulk_keys()
            record = {}
            record["id"] = attributes["uuid"]
            record["deleted"] = True
            debug("deleting %s" % record)
            self.__mozilla_sync.add(record, "passwords", bulk_keys)
            self.__helper.clear(uri)
        except Exception as e:
            print("SyncWorker::__remove_from_passwords():", e)

    def __remove_from_passwords_thread(self, attributes, password, uri):
        """
            Remove password from passwords collection
            @param attributes as {}
            @param password as str
            @param uri as str
        """
        thread = Thread(target=self.__remove_from_passwords,
                        args=(attributes, password, uri))
        thread.daemon = True
        thread.start()

    def __sync(self, first_sync):
        """
            Sync Eolie objects (bookmarks, history, ...) with Mozilla Sync
            @param first_sync as bool
        """
        debug("Start syncing")
        if not self.__username or not self.__password:
            self.__stop = True
            return
        try:
            self.__mtimes = load(open(LOCAL_PATH + "/mozilla_sync.bin", "rb"))
        except:
            self.__mtimes = {
                "bookmarks": 0.1,
                "history": 0.1,
                "passwords": 0.1
            }
        try:
            bulk_keys = self.__get_session_bulk_keys()
            new_mtimes = self.__mozilla_sync.client.info_collections()

            if self.__stop:
                return

            ######################
            # Passwords Management #
            ######################
            debug("local passwords: %s, remote passwords: %s" %
                  (self.__mtimes["passwords"], new_mtimes["passwords"]))
            # Only pull if something new available
            if self.__mtimes["passwords"] != new_mtimes["passwords"]:
                self.__pull_passwords(bulk_keys)

            if self.__stop:
                return
            ######################
            # History Management #
            ######################
            debug("local history: %s, remote history: %s" %
                  (self.__mtimes["history"], new_mtimes["history"]))
            # Only pull if something new available
            if self.__mtimes["history"] != new_mtimes["history"]:
                self.__pull_history(bulk_keys)

            if self.__stop:
                return
            ########################
            # Bookmarks Management #
            ########################
            debug("local bookmarks: %s, remote bookmarks: %s" %
                  (self.__mtimes["bookmarks"], new_mtimes["bookmarks"]))
            # Push new bookmarks
            self.__push_bookmarks(bulk_keys)

            if self.__stop:
                return

            # Only pull if something new available
            if self.__mtimes["bookmarks"] != new_mtimes["bookmarks"]:
                self.__pull_bookmarks(bulk_keys, first_sync)
            # Update last sync mtime
            self.__mtimes = self.__mozilla_sync.client.info_collections()
            dump(self.__mtimes, open(LOCAL_PATH + "/mozilla_sync.bin", "wb"))
            debug("Stop syncing")
            GLib.idle_add(self.emit, "sync-finished")
        except Exception as e:
            print("SyncWorker::__sync():", e)
            if str(e) == "The authentication token could not be found":
                self.__helper.get_sync(self.login)
        self.__stop = True

    def __push_bookmarks(self, bulk_keys):
        """
            Push to bookmarks
            @param bulk keys as KeyBundle
            @param start time as float
            @raise StopIteration
        """
        debug("push bookmarks")
        parents = []
        for bookmark_id in El().bookmarks.get_ids_for_mtime(
                self.__mtimes["bookmarks"]):
            if self.__stop:
                raise StopIteration("Cancelled")
            sleep(0.01)
            parent_guid = El().bookmarks.get_parent_guid(bookmark_id)
            # No parent, move it to unfiled
            if parent_guid is None:
                parent_guid = "unfiled"
            parent_id = El().bookmarks.get_id_by_guid(parent_guid)
            if parent_id not in parents:
                parents.append(parent_id)
            record = {}
            record["bmkUri"] = El().bookmarks.get_uri(bookmark_id)
            record["id"] = El().bookmarks.get_guid(bookmark_id)
            record["title"] = El().bookmarks.get_title(bookmark_id)
            record["tags"] = El().bookmarks.get_tags(bookmark_id)
            record["parentid"] = parent_guid
            record["type"] = "bookmark"
            debug("pushing %s" % record)
            self.__mozilla_sync.add(record, "bookmarks", bulk_keys)
        # Del old bookmarks
        for bookmark_id in El().bookmarks.get_deleted_ids():
            if self.__stop:
                raise StopIteration("Cancelled")
            sleep(0.01)
            parent_guid = El().bookmarks.get_parent_guid(bookmark_id)
            parent_id = El().bookmarks.get_id_by_guid(parent_guid)
            if parent_id not in parents:
                parents.append(parent_id)
            record = {}
            record["id"] = El().bookmarks.get_guid(bookmark_id)
            record["type"] = "item"
            record["deleted"] = True
            debug("deleting %s" % record)
            self.__mozilla_sync.add(record, "bookmarks", bulk_keys)
            El().bookmarks.remove(bookmark_id)
        # Push parents in this order, parents near root are handled later
        # Otherwise, order will be broken by new children updates
        while parents:
            parent_id = parents.pop(0)
            parent_guid = El().bookmarks.get_guid(parent_id)
            parent_name = El().bookmarks.get_title(parent_id)
            children = El().bookmarks.get_children(parent_guid)
            # So search if children in parents
            found = False
            for child_guid in children:
                child_id = El().bookmarks.get_id_by_guid(child_guid)
                if child_id in parents:
                    found = True
                    break
            # Handle children first
            if found:
                parents.append(parent_id)
                debug("later: %s" % parent_name)
                continue
            record = {}
            record["id"] = parent_guid
            record["type"] = "folder"
            # A parent with parent as unfiled needs to be moved to places
            # Firefox internal
            grand_parent_guid = El().bookmarks.get_parent_guid(parent_id)
            if grand_parent_guid == "unfiled":
                grand_parent_guid = "places"
            record["parentid"] = grand_parent_guid
            record["parentName"] = El().bookmarks.get_parent_name(parent_id)
            record["title"] = parent_name
            record["children"] = children
            debug("pushing parent %s" % record)
            self.__mozilla_sync.add(record, "bookmarks", bulk_keys)
        El().bookmarks.clean_tags()

    def __pull_bookmarks(self, bulk_keys, first_sync):
        """
            Pull from bookmarks
            @param bulk_keys as KeyBundle
            @param first_sync as bool
            @raise StopIteration
        """
        debug("pull bookmarks")
        SqlCursor.add(El().bookmarks)
        records = self.__mozilla_sync.get_records("bookmarks", bulk_keys)
        # We get all guids here and remove them while sync
        # At the end, we have deleted records
        # On fist sync, keep all
        if first_sync:
            to_delete = []
        else:
            to_delete = El().bookmarks.get_guids()
        for record in records:
            if self.__stop:
                raise StopIteration("Cancelled")
            sleep(0.01)
            bookmark = record["payload"]
            if "type" not in bookmark.keys() or\
                    bookmark["type"] not in ["folder", "bookmark"]:
                continue
            bookmark_id = El().bookmarks.get_id_by_guid(bookmark["id"])
            # This bookmark exists, remove from to delete
            if bookmark["id"] in to_delete:
                to_delete.remove(bookmark["id"])
            # Nothing to apply, continue
            if El().bookmarks.get_mtime(bookmark_id) >= record["modified"]:
                continue
            debug("pulling %s" % record)
            if bookmark_id is None:
                if "bmkUri" in bookmark.keys():
                    # Use parent name if no bookmarks tags
                    if "tags" not in bookmark.keys() or\
                            not bookmark["tags"]:
                        if "parentName" in bookmark.keys() and\
                                bookmark["parentName"]:
                            bookmark["tags"] = [bookmark["parentName"]]
                        else:
                            bookmark["tags"] = []
                    bookmark_id = El().bookmarks.add(bookmark["title"],
                                                     bookmark["bmkUri"],
                                                     bookmark["id"],
                                                     bookmark["tags"], False)
                else:
                    bookmark["tags"] = []
                    bookmark_id = El().bookmarks.add(bookmark["title"],
                                                     bookmark["id"],
                                                     bookmark["id"],
                                                     bookmark["tags"], False)
            else:
                El().bookmarks.set_title(bookmark_id, bookmark["title"], False)
                if "bmkUri" in bookmark.keys():
                    El().bookmarks.set_uri(bookmark_id, bookmark["bmkUri"],
                                           False)
                elif "children" in bookmark.keys():
                    position = 0
                    for child in bookmark["children"]:
                        bid = El().bookmarks.get_id_by_guid(child)
                        El().bookmarks.set_position(bid, position, False)
                        position += 1
                # Remove previous tags
                current_tags = El().bookmarks.get_tags(bookmark_id)
                for tag in El().bookmarks.get_tags(bookmark_id):
                    if "tags" in bookmark.keys() and\
                            tag not in bookmark["tags"]:
                        tag_id = El().bookmarks.get_tag_id(tag)
                        current_tags.remove(tag)
                        El().bookmarks.del_tag_from(tag_id, bookmark_id, False)
                if "tags" in bookmark.keys():
                    for tag in bookmark["tags"]:
                        # Tag already associated
                        if tag in current_tags:
                            continue
                        tag_id = El().bookmarks.get_tag_id(tag)
                        if tag_id is None:
                            tag_id = El().bookmarks.add_tag(tag, False)
                        El().bookmarks.add_tag_to(tag_id, bookmark_id, False)
            El().bookmarks.set_mtime(bookmark_id, record["modified"], False)
            if "parentName" in bookmark.keys():
                El().bookmarks.set_parent(bookmark_id, bookmark["parentid"],
                                          bookmark["parentName"], False)
        for guid in to_delete:
            if self.__stop:
                raise StopIteration("Cancelled")
            debug("deleting: %s" % guid)
            bookmark_id = El().bookmarks.get_id_by_guid(guid)
            if bookmark_id is not None:
                El().bookmarks.remove(bookmark_id, False)
        El().bookmarks.clean_tags()  # Will commit
        SqlCursor.remove(El().bookmarks)

    def __pull_passwords(self, bulk_keys):
        """
            Pull from passwords
            @param bulk_keys as KeyBundle
            @raise StopIteration
        """
        debug("pull passwords")
        records = self.__mozilla_sync.get_records("passwords", bulk_keys)
        for record in records:
            if self.__stop:
                raise StopIteration("Cancelled")
            sleep(0.01)
            debug("pulling %s" % record)
            password = record["payload"]
            if "formSubmitURL" in password.keys():
                self.__helper.clear(password["formSubmitURL"])
                self.__helper.store(password["username"], password["password"],
                                    password["formSubmitURL"], password["id"],
                                    None)
            elif "deleted" in password.keys():  # We assume True
                self.__helper.clear(password["id"])

    def __pull_history(self, bulk_keys):
        """
            Pull from history
            @param bulk_keys as KeyBundle
            @raise StopIteration
        """
        debug("pull history")
        records = self.__mozilla_sync.get_records("history", bulk_keys)
        for record in records:
            if self.__stop:
                raise StopIteration("Cancelled")
            sleep(0.01)
            El().history.thread_lock.acquire()
            history = record["payload"]
            keys = history.keys()
            # Ignore pages without a title
            if "title" not in keys or not history["title"]:
                El().history.thread_lock.release()
                continue
            # Ignore pages without an uri (deleted)
            if "histUri" not in keys:
                El().history.thread_lock.release()
                continue
            history_id = El().history.get_id_by_guid(history["id"])
            # Nothing to apply, continue
            if El().history.get_mtime(history_id) >= record["modified"]:
                El().history.thread_lock.release()
                continue
            # Try to get visit date
            atimes = []
            try:
                for visit in history["visits"]:
                    atimes.append(round(int(visit["date"]) / 1000000, 2))
            except:
                El().history.thread_lock.release()
                continue
            debug("pulling %s" % record)
            title = history["title"].rstrip().lstrip()
            history_id = El().history.add(title, history["histUri"],
                                          record["modified"], history["id"],
                                          atimes, True)
            El().history.thread_lock.release()

    def __start_sync(self, attributes, password, uri, first_sync):
        """
            Set params and start sync
            @param attributes as {}
            @param password as str
            @param uri as None
            @param first_sync as bool
        """
        if attributes is None:
            return
        try:
            self.__username = attributes["login"]
            self.__password = password
            self.__token = attributes["token"]
            self.__uid = attributes["uid"]
            self.__keyB = base64.b64decode(attributes["keyB"])
            if Gio.NetworkMonitor.get_default().get_network_available():
                thread = Thread(target=self.__sync, args=(first_sync, ))
                thread.daemon = True
                thread.start()
        except Exception as e:
            print("SyncWorker::__start_sync()", e)
예제 #29
0
class CredentialsPopover(Gtk.Popover):
    """
        Tell user to save form credentials
    """
    def __init__(self, username, userform, password, passform, uri):
        """
            Init popover
            @param username as str
            @param password as str
            @param netloc as str
        """
        Gtk.Popover.__init__(self)
        self.__helper = PasswordsHelper()
        self.__username = username
        self.__userform = userform
        self.__password = password
        self.__passform = passform
        self.__uri = uri
        self.__uuid = None
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/PopoverCredentials.ui')
        builder.connect_signals(self)
        self.__label = builder.get_object('label')
        parsed = urlparse(uri)
        builder.get_object('uri').set_text(parsed.netloc)
        builder.get_object('username').set_text(username)
        builder.get_object('password').set_text(password)
        self.add(builder.get_object('widget'))

#######################
# PROTECTED           #
#######################

    def _on_save_clicked(self, button):
        """
            Save username and password
            @param button as Gtk.Button
        """
        try:
            parsed = urlparse(self.__uri)
            uri = "%s://%s" % (parsed.scheme, parsed.netloc)
            if self.__uuid is None:
                self.__uuid = str(uuid3(NAMESPACE_DNS, parsed.netloc))
            else:
                self.__helper.clear(self.__uuid)
            self.__helper.store(self.__username, self.__password, uri,
                                self.__uuid, None)
            if El().sync_worker is not None:
                El().sync_worker.push_password(self.__username,
                                               self.__userform,
                                               self.__password,
                                               self.__passform, uri,
                                               self.__uuid)
            self.destroy()
        except Exception as e:
            print("CredentialsPopover::_on_save_clicked()", e)

    def show(self):
        """
            Overwrite show
        """
        self.__helper.get(self.__uri, self.__on_get_password)

#######################
# PRIVATE             #
#######################

    def __on_get_password(self, attributes, password, uri):
        """
            Set username/password input
            @param attributes as {}
            @param password as str
            @param uri as str
        """
        try:
            if attributes is None:
                Gtk.Popover.show(self)
            elif attributes["login"] == self.__username and\
                    self.__password == password:
                self.emit("closed")
            else:
                Gtk.Popover.show(self)
                self.__uuid = attributes["uuid"]
                self.__label.set_text(
                    _("Do you want to modify this password?"))
        except Exception as e:
            print("CredentialsPopover::__on_get_password()", e)