Blame SOURCES/compress-dialog-Add-support-for-encrypted-.zip.patch

6a4a9c
From 98c79d46ab05bd86fc1309d9ae560edc19f62071 Mon Sep 17 00:00:00 2001
6a4a9c
From: Ondrej Holy <oholy@redhat.com>
6a4a9c
Date: Fri, 30 Jul 2021 10:52:55 +0200
6a4a9c
Subject: [PATCH] compress-dialog: Add support for encrypted .zip
6a4a9c
6a4a9c
Currently, it is not possible to create encrypted archives over
6a4a9c
Nautilus. Let's add support for encrypted .zip files to not have
6a4a9c
to install a dedicated archive manager.
6a4a9c
6a4a9c
Fixes: https://gitlab.gnome.org/GNOME/nautilus/-/issues/822
6a4a9c
---
6a4a9c
 data/org.gnome.nautilus.gschema.xml          |   1 +
6a4a9c
 meson.build                                  |   2 +-
6a4a9c
 src/nautilus-compress-dialog-controller.c    | 136 +++++++++++++++++++
6a4a9c
 src/nautilus-compress-dialog-controller.h    |   1 +
6a4a9c
 src/nautilus-file-operations.c               |   8 +-
6a4a9c
 src/nautilus-file-operations.h               |   1 +
6a4a9c
 src/nautilus-file-undo-operations.c          |   7 +-
6a4a9c
 src/nautilus-file-undo-operations.h          |   3 +-
6a4a9c
 src/nautilus-files-view.c                    |  10 ++
6a4a9c
 src/nautilus-global-preferences.h            |   3 +-
6a4a9c
 src/resources/css/nautilus.css               |   9 ++
6a4a9c
 src/resources/ui/nautilus-compress-dialog.ui |  57 ++++++++
6a4a9c
 12 files changed, 233 insertions(+), 5 deletions(-)
6a4a9c
6a4a9c
diff --git a/data/org.gnome.nautilus.gschema.xml b/data/org.gnome.nautilus.gschema.xml
6a4a9c
index 3f89466de..7585be8cd 100644
6a4a9c
--- a/data/org.gnome.nautilus.gschema.xml
6a4a9c
+++ b/data/org.gnome.nautilus.gschema.xml
6a4a9c
@@ -65,6 +65,7 @@
6a4a9c
     <value value="0" nick="zip"/>
6a4a9c
     <value value="1" nick="tar.xz"/>
6a4a9c
     <value value="2" nick="7z"/>
6a4a9c
+    <value value="3" nick="encrypted_zip"/>
6a4a9c
   </enum>
6a4a9c
 
6a4a9c
   <schema path="/org/gnome/nautilus/" id="org.gnome.nautilus" gettext-domain="nautilus">
6a4a9c
diff --git a/meson.build b/meson.build
6a4a9c
index d5316475d..446b25614 100644
6a4a9c
--- a/meson.build
6a4a9c
+++ b/meson.build
6a4a9c
@@ -117,7 +117,7 @@ gio = dependency('gio-2.0', version: glib_ver)
6a4a9c
 gio_unix = dependency('gio-unix-2.0', version: glib_ver)
6a4a9c
 glib = dependency('glib-2.0', version: glib_ver)
6a4a9c
 gmodule = dependency('gmodule-no-export-2.0', version: glib_ver)
6a4a9c
-gnome_autoar = dependency('gnome-autoar-0', version: '>= 0.3.0')
6a4a9c
+gnome_autoar = dependency('gnome-autoar-0', version: '>= 0.4.0')
6a4a9c
 gnome_desktop = dependency('gnome-desktop-3.0', version: '>= 3.0.0')
6a4a9c
 gtk = dependency('gtk+-3.0', version: '>= 3.22.27')
6a4a9c
 libhandy = dependency('libhandy-1', version: '>= 1.1.90')
6a4a9c
diff --git a/src/nautilus-compress-dialog-controller.c b/src/nautilus-compress-dialog-controller.c
6a4a9c
index 154573c0f..e1ba5a803 100644
6a4a9c
--- a/src/nautilus-compress-dialog-controller.c
6a4a9c
+++ b/src/nautilus-compress-dialog-controller.c
6a4a9c
@@ -32,17 +32,24 @@ struct _NautilusCompressDialogController
6a4a9c
     NautilusFileNameWidgetController parent_instance;
6a4a9c
 
6a4a9c
     GtkWidget *compress_dialog;
6a4a9c
+    GtkWidget *activate_button;
6a4a9c
+    GtkWidget *error_label;
6a4a9c
     GtkWidget *name_entry;
6a4a9c
     GtkWidget *extension_stack;
6a4a9c
     GtkWidget *zip_label;
6a4a9c
+    GtkWidget *encrypted_zip_label;
6a4a9c
     GtkWidget *tar_xz_label;
6a4a9c
     GtkWidget *seven_zip_label;
6a4a9c
     GtkWidget *extension_popover;
6a4a9c
     GtkWidget *zip_checkmark;
6a4a9c
+    GtkWidget *encrypted_zip_checkmark;
6a4a9c
     GtkWidget *tar_xz_checkmark;
6a4a9c
     GtkWidget *seven_zip_checkmark;
6a4a9c
+    GtkWidget *passphrase_label;
6a4a9c
+    GtkWidget *passphrase_entry;
6a4a9c
 
6a4a9c
     const char *extension;
6a4a9c
+    gchar *passphrase;
6a4a9c
 
6a4a9c
     gulong response_handler_id;
6a4a9c
 };
6a4a9c
@@ -142,6 +149,7 @@ update_selected_format (NautilusCompressDialogController *self,
6a4a9c
     const char *extension;
6a4a9c
     GtkWidget *active_label;
6a4a9c
     GtkWidget *active_checkmark;
6a4a9c
+    gboolean show_passphrase = FALSE;
6a4a9c
 
6a4a9c
     switch (format)
6a4a9c
     {
6a4a9c
@@ -153,6 +161,15 @@ update_selected_format (NautilusCompressDialogController *self,
6a4a9c
         }
6a4a9c
         break;
6a4a9c
 
6a4a9c
+        case NAUTILUS_COMPRESSION_ENCRYPTED_ZIP:
6a4a9c
+        {
6a4a9c
+            extension = ".zip";
6a4a9c
+            active_label = self->encrypted_zip_label;
6a4a9c
+            active_checkmark = self->encrypted_zip_checkmark;
6a4a9c
+            show_passphrase = TRUE;
6a4a9c
+        }
6a4a9c
+        break;
6a4a9c
+
6a4a9c
         case NAUTILUS_COMPRESSION_TAR_XZ:
6a4a9c
         {
6a4a9c
             extension = ".tar.xz";
6a4a9c
@@ -178,12 +195,26 @@ update_selected_format (NautilusCompressDialogController *self,
6a4a9c
 
6a4a9c
     self->extension = extension;
6a4a9c
 
6a4a9c
+    gtk_widget_set_visible (self->passphrase_label, show_passphrase);
6a4a9c
+    gtk_widget_set_visible (self->passphrase_entry, show_passphrase);
6a4a9c
+    if (!show_passphrase)
6a4a9c
+    {
6a4a9c
+        gtk_entry_set_text (GTK_ENTRY (self->passphrase_entry), "");
6a4a9c
+        gtk_entry_set_visibility (GTK_ENTRY (self->passphrase_entry), FALSE);
6a4a9c
+        gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->passphrase_entry),
6a4a9c
+                                           GTK_ENTRY_ICON_SECONDARY,
6a4a9c
+                                           "view-conceal");
6a4a9c
+    }
6a4a9c
+
6a4a9c
     gtk_stack_set_visible_child (GTK_STACK (self->extension_stack),
6a4a9c
                                  active_label);
6a4a9c
 
6a4a9c
     gtk_image_set_from_icon_name (GTK_IMAGE (self->zip_checkmark),
6a4a9c
                                   NULL,
6a4a9c
                                   GTK_ICON_SIZE_BUTTON);
6a4a9c
+    gtk_image_set_from_icon_name (GTK_IMAGE (self->encrypted_zip_checkmark),
6a4a9c
+                                  NULL,
6a4a9c
+                                  GTK_ICON_SIZE_BUTTON);
6a4a9c
     gtk_image_set_from_icon_name (GTK_IMAGE (self->tar_xz_checkmark),
6a4a9c
                                   NULL,
6a4a9c
                                   GTK_ICON_SIZE_BUTTON);
6a4a9c
@@ -200,6 +231,7 @@ update_selected_format (NautilusCompressDialogController *self,
6a4a9c
     /* Since the extension changes when the button is toggled, force a
6a4a9c
      * verification of the new file name by simulating an entry change
6a4a9c
      */
6a4a9c
+    gtk_widget_set_sensitive (self->activate_button, FALSE);
6a4a9c
     g_signal_emit_by_name (self->name_entry, "changed");
6a4a9c
 }
6a4a9c
 
6a4a9c
@@ -216,6 +248,19 @@ zip_row_on_activated (HdyActionRow *row,
6a4a9c
                             NAUTILUS_COMPRESSION_ZIP);
6a4a9c
 }
6a4a9c
 
6a4a9c
+static void
6a4a9c
+encrypted_zip_row_on_activated (HdyActionRow *row,
6a4a9c
+                                gpointer      user_data)
6a4a9c
+{
6a4a9c
+    NautilusCompressDialogController *controller;
6a4a9c
+
6a4a9c
+    controller = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
6a4a9c
+
6a4a9c
+    gtk_popover_popdown (GTK_POPOVER (controller->extension_popover));
6a4a9c
+    update_selected_format (controller,
6a4a9c
+                            NAUTILUS_COMPRESSION_ENCRYPTED_ZIP);
6a4a9c
+}
6a4a9c
+
6a4a9c
 static void
6a4a9c
 tar_xz_row_on_activated (HdyActionRow *row,
6a4a9c
                          gpointer      user_data)
6a4a9c
@@ -242,6 +287,67 @@ seven_zip_row_on_activated (HdyActionRow *row,
6a4a9c
                             NAUTILUS_COMPRESSION_7ZIP);
6a4a9c
 }
6a4a9c
 
6a4a9c
+static void
6a4a9c
+passphrase_entry_on_changed (GtkEditable *editable,
6a4a9c
+                             gpointer     user_data)
6a4a9c
+{
6a4a9c
+    NautilusCompressDialogController *self;
6a4a9c
+    const gchar *error_message;
6a4a9c
+
6a4a9c
+    self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
6a4a9c
+
6a4a9c
+    g_free (self->passphrase);
6a4a9c
+    self->passphrase = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->passphrase_entry)));
6a4a9c
+
6a4a9c
+    /* Simulate a change of the name_entry to ensure the correct sensitivity of
6a4a9c
+     * the activate_button, but only if the name_entry is valid in order to
6a4a9c
+     * avoid changes of the error_revealer.
6a4a9c
+     */
6a4a9c
+    error_message = gtk_label_get_text (GTK_LABEL (self->error_label));
6a4a9c
+    if (error_message[0] == '\0')
6a4a9c
+    {
6a4a9c
+        gtk_widget_set_sensitive (self->activate_button, FALSE);
6a4a9c
+        g_signal_emit_by_name (self->name_entry, "changed");
6a4a9c
+    }
6a4a9c
+}
6a4a9c
+
6a4a9c
+static void
6a4a9c
+passphrase_entry_on_icon_press (GtkEntry             *entry,
6a4a9c
+                                GtkEntryIconPosition  icon_pos,
6a4a9c
+                                GdkEvent             *event,
6a4a9c
+                                gpointer              user_data)
6a4a9c
+{
6a4a9c
+    NautilusCompressDialogController *self;
6a4a9c
+    gboolean visibility;
6a4a9c
+
6a4a9c
+    self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
6a4a9c
+    visibility = gtk_entry_get_visibility (GTK_ENTRY (self->passphrase_entry));
6a4a9c
+
6a4a9c
+    gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->passphrase_entry),
6a4a9c
+                                       GTK_ENTRY_ICON_SECONDARY,
6a4a9c
+                                       visibility ? "view-conceal" : "view-reveal");
6a4a9c
+    gtk_entry_set_visibility (GTK_ENTRY (self->passphrase_entry), !visibility);
6a4a9c
+}
6a4a9c
+
6a4a9c
+static void
6a4a9c
+activate_button_on_sensitive_notify (GObject    *gobject,
6a4a9c
+                                     GParamSpec *pspec,
6a4a9c
+                                     gpointer    user_data)
6a4a9c
+{
6a4a9c
+    NautilusCompressDialogController *self;
6a4a9c
+    NautilusCompressionFormat format;
6a4a9c
+
6a4a9c
+    self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
6a4a9c
+    format = g_settings_get_enum (nautilus_compression_preferences,
6a4a9c
+                                  NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT);
6a4a9c
+    if (format == NAUTILUS_COMPRESSION_ENCRYPTED_ZIP &&
6a4a9c
+        (self->passphrase == NULL || self->passphrase[0] == '\0'))
6a4a9c
+    {
6a4a9c
+        /* Reset sensitivity of the activate_button if password is not set. */
6a4a9c
+        gtk_widget_set_sensitive (self->activate_button, FALSE);
6a4a9c
+    }
6a4a9c
+}
6a4a9c
+
6a4a9c
 NautilusCompressDialogController *
6a4a9c
 nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
6a4a9c
                                          NautilusDirectory *destination_directory,
6a4a9c
@@ -256,12 +362,16 @@ nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
6a4a9c
     GtkWidget *activate_button;
6a4a9c
     GtkWidget *extension_stack;
6a4a9c
     GtkWidget *zip_label;
6a4a9c
+    GtkWidget *encrypted_zip_label;
6a4a9c
     GtkWidget *tar_xz_label;
6a4a9c
     GtkWidget *seven_zip_label;
6a4a9c
     GtkWidget *extension_popover;
6a4a9c
     GtkWidget *zip_checkmark;
6a4a9c
+    GtkWidget *encrypted_zip_checkmark;
6a4a9c
     GtkWidget *tar_xz_checkmark;
6a4a9c
     GtkWidget *seven_zip_checkmark;
6a4a9c
+    GtkWidget *passphrase_label;
6a4a9c
+    GtkWidget *passphrase_entry;
6a4a9c
     NautilusCompressionFormat format;
6a4a9c
 
6a4a9c
     builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-compress-dialog.ui");
6a4a9c
@@ -272,12 +382,16 @@ nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
6a4a9c
     activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "activate_button"));
6a4a9c
     extension_stack = GTK_WIDGET (gtk_builder_get_object (builder, "extension_stack"));
6a4a9c
     zip_label = GTK_WIDGET (gtk_builder_get_object (builder, "zip_label"));
6a4a9c
+    encrypted_zip_label = GTK_WIDGET (gtk_builder_get_object (builder, "encrypted_zip_label"));
6a4a9c
     tar_xz_label = GTK_WIDGET (gtk_builder_get_object (builder, "tar_xz_label"));
6a4a9c
     seven_zip_label = GTK_WIDGET (gtk_builder_get_object (builder, "seven_zip_label"));
6a4a9c
     extension_popover = GTK_WIDGET (gtk_builder_get_object (builder, "extension_popover"));
6a4a9c
     zip_checkmark = GTK_WIDGET (gtk_builder_get_object (builder, "zip_checkmark"));
6a4a9c
+    encrypted_zip_checkmark = GTK_WIDGET (gtk_builder_get_object (builder, "encrypted_zip_checkmark"));
6a4a9c
     tar_xz_checkmark = GTK_WIDGET (gtk_builder_get_object (builder, "tar_xz_checkmark"));
6a4a9c
     seven_zip_checkmark = GTK_WIDGET (gtk_builder_get_object (builder, "seven_zip_checkmark"));
6a4a9c
+    passphrase_label = GTK_WIDGET (gtk_builder_get_object (builder, "passphrase_label"));
6a4a9c
+    passphrase_entry = GTK_WIDGET (gtk_builder_get_object (builder, "passphrase_entry"));
6a4a9c
 
6a4a9c
     gtk_window_set_transient_for (GTK_WINDOW (compress_dialog),
6a4a9c
                                   parent_window);
6a4a9c
@@ -290,16 +404,22 @@ nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
6a4a9c
                          "containing-directory", destination_directory, NULL);
6a4a9c
 
6a4a9c
     self->compress_dialog = compress_dialog;
6a4a9c
+    self->activate_button = activate_button;
6a4a9c
+    self->error_label = error_label;
6a4a9c
     self->extension_stack = extension_stack;
6a4a9c
     self->zip_label = zip_label;
6a4a9c
+    self->encrypted_zip_label = encrypted_zip_label;
6a4a9c
     self->tar_xz_label = tar_xz_label;
6a4a9c
     self->seven_zip_label = seven_zip_label;
6a4a9c
     self->name_entry = name_entry;
6a4a9c
     self->extension_popover = extension_popover;
6a4a9c
     self->zip_checkmark = zip_checkmark;
6a4a9c
+    self->encrypted_zip_checkmark = encrypted_zip_checkmark;
6a4a9c
     self->tar_xz_checkmark = tar_xz_checkmark;
6a4a9c
     self->seven_zip_checkmark = seven_zip_checkmark;
6a4a9c
     self->name_entry = name_entry;
6a4a9c
+    self->passphrase_label = passphrase_label;
6a4a9c
+    self->passphrase_entry = passphrase_entry;
6a4a9c
 
6a4a9c
     self->response_handler_id = g_signal_connect (compress_dialog,
6a4a9c
                                                   "response",
6a4a9c
@@ -309,10 +429,18 @@ nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
6a4a9c
     gtk_builder_add_callback_symbols (builder,
6a4a9c
                                       "zip_row_on_activated",
6a4a9c
                                       G_CALLBACK (zip_row_on_activated),
6a4a9c
+                                      "encrypted_zip_row_on_activated",
6a4a9c
+                                      G_CALLBACK (encrypted_zip_row_on_activated),
6a4a9c
                                       "tar_xz_row_on_activated",
6a4a9c
                                       G_CALLBACK (tar_xz_row_on_activated),
6a4a9c
                                       "seven_zip_row_on_activated",
6a4a9c
                                       G_CALLBACK (seven_zip_row_on_activated),
6a4a9c
+                                      "passphrase_entry_on_changed",
6a4a9c
+                                      G_CALLBACK (passphrase_entry_on_changed),
6a4a9c
+                                      "passphrase_entry_on_icon_press",
6a4a9c
+                                      G_CALLBACK (passphrase_entry_on_icon_press),
6a4a9c
+                                      "activate_button_on_sensitive_notify",
6a4a9c
+                                      G_CALLBACK (activate_button_on_sensitive_notify),
6a4a9c
                                       NULL);
6a4a9c
     gtk_builder_connect_signals (builder, self);
6a4a9c
 
6a4a9c
@@ -350,6 +478,8 @@ nautilus_compress_dialog_controller_finalize (GObject *object)
6a4a9c
         self->compress_dialog = NULL;
6a4a9c
     }
6a4a9c
 
6a4a9c
+    g_free (self->passphrase);
6a4a9c
+
6a4a9c
     G_OBJECT_CLASS (nautilus_compress_dialog_controller_parent_class)->finalize (object);
6a4a9c
 }
6a4a9c
 
6a4a9c
@@ -364,3 +494,9 @@ nautilus_compress_dialog_controller_class_init (NautilusCompressDialogController
6a4a9c
     parent_class->get_new_name = nautilus_compress_dialog_controller_get_new_name;
6a4a9c
     parent_class->name_is_valid = nautilus_compress_dialog_controller_name_is_valid;
6a4a9c
 }
6a4a9c
+
6a4a9c
+const gchar *
6a4a9c
+nautilus_compress_dialog_controller_get_passphrase (NautilusCompressDialogController *self)
6a4a9c
+{
6a4a9c
+    return self->passphrase;
6a4a9c
+}
6a4a9c
diff --git a/src/nautilus-compress-dialog-controller.h b/src/nautilus-compress-dialog-controller.h
6a4a9c
index 2421b8115..6c96d68fa 100644
6a4a9c
--- a/src/nautilus-compress-dialog-controller.h
6a4a9c
+++ b/src/nautilus-compress-dialog-controller.h
6a4a9c
@@ -31,3 +31,4 @@ G_DECLARE_FINAL_TYPE (NautilusCompressDialogController, nautilus_compress_dialog
6a4a9c
 NautilusCompressDialogController * nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
6a4a9c
                                                                             NautilusDirectory *destination_directory,
6a4a9c
                                                                             gchar             *initial_name);
6a4a9c
+const gchar * nautilus_compress_dialog_controller_get_passphrase (NautilusCompressDialogController *controller);
6a4a9c
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
6a4a9c
index 59beecd7e..f909173f9 100644
6a4a9c
--- a/src/nautilus-file-operations.c
6a4a9c
+++ b/src/nautilus-file-operations.c
6a4a9c
@@ -222,6 +222,7 @@ typedef struct
6a4a9c
 
6a4a9c
     AutoarFormat format;
6a4a9c
     AutoarFilter filter;
6a4a9c
+    gchar *passphrase;
6a4a9c
 
6a4a9c
     guint64 total_size;
6a4a9c
     guint total_files;
6a4a9c
@@ -8753,6 +8754,7 @@ compress_task_done (GObject      *source_object,
6a4a9c
 
6a4a9c
     g_object_unref (compress_job->output_file);
6a4a9c
     g_list_free_full (compress_job->source_files, g_object_unref);
6a4a9c
+    g_free (compress_job->passphrase);
6a4a9c
 
6a4a9c
     finalize_common ((CommonJob *) compress_job);
6a4a9c
 
6a4a9c
@@ -9027,6 +9029,7 @@ compress_task_thread_func (GTask        *task,
6a4a9c
                                         compress_job->format,
6a4a9c
                                         compress_job->filter,
6a4a9c
                                         FALSE);
6a4a9c
+    autoar_compressor_set_passphrase (compressor, compress_job->passphrase);
6a4a9c
 
6a4a9c
     autoar_compressor_set_output_is_dest (compressor, TRUE);
6a4a9c
 
6a4a9c
@@ -9057,6 +9060,7 @@ nautilus_file_operations_compress (GList                          *files,
6a4a9c
                                    GFile                          *output,
6a4a9c
                                    AutoarFormat                    format,
6a4a9c
                                    AutoarFilter                    filter,
6a4a9c
+                                   const gchar                    *passphrase,
6a4a9c
                                    GtkWindow                      *parent_window,
6a4a9c
                                    NautilusFileOperationsDBusData *dbus_data,
6a4a9c
                                    NautilusCreateCallback          done_callback,
6a4a9c
@@ -9072,6 +9076,7 @@ nautilus_file_operations_compress (GList                          *files,
6a4a9c
     compress_job->output_file = g_object_ref (output);
6a4a9c
     compress_job->format = format;
6a4a9c
     compress_job->filter = filter;
6a4a9c
+    compress_job->passphrase = g_strdup (passphrase);
6a4a9c
     compress_job->done_callback = done_callback;
6a4a9c
     compress_job->done_callback_data = done_callback_data;
6a4a9c
 
6a4a9c
@@ -9082,7 +9087,8 @@ nautilus_file_operations_compress (GList                          *files,
6a4a9c
         compress_job->common.undo_info = nautilus_file_undo_info_compress_new (files,
6a4a9c
                                                                                output,
6a4a9c
                                                                                format,
6a4a9c
-                                                                               filter);
6a4a9c
+                                                                               filter,
6a4a9c
+                                                                               passphrase);
6a4a9c
     }
6a4a9c
 
6a4a9c
     task = g_task_new (NULL, compress_job->common.cancellable,
6a4a9c
diff --git a/src/nautilus-file-operations.h b/src/nautilus-file-operations.h
6a4a9c
index 8236e0e06..14d664f80 100644
6a4a9c
--- a/src/nautilus-file-operations.h
6a4a9c
+++ b/src/nautilus-file-operations.h
6a4a9c
@@ -159,6 +159,7 @@ void nautilus_file_operations_compress (GList                          *files,
6a4a9c
                                         GFile                          *output,
6a4a9c
                                         AutoarFormat                    format,
6a4a9c
                                         AutoarFilter                    filter,
6a4a9c
+                                        const gchar                    *passphrase,
6a4a9c
                                         GtkWindow                      *parent_window,
6a4a9c
                                         NautilusFileOperationsDBusData *dbus_data,
6a4a9c
                                         NautilusCreateCallback          done_callback,
6a4a9c
diff --git a/src/nautilus-file-undo-operations.c b/src/nautilus-file-undo-operations.c
6a4a9c
index a6a3b2025..64f9ce76c 100644
6a4a9c
--- a/src/nautilus-file-undo-operations.c
6a4a9c
+++ b/src/nautilus-file-undo-operations.c
6a4a9c
@@ -2495,6 +2495,7 @@ struct _NautilusFileUndoInfoCompress
6a4a9c
     GFile *output;
6a4a9c
     AutoarFormat format;
6a4a9c
     AutoarFilter filter;
6a4a9c
+    gchar *passphrase;
6a4a9c
 };
6a4a9c
 
6a4a9c
 G_DEFINE_TYPE (NautilusFileUndoInfoCompress, nautilus_file_undo_info_compress, NAUTILUS_TYPE_FILE_UNDO_INFO)
6a4a9c
@@ -2562,6 +2563,7 @@ compress_redo_func (NautilusFileUndoInfo           *info,
6a4a9c
                                        self->output,
6a4a9c
                                        self->format,
6a4a9c
                                        self->filter,
6a4a9c
+                                       self->passphrase,
6a4a9c
                                        parent_window,
6a4a9c
                                        dbus_data,
6a4a9c
                                        compress_callback,
6a4a9c
@@ -2597,6 +2599,7 @@ nautilus_file_undo_info_compress_finalize (GObject *obj)
6a4a9c
 
6a4a9c
     g_list_free_full (self->sources, g_object_unref);
6a4a9c
     g_clear_object (&self->output);
6a4a9c
+    g_free (self->passphrase);
6a4a9c
 
6a4a9c
     G_OBJECT_CLASS (nautilus_file_undo_info_compress_parent_class)->finalize (obj);
6a4a9c
 }
6a4a9c
@@ -2618,7 +2621,8 @@ NautilusFileUndoInfo *
6a4a9c
 nautilus_file_undo_info_compress_new (GList        *sources,
6a4a9c
                                       GFile        *output,
6a4a9c
                                       AutoarFormat  format,
6a4a9c
-                                      AutoarFilter  filter)
6a4a9c
+                                      AutoarFilter  filter,
6a4a9c
+                                      const gchar  *passphrase)
6a4a9c
 {
6a4a9c
     NautilusFileUndoInfoCompress *self;
6a4a9c
 
6a4a9c
@@ -2631,6 +2635,7 @@ nautilus_file_undo_info_compress_new (GList        *sources,
6a4a9c
     self->output = g_object_ref (output);
6a4a9c
     self->format = format;
6a4a9c
     self->filter = filter;
6a4a9c
+    self->passphrase = g_strdup (passphrase);
6a4a9c
 
6a4a9c
     return NAUTILUS_FILE_UNDO_INFO (self);
6a4a9c
 }
6a4a9c
diff --git a/src/nautilus-file-undo-operations.h b/src/nautilus-file-undo-operations.h
6a4a9c
index f96f2fe69..09ae17cef 100644
6a4a9c
--- a/src/nautilus-file-undo-operations.h
6a4a9c
+++ b/src/nautilus-file-undo-operations.h
6a4a9c
@@ -226,4 +226,5 @@ G_DECLARE_FINAL_TYPE (NautilusFileUndoInfoCompress, nautilus_file_undo_info_comp
6a4a9c
 NautilusFileUndoInfo * nautilus_file_undo_info_compress_new (GList        *sources,
6a4a9c
                                                              GFile        *output,
6a4a9c
                                                              AutoarFormat  format,
6a4a9c
-                                                             AutoarFilter  filter);
6a4a9c
+                                                             AutoarFilter  filter,
6a4a9c
+                                                             const gchar  *passphrase);
6a4a9c
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
6a4a9c
index b4a91226b..47aed3cc1 100644
6a4a9c
--- a/src/nautilus-files-view.c
6a4a9c
+++ b/src/nautilus-files-view.c
6a4a9c
@@ -2235,6 +2235,7 @@ compress_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *c
6a4a9c
     NautilusFilesViewPrivate *priv;
6a4a9c
     AutoarFormat format;
6a4a9c
     AutoarFilter filter;
6a4a9c
+    const gchar *passphrase = NULL;
6a4a9c
 
6a4a9c
     view = NAUTILUS_FILES_VIEW (callback_data->view);
6a4a9c
     priv = nautilus_files_view_get_instance_private (view);
6a4a9c
@@ -2280,6 +2281,14 @@ compress_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *c
6a4a9c
         }
6a4a9c
         break;
6a4a9c
 
6a4a9c
+        case NAUTILUS_COMPRESSION_ENCRYPTED_ZIP:
6a4a9c
+        {
6a4a9c
+            format = AUTOAR_FORMAT_ZIP;
6a4a9c
+            filter = AUTOAR_FILTER_NONE;
6a4a9c
+            passphrase = nautilus_compress_dialog_controller_get_passphrase (priv->compress_controller);
6a4a9c
+        }
6a4a9c
+        break;
6a4a9c
+
6a4a9c
         case NAUTILUS_COMPRESSION_TAR_XZ:
6a4a9c
         {
6a4a9c
             format = AUTOAR_FORMAT_TAR;
6a4a9c
@@ -2301,6 +2310,7 @@ compress_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *c
6a4a9c
     nautilus_file_operations_compress (source_files, output,
6a4a9c
                                        format,
6a4a9c
                                        filter,
6a4a9c
+                                       passphrase,
6a4a9c
                                        nautilus_files_view_get_containing_window (view),
6a4a9c
                                        NULL,
6a4a9c
                                        compress_done,
6a4a9c
diff --git a/src/nautilus-global-preferences.h b/src/nautilus-global-preferences.h
6a4a9c
index 8c482f7ce..2e8753b3c 100644
6a4a9c
--- a/src/nautilus-global-preferences.h
6a4a9c
+++ b/src/nautilus-global-preferences.h
6a4a9c
@@ -77,7 +77,8 @@ typedef enum
6a4a9c
 {
6a4a9c
         NAUTILUS_COMPRESSION_ZIP = 0,
6a4a9c
         NAUTILUS_COMPRESSION_TAR_XZ,
6a4a9c
-        NAUTILUS_COMPRESSION_7ZIP
6a4a9c
+        NAUTILUS_COMPRESSION_7ZIP,
6a4a9c
+        NAUTILUS_COMPRESSION_ENCRYPTED_ZIP
6a4a9c
 } NautilusCompressionFormat;
6a4a9c
 
6a4a9c
 /* Icon View */
6a4a9c
diff --git a/src/resources/css/nautilus.css b/src/resources/css/nautilus.css
6a4a9c
index 2e46b7abe..ee25a36a8 100644
6a4a9c
--- a/src/resources/css/nautilus.css
6a4a9c
+++ b/src/resources/css/nautilus.css
6a4a9c
@@ -3,3 +3,12 @@
6a4a9c
     padding-left: 5px;
6a4a9c
     padding-right: 5px;
6a4a9c
 }
6a4a9c
+
6a4a9c
+label.encrypted_zip,
6a4a9c
+row.encrypted_zip label.title {
6a4a9c
+    background-image: -gtk-icontheme('system-lock-screen-symbolic');
6a4a9c
+    background-position: right center;
6a4a9c
+    background-repeat: no-repeat;
6a4a9c
+    background-size: 16px 16px;
6a4a9c
+    padding-right: 24px;
6a4a9c
+}
6a4a9c
diff --git a/src/resources/ui/nautilus-compress-dialog.ui b/src/resources/ui/nautilus-compress-dialog.ui
6a4a9c
index b36539294..a57765eed 100644
6a4a9c
--- a/src/resources/ui/nautilus-compress-dialog.ui
6a4a9c
+++ b/src/resources/ui/nautilus-compress-dialog.ui
6a4a9c
@@ -28,6 +28,26 @@
6a4a9c
             </child>
6a4a9c
           </object>
6a4a9c
         </child>
6a4a9c
+        <child>
6a4a9c
+          <object class="HdyActionRow" id="encrypted_zip_row">
6a4a9c
+            <property name="visible">True</property>
6a4a9c
+            <property name="activatable">True</property>
6a4a9c
+            <property name="title" translatable="no">.zip</property>
6a4a9c
+            <property name="subtitle" translatable="yes">Password protected .zip, must be installed on Windows and Mac.</property>
6a4a9c
+            <signal name="activated" handler="encrypted_zip_row_on_activated"/>
6a4a9c
+            <style>
6a4a9c
+              <class name="encrypted_zip"/>
6a4a9c
+            </style>
6a4a9c
+            <child>
6a4a9c
+              <object class="GtkImage" id="encrypted_zip_checkmark">
6a4a9c
+                <property name="visible">True</property>
6a4a9c
+                <property name="width-request">16</property>
6a4a9c
+                <property name="margin-start">12</property>
6a4a9c
+                <property name="margin-end">12</property>
6a4a9c
+              </object>
6a4a9c
+            </child>
6a4a9c
+          </object>
6a4a9c
+        </child>
6a4a9c
         <child>
6a4a9c
           <object class="HdyActionRow">
6a4a9c
             <property name="visible">True</property>
6a4a9c
@@ -129,6 +149,15 @@
6a4a9c
                             <property name="xalign">0</property>
6a4a9c
                           </object>
6a4a9c
                         </child>
6a4a9c
+                        <child>
6a4a9c
+                          <object class="GtkLabel" id="encrypted_zip_label">
6a4a9c
+                            <property name="label" translatable="no">.zip</property>
6a4a9c
+                            <property name="xalign">0</property>
6a4a9c
+                            <style>
6a4a9c
+                              <class name="encrypted_zip"/>
6a4a9c
+                            </style>
6a4a9c
+                          </object>
6a4a9c
+                        </child>
6a4a9c
                         <child>
6a4a9c
                           <object class="GtkLabel" id="tar_xz_label">
6a4a9c
                             <property name="label" translatable="no">.tar.xz</property>
6a4a9c
@@ -179,6 +208,33 @@
6a4a9c
             <property name="position">3</property>
6a4a9c
           </packing>
6a4a9c
         </child>
6a4a9c
+        <child>
6a4a9c
+          <object class="GtkLabel" id="passphrase_label">
6a4a9c
+            <property name="label" translatable="yes">Password</property>
6a4a9c
+            <property name="margin-top">6</property>
6a4a9c
+            <property name="xalign">0</property>
6a4a9c
+          </object>
6a4a9c
+          <packing>
6a4a9c
+            <property name="expand">False</property>
6a4a9c
+            <property name="fill">True</property>
6a4a9c
+            <property name="position">4</property>
6a4a9c
+          </packing>
6a4a9c
+        </child>
6a4a9c
+        <child>
6a4a9c
+          <object class="GtkEntry" id="passphrase_entry">
6a4a9c
+            <property name="placeholder-text" translatable="yes">Enter a password here.</property>
6a4a9c
+            <property name="input-purpose">password</property>
6a4a9c
+            <property name="visibility">False</property>
6a4a9c
+            <property name="secondary-icon-name">view-conceal</property>
6a4a9c
+            <signal name="changed" handler="passphrase_entry_on_changed"/>
6a4a9c
+            <signal name="icon-press" handler="passphrase_entry_on_icon_press"/>
6a4a9c
+          </object>
6a4a9c
+          <packing>
6a4a9c
+            <property name="expand">False</property>
6a4a9c
+            <property name="fill">True</property>
6a4a9c
+            <property name="position">5</property>
6a4a9c
+          </packing>
6a4a9c
+        </child>
6a4a9c
       </object>
6a4a9c
     </child>
6a4a9c
     <child type="action">
6a4a9c
@@ -197,6 +253,7 @@
6a4a9c
         <property name="can_default">True</property>
6a4a9c
         <property name="receives_default">True</property>
6a4a9c
         <property name="sensitive">False</property>
6a4a9c
+        <signal name="notify::sensitive" handler="activate_button_on_sensitive_notify"/>
6a4a9c
       </object>
6a4a9c
     </child>
6a4a9c
     <action-widgets>
6a4a9c
-- 
6a4a9c
2.31.1
6a4a9c