diff --git a/src/Surface.zig b/src/Surface.zig index 9865efcfb..303c7ee4d 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -142,6 +142,7 @@ const DerivedConfig = struct { clipboard_read: bool, clipboard_write: bool, clipboard_trim_trailing_spaces: bool, + clipboard_paste_protection: bool, copy_on_select: configpkg.CopyOnSelect, confirm_close_surface: bool, mouse_interval: u64, @@ -165,6 +166,7 @@ const DerivedConfig = struct { .clipboard_read = config.@"clipboard-read", .clipboard_write = config.@"clipboard-write", .clipboard_trim_trailing_spaces = config.@"clipboard-trim-trailing-spaces", + .clipboard_paste_protection = config.@"clipboard-paste-protection", .copy_on_select = config.@"copy-on-select", .confirm_close_surface = config.@"confirm-close-surface", .mouse_interval = config.@"click-repeat-interval" * 1_000_000, // 500ms @@ -2500,7 +2502,7 @@ fn sanatizeClipboardPaste(data: []const u8) !void { fn completeClipboardPaste(self: *Surface, data: []const u8, force: bool) !void { if (data.len == 0) return; - if (!force) { + if (!force and self.config.clipboard_paste_protection) { try sanatizeClipboardPaste(data); } diff --git a/src/apprt/gtk/UnsafePasteWindow.zig b/src/apprt/gtk/UnsafePasteWindow.zig index 081329a09..0d87cc0fb 100644 --- a/src/apprt/gtk/UnsafePasteWindow.zig +++ b/src/apprt/gtk/UnsafePasteWindow.zig @@ -1,4 +1,4 @@ -/// Configuration errors window. +/// Unsafe Paste Window const UnsafePaste = @This(); const std = @import("std"); @@ -44,7 +44,7 @@ pub fn create( /// Not public because this should be called by the GTK lifecycle. fn destroy(self: *UnsafePaste) void { const alloc = self.app.core_app.alloc; - self.app.config_errors_window = null; + self.app.unsafe_paste_window = null; alloc.destroy(self); } @@ -55,12 +55,13 @@ fn init( core_surface: CoreSurface, request: ClipboardRequest, ) !void { + // Create the window const window = c.gtk_window_new(); const gtk_window: *c.GtkWindow = @ptrCast(window); errdefer c.gtk_window_destroy(gtk_window); c.gtk_window_set_title(gtk_window, "Unsafe Paste!"); - c.gtk_window_set_default_size(gtk_window, 600, 400); + c.gtk_window_set_default_size(gtk_window, 400, 275); c.gtk_window_set_resizable(gtk_window, 0); _ = c.g_signal_connect_data( window, @@ -86,6 +87,10 @@ fn init( self.view = view; c.gtk_window_set_child(@ptrCast(window), view.root); c.gtk_widget_show(window); + + // Block the main window from input. + // This will auto-revert when the window is closed. + c.gtk_window_set_modal(gtk_window, 1); } fn gtkDestroy(_: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { @@ -164,6 +169,9 @@ const ButtonsView = struct { const paste_button = c.gtk_button_new_with_label("Paste"); errdefer c.g_object_unref(paste_button); + // TODO: Focus on the paste button + // c.gtk_widget_grab_focus(paste_button); + // Create our view const view = try View.init(&.{ .{ .name = "cancel", .widget = cancel_button }, @@ -194,8 +202,6 @@ const ButtonsView = struct { fn gtkCancelClick(_: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { const self: *UnsafePaste = @ptrCast(@alignCast(ud)); c.gtk_window_destroy(@ptrCast(self.window)); - - self.app.unsafe_paste_window = null; } fn gtkPasteClick(_: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { @@ -207,7 +213,6 @@ const ButtonsView = struct { }; c.gtk_window_destroy(@ptrCast(self.window)); - self.app.unsafe_paste_window = null; } const vfl = [_][*:0]const u8{ diff --git a/src/config/Config.zig b/src/config/Config.zig index ba29ed6f2..3319f9d09 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -423,6 +423,10 @@ keybind: Keybinds = .{}, /// This does not affect data sent to the clipboard via "clipboard-write". @"clipboard-trim-trailing-spaces": bool = true, +/// Creates a pop-up window when active, warning the user that they are pasting +/// contents that contains more than one line. This could be a "copy paste attack" +@"clipboard-paste-protection": bool = true, + /// The total amount of bytes that can be used for image data (i.e. /// the Kitty image protocol) per terminal scren. The maximum value /// is 4,294,967,295 (4GB). The default is 320MB. If this is set to zero,