[gnome-boxes/wip/feborges/ssh: 2/2] ssh-display: Introduce SSH support



commit c3bc20c419041c6605f88648db0841b8b3fb39c0
Author: Felipe Borges <felipeborges gnome org>
Date:   Mon Oct 29 13:51:05 2018 +0100

    ssh-display: Introduce SSH support
    
    Embeding a terminal emulator and spawning an ssh command is quite
    straightforward in Boxes, and is what Vinagre does to support SSH.
    
    In the future we should manage our credentials, connection options,
    and certificates.
    
    Fixes #265

 src/app.vala            |  1 +
 src/meson.build         |  2 ++
 src/remote-machine.vala |  5 +++
 src/ssh-display.vala    | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/wizard.vala         |  3 ++
 5 files changed, 106 insertions(+)
---
diff --git a/src/app.vala b/src/app.vala
index 6fc90bf8..dd764d8b 100644
--- a/src/app.vala
+++ b/src/app.vala
@@ -380,6 +380,7 @@ public async void add_collection_source (CollectionSource source) throws GLib.Er
         switch (source.source_type) {
         case "vnc":
         case "spice":
+        case "ssh":
         case "rdp":
             try {
                 var machine = new RemoteMachine (source);
diff --git a/src/meson.build b/src/meson.build
index 533cbb25..e97ffb1a 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -105,6 +105,7 @@ vala_sources = [
   'libvirt-vm-cloner.vala',
   'libvirt-vm-importer.vala',
   'vnc-display.vala',
+  'ssh-display.vala',
   'wizard-downloads-page.vala',
   'wizard-window.vala',
   'wizard-source.vala',
@@ -134,6 +135,7 @@ dependencies = [
   dependency ('libxml-2.0', version: '>= 2.7.8'),
   dependency ('spice-client-gtk-3.0', version: '>= 0.32'),
   dependency ('tracker-sparql-2.0'),
+  dependency ('vte-2.91', version: '>=0.52'),
   dependency ('webkit2gtk-4.0'),
   valac.find_library ('gio-2.0-workaround', dirs: vapi_dir),
   valac.find_library ('linux'),
diff --git a/src/remote-machine.vala b/src/remote-machine.vala
index 6cd8ccea..8359a961 100644
--- a/src/remote-machine.vala
+++ b/src/remote-machine.vala
@@ -8,6 +8,7 @@
     public RemoteMachine (CollectionSource source) throws Boxes.Error {
         if (source.source_type != "spice" &&
             source.source_type != "vnc" &&
+            source.source_type != "ssh" &&
             source.source_type != "rdp")
             throw new Boxes.Error.INVALID ("source is not remote machine: %s", source.uri);
 
@@ -39,6 +40,10 @@ public RemoteMachine (CollectionSource source) throws Boxes.Error {
         case "rdp":
             return new RdpDisplay.with_uri (config, source.uri);
 #endif
+
+        case "ssh":
+            return new SshDisplay.with_uri (config, source.uri);
+
         default:
             throw new Boxes.Error.INVALID ("unsupported display of type " + type);
         }
diff --git a/src/ssh-display.vala b/src/ssh-display.vala
new file mode 100644
index 00000000..37254e0b
--- /dev/null
+++ b/src/ssh-display.vala
@@ -0,0 +1,95 @@
+// This file is part of GNOME Boxes. License: LGPLv2+
+using Gtk;
+using Vte;
+
+private class Boxes.SshDisplay: Boxes.Display {
+    public override string protocol { get { return "SSH"; } }
+    public override string? uri { owned get { return @"ssh://$user@$host"; } }
+    private Terminal display;
+    private string host;
+    private string user;
+    private int port;
+    private BoxConfig.SavedProperty[] saved_properties;
+
+    construct {
+        saved_properties = {
+            BoxConfig.SavedProperty () { name = "read-only", default_value = false }
+        };
+        display = new Terminal ();
+        display.show.connect (() => {
+            show (0);
+            access_start ();
+        });
+    }
+
+    public SshDisplay (BoxConfig config, string user, string host, int port) {
+        this.config = config;
+
+        this.user = user;
+        this.host = host;
+        this.port = port;
+
+        config.save_properties (display, saved_properties);
+    }
+
+    public SshDisplay.with_uri (BoxConfig config, string _uri) throws Boxes.Error {
+        this.config = config;
+
+        var uri = Xml.URI.parse (_uri);
+        if (uri.scheme != "ssh")
+            throw new Boxes.Error.INVALID ("the URL is not ssh://");
+
+        if (uri.server == null)
+            throw new Boxes.Error.INVALID ("the URL is missing a server");
+
+        this.host = uri.server + uri.path;
+        this.user = uri.user;
+        this.port = uri.port <= 0 ? 22 : uri.port;
+
+        config.save_properties (display, saved_properties);
+    }
+
+    public override Gtk.Widget get_display (int n) {
+        return display;
+    }
+
+    public override void set_enable_audio (bool enable) {
+    }
+
+    public override Gdk.Pixbuf? get_pixbuf (int n) {
+        return null;
+    }
+
+    private bool run (string[] command) {
+        SpawnFlags flags = SpawnFlags.SEARCH_PATH_FROM_ENVP | SpawnFlags.DO_NOT_REAP_CHILD;
+
+        return display.spawn_sync (PtyFlags.DEFAULT, Environment.get_home_dir (), command, null, flags, 
null, null);
+    }
+
+    public override void connect_it (owned Display.OpenFDFunc? open_fd = null) {
+        // We only initiate connection once
+        if (connected)
+            return;
+        connected = true;
+
+        display.show_all ();
+
+        string[] ssh_connect_cmd = {
+            "ssh", this.user + "@" + this.host,
+        };
+
+        run (ssh_connect_cmd);
+    }
+
+    public override void disconnect_it () {
+    }
+
+    public override List<Boxes.Property> get_properties (Boxes.PropertiesPage page) {
+        var list = new List<Boxes.Property> ();
+
+        return list;
+    }
+
+    public override void send_keys (uint[] keyvals) {
+    }
+}
diff --git a/src/wizard.vala b/src/wizard.vala
index 86d222b1..bd82a6cd 100644
--- a/src/wizard.vala
+++ b/src/wizard.vala
@@ -366,6 +366,8 @@ private void prepare_for_uri (string uri_as_text, string? filename = null) throw
             source.source_type = "spice";
         } else if (uri.scheme == "vnc") {
             // accept any vnc:// uri
+        } else if (uri.scheme == "ssh") {
+           // accept any ssh:// uri
         } else if (uri.scheme == "rdp") {
             // accept any rdp:// uri
         #if !HAVE_RDP
@@ -555,6 +557,7 @@ private async bool do_review_cancellable () {
 
             case "vnc":
             case "rdp":
+            case "ssh":
                 if (uri.port > 0)
                     summary.add_property (_("Port"), uri.port.to_string ());
                 break;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]