OSC 52: Clipboard Control (#52)

This adds support for OSC 52 -- applications can read/write the clipboard. Due to the security risk of this, the default configuration allows for writing but _not reading_. This is configurable using two new settings: `clipboard-read` and `clipboard-write` (both booleans).
This commit is contained in:
Mitchell Hashimoto
2022-11-21 15:12:00 -08:00
committed by GitHub
parent 173aff1e80
commit 56de5846f4
7 changed files with 147 additions and 6 deletions

View File

@@ -592,9 +592,80 @@ pub fn handleMessage(self: *Window, msg: Message) !void {
},
.cell_size => |size| try self.setCellSize(size),
.clipboard_read => |kind| try self.clipboardRead(kind),
.clipboard_write => |req| switch (req) {
.small => |v| try self.clipboardWrite(v.data[0..v.len]),
.stable => |v| try self.clipboardWrite(v),
.alloc => |v| {
defer v.alloc.free(v.data);
try self.clipboardWrite(v.data);
},
},
}
}
fn clipboardRead(self: *const Window, kind: u8) !void {
if (!self.config.@"clipboard-read") {
log.info("application attempted to read clipboard, but 'clipboard-read' setting is off", .{});
return;
}
const data = glfw.getClipboardString() catch |err| {
log.warn("error reading clipboard: {}", .{err});
return;
};
// Even if the clipboard data is empty we reply, since presumably
// the client app is expecting a reply. We first allocate our buffer.
// This must hold the base64 encoded data PLUS the OSC code surrounding it.
const enc = std.base64.standard.Encoder;
const size = enc.calcSize(data.len);
var buf = try self.alloc.alloc(u8, size + 9); // const for OSC
defer self.alloc.free(buf);
// Wrap our data with the OSC code
const prefix = try std.fmt.bufPrint(buf, "\x1b]52;{c};", .{kind});
assert(prefix.len == 7);
buf[buf.len - 2] = '\x1b';
buf[buf.len - 1] = '\\';
// Do the base64 encoding
const encoded = enc.encode(buf[prefix.len..], data);
assert(encoded.len == size);
_ = self.io_thread.mailbox.push(try termio.Message.writeReq(
self.alloc,
buf,
), .{ .forever = {} });
self.io_thread.wakeup.send() catch {};
}
fn clipboardWrite(self: *const Window, data: []const u8) !void {
if (!self.config.@"clipboard-write") {
log.info("application attempted to write clipboard, but 'clipboard-write' setting is off", .{});
return;
}
const dec = std.base64.standard.Decoder;
// Build buffer
const size = try dec.calcSizeForSlice(data);
var buf = try self.alloc.allocSentinel(u8, size, 0);
defer self.alloc.free(buf);
buf[buf.len] = 0;
// Decode
try dec.decode(buf, data);
assert(buf[buf.len] == 0);
glfw.setClipboardString(buf) catch |err| {
log.err("error setting clipboard string err={}", .{err});
return;
};
}
/// Change the cell size for the terminal grid. This can happen as
/// a result of changing the font size at runtime.
fn setCellSize(self: *Window, size: renderer.CellSize) !void {