Exemplo n.º 1
0
 def on_lock_button_clicked(self, button):
     logger.debug("in on_lock_button_clicked")
     loop = self.backing_volume.udisks_object.get_loop()
     if loop:
         # Ensure that the loop device is removed after locking the volume
         loop.call_set_autoclear_sync(
             True,
             GLib.Variant('a{sv}', {}),  # options
             None)  # cancellable
     try:
         self.unmount()
         self.backing_volume.lock()
     except GLib.Error as e:
         # Show a more helpful message for the known error cases
         if e.domain == "udisks-error-quark" and e.code == UDisks.Error.DEVICE_BUSY:
             body = _(
                 "One or more applications are keeping the volume busy.")
         # Show a general error message and print the detailed, technical
         # message in unknown error cases
         else:
             # Translators: Don't translate {volume_name} or {error_message},
             # they are placeholder and will be replaced.
             body = _(
                 "Couldn't lock volume {volume_name}:\n{error_message}".
                 format(volume_name=self.name, error_message=e.message))
         self.manager.show_warning(_("Locking the volume failed"), body)
         return
Exemplo n.º 2
0
        def mount_cb(gio_volume: Gio.Volume, result: Gio.AsyncResult):
            logger.debug("in mount_cb")
            self.hide_spinner()
            try:
                gio_volume.mount_finish(result)
            except GLib.Error as e:
                if e.code == Gio.IOErrorEnum.FAILED_HANDLED:
                    logger.warning("Couldn't unlock volume: %s:", e.message)
                    return

                logger.exception(e)

                if "No key available with this passphrase" in e.message or \
                   "No device header detected with this passphrase" in e.message:
                    title = _("Wrong passphrase or parameters")
                else:
                    title = _("Error unlocking volume")

                # Translators: Don't translate {volume_name} or {error_message},
                # they are placeholder and will be replaced.
                body = _("Couldn't unlock volume {volume_name}:\n{error_message}".format(volume_name=self.name, error_message=e.message))
                self.manager.show_warning(title, body)
                return
            finally:
                self.manager.mount_op_lock.release()

            if open_after_unlock:
                # The GVolume now changed from the loop device to the dm device, so
                # by also updating the udisks object we change this volume from the
                # crypto backing loop device to the unlocked device-mapper device,
                # which we can then open
                self.udisks_object = self._find_udisks_object()
                self.open()
Exemplo n.º 3
0
    def on_add_file_container_button_clicked(self, button, data=None):
        path = self.choose_container_path()

        if path in self.container_list.backing_file_paths:
            self.show_warning(
                title=_("Container already added"),
                body=_("The file container %s should already be listed.") %
                path)
            return

        if path:
            self.unlock_file_container(path)
Exemplo n.º 4
0
    def __init__(self, application: Gtk.Application):
        self.udisks_client = UDisks.Client.new_sync()
        self.udisks_manager = self.udisks_client.get_manager()
        self.gio_volume_monitor = Gio.VolumeMonitor.get()
        self.gio_volume_monitor.connect("volume-changed",
                                        self.on_volume_changed)
        self.gio_volume_monitor.connect("volume-added", self.on_volume_added)
        self.gio_volume_monitor.connect("volume-removed",
                                        self.on_volume_removed)
        self.udev_client = GUdev.Client()
        self.mount_op_lock = Lock()

        self.builder = Gtk.Builder.new_from_file(MAIN_UI_FILE)
        self.builder.set_translation_domain(TRANSLATION_DOMAIN)
        self.builder.connect_signals(self)

        self.window = self.builder.get_object(
            "window")  # type: Gtk.ApplicationWindow
        self.window.set_application(application)
        self.window.set_title(_("Unlock VeraCrypt Volumes"))

        self.container_list = ContainerList()
        self.device_list = DeviceList()

        containers_frame = self.builder.get_object("containers_frame")
        containers_frame.add(self.container_list.list_box)
        devices_frame = self.builder.get_object("devices_frame")
        devices_frame.add(self.device_list.list_box)

        self.add_tcrypt_volumes()

        logger.debug("showing window")
        self.window.show_all()
        self.window.present()
Exemplo n.º 5
0
 def name(self) -> str:
     """Short description for display to the user. The block device
     label or partition label, if any, plus the size"""
     block_label = self.udisks_object.get_block().props.id_label
     partition = self.udisks_object.get_partition()
     if block_label:
         # Translators: Don't translate {volume_label} or {volume_size},
         # they are placeholders and will be replaced.
         return _("{volume_label} ({volume_size})").format(volume_label=block_label,
                                                           volume_size=self.size_for_display)
     elif partition and partition.props.name:
         # Translators: Don't translate {partition_name} or {partition_size},
         # they are placeholders and will be replaced.
         return _("{partition_name} ({partition_size})").format(partition_name=partition.props.name,
                                                                partition_size=self.size_for_display)
     else:
         # Translators: Don't translate {volume_size}, it's a placeholder
         # and will be replaced.
         return _("{volume_size} Volume").format(volume_size=self.size_for_display)
Exemplo n.º 6
0
    def description(self) -> str:
        """Longer description for display to the user."""
        if self.udisks_object.get_block().props.read_only:
            # Translators: Don't translate {volume_name}, it's a placeholder and
            # will be replaced. It needs to be present in the translated string.
            desc = _("{volume_name} (Read-Only)").format(volume_name=self.name)
        else:
            desc = self.name

        if self.partition_table_object and self.partition_table_object.get_loop(
        ):
            # This is a partition of a loop device, so lets include the backing file name
            # Translators: Don't translate {partition_name} and {container_path}, they
            # are placeholders and will be replaced. They need to be present
            # in the translated string.
            return _("{partition_name} in {container_path}").format(
                partition_name=desc, container_path=self.backing_file_name)
        elif self.is_file_container:
            # This is file container, lets include the file name
            # Translators: Don't translate {volume_name} and {path_to_file_container},
            # they are placeholders and will be replaced. You should only have to translate
            # this string if it makes sense to reverse the order of the placeholders.
            return _("{volume_name} – {path_to_file_container}").format(
                volume_name=desc,
                path_to_file_container=self.backing_file_name)
        elif self.is_partition and self.drive_object:
            # This is a partition on a drive, lets include the drive name
            # Translators: Don't translate {partition_name} and {drive_name}, they
            # are placeholders and will be replaced. They need to be present
            # in the translated string.
            return _("{partition_name} on {drive_name}").format(
                partition_name=desc, drive_name=self.drive_name)
        elif self.drive_name:
            # This is probably an unpartitioned drive, so lets include the drive name
            # Translators: Don't translate {volume_name} and {drive_name},
            # they are placeholders and will be replaced. You should only have to translate
            # this string if it makes sense to reverse the order of the placeholders.
            return _("{volume_name} – {drive_name}").format(
                volume_name=desc, drive_name=self.drive_name)
        else:
            return desc
Exemplo n.º 7
0
    def attach_file_container(self, path: str) -> Union[Volume, None]:
        logger.debug("attaching file %s. backing_file_paths: %s", path,
                     self.container_list.backing_file_paths)
        warning = dict()

        try:
            fd = os.open(path, os.O_RDWR)
        except PermissionError as e:
            # Try opening read-only
            try:
                fd = os.open(path, os.O_RDONLY)
                warning["title"] = _("Container opened read-only")
                # Translators: Don't translate {path}, it's a placeholder  and will be replaced.
                warning["body"] = _(
                    "The file container {path} could not be opened with write access. "
                    "It was opened read-only instead. You will not be able to modify the "
                    "content of the container.\n"
                    "{error_message}").format(path=path, error_message=str(e))
            except PermissionError as e:
                self.show_warning(title=_("Error opening file"), body=str(e))
                return None

        fd_list = Gio.UnixFDList()
        fd_list.append(fd)
        udisks_path, __ = self.udisks_manager.call_loop_setup_sync(
            GLib.Variant('h', 0),  # fd index
            GLib.Variant('a{sv}', {}),  # options
            fd_list,  # the fd list
            None)  # cancellable
        logger.debug("Created loop device %s", udisks_path)

        volume = self._wait_for_loop_setup(path)
        if volume:
            if warning:
                self.show_warning(title=warning["title"], body=warning["body"])
            return volume
        elif not self._udisks_object_is_tcrypt(udisks_path):
            # Remove the loop device
            self.udisks_client.get_object(udisks_path).get_loop().call_delete(
                GLib.Variant('a{sv}', {}),  # options
                None,  # cancellable
                None,  # callback
                None)  # user data
            self.show_warning(
                title=_("Not a VeraCrypt container"),
                body=_(
                    "The file %s does not seem to be a VeraCrypt container.") %
                path)
        else:
            self.show_warning(
                title=_("Failed to add container"),
                body=
                _("Could not add file container %s: Timeout while waiting for loop setup."
                  "Please try using the <i>Disks</i> application instead.") %
                path)
Exemplo n.º 8
0
class ContainerList(VolumeList):
    """Manages attached file containers"""
    placeholder_label = _("No file containers added")

    @property
    def backing_file_paths(self) -> List[str]:
        return [volume.backing_file_name for volume in self.volumes]

    def find_by_backing_file(self, path: str) -> Union[Volume, None]:
        for volume in self.volumes:
            if volume.backing_file_name == path:
                return volume
        raise VolumeNotFoundError()
Exemplo n.º 9
0
    def choose_container_path(self):
        dialog = Gtk.FileChooserDialog(
            _("Choose File Container"), self.window,
            Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.ACCEPT))
        result = dialog.run()
        if result != Gtk.ResponseType.ACCEPT:
            dialog.destroy()
            return

        path = dialog.get_filename()
        dialog.destroy()
        return path
Exemplo n.º 10
0
class DeviceList(VolumeList):
    """Manages physically connected drives and partitions"""
    placeholder_label = _("No VeraCrypt devices detected")