In the past week I have written an X clipboard forwarder and hooked it
up to Xpra.  The forwarder is based on the XCB-based Python X library
that I started last year with the intention of writing an X security
proxy (http://plash.beasts.org/wiki/X11ProxySpike).

The novel part is that this is a trusted-path clipboard forwarder.
Forwarding only occurs when the user presses Ctrl-X, Ctrl-C or Ctrl-V.
The intention is to prevent malicious clients from snooping on the
clipboard contents or writing data into the clipboard without action
from the user.  It does not forward X's primary selection, only the
clipboard.

The forwarder is only hooked up to the "xpra standalone" subcommand
that is added by the last patch I sent, just because that was easiest
to do quickly.

For some background see
http://lists.gnu.org/archive/html/plash/2008-06/msg00004.html
and for a list of tasks still to do see
http://plash.beasts.org/wiki/X11Selections

This is just a request for comments at the moment.  I don't expect
this patch to be merged as is.  For one thing, my X library does not
have a stable interface yet, and it is debatable whether Xpra should
depend on it.

Regards,
Mark


diff --git a/xpra/client.py b/xpra/client.py
index 8d0d467..9297cbc 100644
--- a/xpra/client.py
+++ b/xpra/client.py
@@ -48,7 +48,8 @@ class ClientSource(object):
             return None, False
 
 class ClientWindow(gtk.Window):
-    def __init__(self, client, id, x, y, w, h, metadata, override_redirect):
+    def __init__(self, client, id, x, y, w, h, metadata, override_redirect,
+                 tp_clipboard):
         if override_redirect:
             type = gtk.WINDOW_POPUP
         else:
@@ -61,6 +62,7 @@ class ClientWindow(gtk.Window):
         self._backing = None
         self._metadata = {}
         self._override_redirect = override_redirect
+        self._tp_clipboard = tp_clipboard
         self._new_backing(w, h)
         self.update_metadata(metadata)
         
@@ -192,6 +194,11 @@ class ClientWindow(gtk.Window):
     def _key_action(self, event, depressed):
         modifiers = self._client.mask_to_names(event.state)
         name = gtk.gdk.keyval_name(event.keyval)
+        if modifiers == ["control"]:
+            if name in ("x", "c"):
+                self._tp_clipboard.copy()
+            elif name == "v":
+                self._tp_clipboard.paste()
         self._client.send(["key-action", self._id, name, depressed, modifiers])
 
     def do_key_press_event(self, event):
@@ -227,13 +234,24 @@ class ClientWindow(gtk.Window):
 
 gobject.type_register(ClientWindow)
 
+
+class DummyClipboard(object):
+
+    def copy(self):
+        pass
+
+    def paste(self):
+        pass
+
+
 class XpraClient(gobject.GObject):
     __gsignals__ = {
         "wimpiggy-property-notify-event": one_arg_signal,
         }
 
-    def __init__(self, sock):
+    def __init__(self, sock, tp_clipboard=DummyClipboard()):
         gobject.GObject.__init__(self)
+        self._tp_clipboard = tp_clipboard
         self._window_to_id = {}
         self._id_to_window = {}
         self._stacking = []
@@ -309,7 +327,7 @@ class XpraClient(gobject.GObject):
     def _process_new_common(self, packet, override_redirect):
         (_, id, x, y, w, h, metadata) = packet
         window = ClientWindow(self, id, x, y, w, h, metadata,
-                              override_redirect)
+                              override_redirect, self._tp_clipboard)
         self._id_to_window[id] = window
         self._window_to_id[window] = id
         window.show_all()
diff --git a/xpra/scripts/main.py b/xpra/scripts/main.py
index eded4f3..3cde24e 100644
--- a/xpra/scripts/main.py
+++ b/xpra/scripts/main.py
@@ -9,6 +9,10 @@ import tempfile
 from optparse import OptionParser
 import logging
 
+import plash.comms.event_loop
+import example_clients
+import selection
+
 import xpra
 from xpra.bencode import bencode
 from xpra.address import (sockdir, sockpath,
@@ -176,7 +180,15 @@ def run_standalone(parser, args):
         client_socket.connect(socket_path)
     finally:
         shutil.rmtree(temp_dir)
-    client = xpra.client.XpraClient(client_socket)
+
+    event_loop = plash.comms.event_loop.GlibEventLoop()
+    app_display = selection.SharableClientConnection(
+        example_clients.connect_to_display(event_loop, new_display))
+    real_display = selection.SharableClientConnection(
+        example_clients.connect_to_default_display(event_loop))
+    tp_clipboard = selection.AsymmetricForwarder(real_display, app_display)
+
+    client = xpra.client.XpraClient(client_socket, tp_clipboard)
     environ = os.environ.copy()
     environ["DISPLAY"] = new_display
     proc = subprocess.Popen(args, env=environ)

_______________________________________________
Parti-discuss mailing list
[email protected]
http://lists.partiwm.org/cgi-bin/mailman/listinfo/parti-discuss

Reply via email to