[Wayland] Handle clipboard pasting more securely
Only receive clipboard offers when pasting instead of storing the data indefinitely. This is also more performant by default as it is not doing unnecessary work.
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
#ifndef ROFI_DISPLAY_INTERNAL_H
|
||||
#define ROFI_DISPLAY_INTERNAL_H
|
||||
|
||||
#include "display.h"
|
||||
#include "helper.h"
|
||||
#include "nkutils-bindings.h"
|
||||
#include <glib.h>
|
||||
@@ -48,7 +49,7 @@ typedef struct _display_proxy {
|
||||
|
||||
void (*set_input_focus)(guint window);
|
||||
void (*revert_input_focus)(void);
|
||||
char *(*get_clipboard_data)(int type);
|
||||
void (*get_clipboard_data)(int type, ClipboardCb callback, void *user_data);
|
||||
void (*set_fullscreen_mode)(void);
|
||||
|
||||
guint (*scale)(void);
|
||||
|
@@ -127,7 +127,8 @@ enum clipboard_type {
|
||||
CLIPBOARD_PRIMARY,
|
||||
};
|
||||
|
||||
char *display_get_clipboard_data(enum clipboard_type);
|
||||
typedef void (* ClipboardCb)(char *clipboard_data, void *user_data);
|
||||
void display_get_clipboard_data(enum clipboard_type, ClipboardCb callback, void* user_data);
|
||||
|
||||
void display_set_fullscreen_mode(void);
|
||||
|
||||
|
@@ -34,6 +34,10 @@ typedef struct {
|
||||
|
||||
typedef struct _wayland_seat wayland_seat;
|
||||
|
||||
typedef struct {
|
||||
void *offer;
|
||||
} clipboard_data;
|
||||
|
||||
typedef struct {
|
||||
GMainLoop *main_loop;
|
||||
GWaterWaylandSource *main_loop_source;
|
||||
@@ -77,8 +81,7 @@ typedef struct {
|
||||
int32_t scale;
|
||||
NkBindingsSeat *bindings_seat;
|
||||
|
||||
char *clipboard_default_data;
|
||||
char *clipboard_primary_data;
|
||||
clipboard_data clipboards[2];
|
||||
|
||||
uint32_t layer_width;
|
||||
uint32_t layer_height;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#include "keyb.h"
|
||||
#include <glib.h>
|
||||
|
||||
#include "display-internal.h"
|
||||
#include "display.h"
|
||||
#include "display-internal.h"
|
||||
|
||||
#include "view.h"
|
||||
|
||||
@@ -41,8 +41,8 @@ void display_startup_notification(RofiHelperExecuteContext *context,
|
||||
|
||||
guint display_scale(void) { return proxy->scale(); }
|
||||
|
||||
char *display_get_clipboard_data(enum clipboard_type type) {
|
||||
return proxy->get_clipboard_data(type);
|
||||
void display_get_clipboard_data(enum clipboard_type type, ClipboardCb callback, void* user_data) {
|
||||
proxy->get_clipboard_data(type, callback, user_data);
|
||||
}
|
||||
|
||||
void display_set_fullscreen_mode(void) { proxy->set_fullscreen_mode(); }
|
||||
|
@@ -921,6 +921,18 @@ static void rofi_view_input_changed(void) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WAYLAND
|
||||
static void rofi_view_clipboard_callback(char *clipboard_data, G_GNUC_UNUSED void *user_data) {
|
||||
RofiViewState *state = rofi_view_get_active();
|
||||
if (clipboard_data != NULL) {
|
||||
if (state != NULL) {
|
||||
rofi_view_handle_text(state, clipboard_data);
|
||||
}
|
||||
g_free(clipboard_data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rofi_view_trigger_global_action(KeyBindingAction action) {
|
||||
RofiViewState *state = rofi_view_get_active();
|
||||
switch (action) {
|
||||
@@ -936,10 +948,7 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
|
||||
#endif
|
||||
#ifdef ENABLE_WAYLAND
|
||||
if (config.backend == DISPLAY_WAYLAND) {
|
||||
char *d = display_get_clipboard_data(CLIPBOARD_PRIMARY);
|
||||
if (d != NULL) {
|
||||
rofi_view_handle_text(current_active_menu, d);
|
||||
}
|
||||
display_get_clipboard_data(CLIPBOARD_PRIMARY, rofi_view_clipboard_callback, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@@ -954,10 +963,7 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
|
||||
#endif
|
||||
#ifdef ENABLE_WAYLAND
|
||||
if (config.backend == DISPLAY_WAYLAND) {
|
||||
char *d = display_get_clipboard_data(CLIPBOARD_DEFAULT);
|
||||
if (d != NULL) {
|
||||
rofi_view_handle_text(current_active_menu, d);
|
||||
}
|
||||
display_get_clipboard_data(CLIPBOARD_DEFAULT, rofi_view_clipboard_callback, NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
@@ -885,13 +885,12 @@ static void wayland_keyboard_release(wayland_seat *self) {
|
||||
|
||||
#define CLIPBOARD_READ_INCREMENT 1024
|
||||
|
||||
typedef void (*clipboard_read_callback)(char *data);
|
||||
|
||||
struct clipboard_read_info {
|
||||
char *buffer;
|
||||
size_t size;
|
||||
int fd;
|
||||
clipboard_read_callback callback;
|
||||
ClipboardCb callback;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static gboolean clipboard_read_glib_callback(GIOChannel *channel,
|
||||
@@ -900,8 +899,9 @@ static gboolean clipboard_read_glib_callback(GIOChannel *channel,
|
||||
struct clipboard_read_info *info = opaque;
|
||||
gsize read;
|
||||
|
||||
switch (g_io_channel_read_chars(channel, info->buffer + info->size,
|
||||
CLIPBOARD_READ_INCREMENT, &read, NULL)) {
|
||||
GIOStatus status = g_io_channel_read_chars(channel, info->buffer + info->size,
|
||||
CLIPBOARD_READ_INCREMENT, &read, NULL);
|
||||
switch (status) {
|
||||
case G_IO_STATUS_AGAIN:
|
||||
return TRUE;
|
||||
|
||||
@@ -921,7 +921,12 @@ static gboolean clipboard_read_glib_callback(GIOChannel *channel,
|
||||
|
||||
default:
|
||||
info->buffer[info->size] = '\0';
|
||||
info->callback(info->buffer);
|
||||
if (status == G_IO_STATUS_EOF) {
|
||||
info->callback(info->buffer, info->user_data);
|
||||
} else { // G_IO_STATUS_ERROR
|
||||
g_warning("Could not read data from clipboard");
|
||||
g_free(info->buffer);
|
||||
}
|
||||
g_io_channel_shutdown(channel, FALSE, NULL);
|
||||
g_io_channel_unref(channel);
|
||||
close(info->fd);
|
||||
@@ -930,7 +935,7 @@ static gboolean clipboard_read_glib_callback(GIOChannel *channel,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean clipboard_read_data(int fd, clipboard_read_callback callback) {
|
||||
static gboolean clipboard_read_data(int fd, ClipboardCb callback, void *user_data) {
|
||||
GIOChannel *channel = g_io_channel_unix_new(fd);
|
||||
|
||||
struct clipboard_read_info *info = g_malloc(sizeof *info);
|
||||
@@ -943,6 +948,7 @@ static gboolean clipboard_read_data(int fd, clipboard_read_callback callback) {
|
||||
info->fd = fd;
|
||||
info->size = 0;
|
||||
info->callback = callback;
|
||||
info->user_data = user_data;
|
||||
info->buffer = g_malloc(CLIPBOARD_READ_INCREMENT);
|
||||
|
||||
if (info->buffer == NULL) {
|
||||
@@ -980,32 +986,24 @@ static void data_device_handle_data_offer(void *data,
|
||||
wl_data_offer_add_listener(offer, &data_offer_listener, NULL);
|
||||
}
|
||||
|
||||
static void clipboard_default_callback(char *data) {
|
||||
if (wayland->clipboard_default_data != NULL) {
|
||||
g_free(wayland->clipboard_default_data);
|
||||
static void clipboard_handle_selection(enum clipboard_type cb_type, void *offer) {
|
||||
clipboard_data *clipboard = &wayland->clipboards[cb_type];
|
||||
|
||||
if (clipboard->offer != NULL) {
|
||||
if (cb_type == CLIPBOARD_DEFAULT) {
|
||||
wl_data_offer_destroy(clipboard->offer);
|
||||
} else {
|
||||
zwp_primary_selection_offer_v1_destroy(clipboard->offer);
|
||||
}
|
||||
}
|
||||
wayland->clipboard_default_data = data;
|
||||
clipboard->offer = offer;
|
||||
|
||||
}
|
||||
|
||||
static void data_device_handle_selection(void *data,
|
||||
struct wl_data_device *data_device,
|
||||
struct wl_data_offer *offer) {
|
||||
if (offer == NULL) {
|
||||
// clipboard is empty
|
||||
return;
|
||||
}
|
||||
|
||||
int fds[2];
|
||||
if (pipe(fds) < 0) {
|
||||
return;
|
||||
}
|
||||
wl_data_offer_receive(offer, "text/plain", fds[1]);
|
||||
close(fds[1]);
|
||||
|
||||
wl_display_roundtrip(wayland->display);
|
||||
|
||||
clipboard_read_data(fds[0], clipboard_default_callback);
|
||||
wl_data_offer_destroy(offer);
|
||||
clipboard_handle_selection(CLIPBOARD_DEFAULT, offer);
|
||||
}
|
||||
|
||||
static const struct wl_data_device_listener data_device_listener = {
|
||||
@@ -1030,32 +1028,10 @@ static void primary_selection_device_handle_data_offer(
|
||||
offer, &primary_selection_offer_listener, NULL);
|
||||
}
|
||||
|
||||
static void clipboard_primary_callback(char *data) {
|
||||
if (wayland->clipboard_primary_data != NULL) {
|
||||
g_free(wayland->clipboard_primary_data);
|
||||
}
|
||||
wayland->clipboard_primary_data = data;
|
||||
}
|
||||
|
||||
static void primary_selection_device_handle_selection(
|
||||
void *data, struct zwp_primary_selection_device_v1 *data_device,
|
||||
struct zwp_primary_selection_offer_v1 *offer) {
|
||||
if (offer == NULL) {
|
||||
// clipboard is empty
|
||||
return;
|
||||
}
|
||||
|
||||
int fds[2];
|
||||
if (pipe(fds) < 0) {
|
||||
return;
|
||||
}
|
||||
zwp_primary_selection_offer_v1_receive(offer, "text/plain", fds[1]);
|
||||
close(fds[1]);
|
||||
|
||||
wl_display_roundtrip(wayland->display);
|
||||
|
||||
clipboard_read_data(fds[0], clipboard_primary_callback);
|
||||
zwp_primary_selection_offer_v1_destroy(offer);
|
||||
clipboard_handle_selection(CLIPBOARD_PRIMARY, offer);
|
||||
}
|
||||
|
||||
static const struct zwp_primary_selection_device_v1_listener
|
||||
@@ -1748,15 +1724,26 @@ static const struct _view_proxy *wayland_display_view_proxy(void) {
|
||||
|
||||
static guint wayland_display_scale(void) { return wayland->scale; }
|
||||
|
||||
static char *wayland_get_clipboard_data(int type) {
|
||||
switch (type) {
|
||||
case CLIPBOARD_DEFAULT:
|
||||
return wayland->clipboard_default_data;
|
||||
case CLIPBOARD_PRIMARY:
|
||||
return wayland->clipboard_primary_data;
|
||||
static void wayland_get_clipboard_data(int cb_type, ClipboardCb callback, void *user_data) {
|
||||
clipboard_data *clipboard = &wayland->clipboards[cb_type];
|
||||
|
||||
if (clipboard->offer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
int fds[2];
|
||||
if (pipe(fds) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb_type == CLIPBOARD_DEFAULT) {
|
||||
wl_data_offer_receive(clipboard->offer, "text/plain", fds[1]);
|
||||
} else {
|
||||
zwp_primary_selection_offer_v1_receive(clipboard->offer, "text/plain", fds[1]);
|
||||
}
|
||||
close(fds[1]);
|
||||
|
||||
clipboard_read_data(fds[0], callback, user_data);
|
||||
}
|
||||
|
||||
static void wayland_set_fullscreen_mode(void) {
|
||||
|
Reference in New Issue
Block a user