LCOV - code coverage report
Current view: top level - src/plugins/sftp - valent-sftp-plugin.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 45.1 % 295 133
Test Date: 2024-11-16 20:34:14 Functions: 53.6 % 28 15
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 18.7 % 214 40

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-sftp-plugin"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <glib/gi18n.h>
       9                 :             : #include <gio/gio.h>
      10                 :             : #include <json-glib/json-glib.h>
      11                 :             : #include <valent.h>
      12                 :             : 
      13                 :             : #include "valent-sftp-plugin.h"
      14                 :             : 
      15                 :             : 
      16                 :             : typedef struct _ValentSftpSession ValentSftpSession;
      17                 :             : 
      18                 :             : struct _ValentSftpPlugin
      19                 :             : {
      20                 :             :   ValentDevicePlugin  parent_instance;
      21                 :             : 
      22                 :             :   GVolumeMonitor     *monitor;
      23                 :             :   ValentSftpSession  *session;
      24                 :             : };
      25                 :             : 
      26   [ +  +  +  - ]:          72 : G_DEFINE_FINAL_TYPE (ValentSftpPlugin, valent_sftp_plugin, VALENT_TYPE_DEVICE_PLUGIN)
      27                 :             : 
      28                 :             : 
      29                 :             : static char *
      30                 :           4 : get_device_host (ValentSftpPlugin *self)
      31                 :             : {
      32                 :           4 :   ValentDevice *device;
      33                 :           8 :   g_autoptr (ValentChannel) channel = NULL;
      34         [ +  - ]:           4 :   g_autofree char *host = NULL;
      35                 :           4 :   GParamSpec *pspec = NULL;
      36                 :             : 
      37                 :             :   /* The plugin doesn't know ValentChannel derivations, so we have to check for
      38                 :             :    * a "host" property to ensure it's IP-based */
      39                 :           4 :   device = valent_extension_get_object (VALENT_EXTENSION (self));
      40                 :           4 :   channel = valent_device_ref_channel (device);
      41                 :             : 
      42         [ +  - ]:           4 :   if G_LIKELY (channel != NULL)
      43                 :           4 :     pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (channel), "host");
      44                 :             : 
      45         [ +  - ]:           4 :   if G_LIKELY (pspec != NULL)
      46                 :           4 :     g_object_get (channel, "host", &host, NULL);
      47                 :             : 
      48                 :           4 :   return g_steal_pointer (&host);
      49                 :             : }
      50                 :             : 
      51                 :             : /**
      52                 :             :  * ValentSftpSession:
      53                 :             :  * @host: Host name or IP
      54                 :             :  * @port: Port
      55                 :             :  * @username: Username (deprecated)
      56                 :             :  * @password: Password (deprecated)
      57                 :             :  * @mount: A `GMount` for the session
      58                 :             :  *
      59                 :             :  * `ValentSftpSession` is a simple representation of a SFTP session.
      60                 :             :  */
      61                 :             : typedef struct _ValentSftpSession
      62                 :             : {
      63                 :             :   char     *host;
      64                 :             :   uint16_t  port;
      65                 :             :   char     *username;
      66                 :             :   char     *password;
      67                 :             : 
      68                 :             :   char    *uri;
      69                 :             :   GMount  *mount;
      70                 :             : } ValentSftpSession;
      71                 :             : 
      72                 :             : 
      73                 :             : static ValentSftpSession *
      74                 :           0 : sftp_session_new (ValentSftpPlugin *self,
      75                 :             :                   JsonNode         *packet)
      76                 :             : {
      77                 :           0 :   ValentSftpSession *session;
      78                 :           0 :   g_autofree char *host = NULL;
      79                 :           0 :   int64_t port;
      80                 :           0 :   const char *password;
      81                 :           0 :   const char *username;
      82                 :             : 
      83                 :             :   /* Ultimately, these are the only packet fields we really need */
      84         [ #  # ]:           0 :   if (!valent_packet_get_int (packet, "port", &port) ||
      85         [ #  # ]:           0 :       (port < 0 || port > G_MAXUINT16))
      86                 :             :     {
      87                 :           0 :       g_debug ("%s(): expected \"port\" field holding a uint16",
      88                 :             :                G_STRFUNC);
      89                 :           0 :       return NULL;
      90                 :             :     }
      91                 :             : 
      92         [ #  # ]:           0 :   if ((host = get_device_host (self)) == NULL)
      93                 :             :     {
      94                 :           0 :       g_warning ("%s(): failed to get host address",
      95                 :             :                  G_STRFUNC);
      96                 :           0 :       return NULL;
      97                 :             :     }
      98                 :             : 
      99                 :             :   // Create a session struct
     100                 :           0 :   session = g_new0 (ValentSftpSession, 1);
     101                 :           0 :   session->host = g_steal_pointer (&host);
     102                 :           0 :   session->port = (uint16_t)port;
     103                 :             : 
     104         [ #  # ]:           0 :   if (valent_packet_get_string (packet, "user", &username))
     105         [ #  # ]:           0 :     session->username = g_strdup (username);
     106                 :             : 
     107         [ #  # ]:           0 :   if (valent_packet_get_string (packet, "password", &password))
     108         [ #  # ]:           0 :     session->password = g_strdup (password);
     109                 :             : 
     110                 :             :   // Gvfs
     111                 :           0 :   session->uri = g_strdup_printf ("sftp://%s:%u/",
     112                 :             :                                   session->host,
     113                 :             :                                   session->port);
     114                 :             : 
     115                 :           0 :   return session;
     116                 :             : }
     117                 :             : 
     118                 :             : static void
     119                 :           0 : sftp_session_free (gpointer data)
     120                 :             : {
     121                 :           0 :   ValentSftpSession *session = data;
     122                 :             : 
     123         [ #  # ]:           0 :   g_clear_pointer (&session->host, g_free);
     124         [ #  # ]:           0 :   g_clear_pointer (&session->username, g_free);
     125         [ #  # ]:           0 :   g_clear_pointer (&session->password, g_free);
     126                 :             : 
     127         [ #  # ]:           0 :   g_clear_object (&session->mount);
     128         [ #  # ]:           0 :   g_clear_pointer (&session->uri, g_free);
     129                 :             : 
     130                 :           0 :   g_free (session);
     131                 :           0 : }
     132                 :             : 
     133                 :             : static void
     134                 :           0 : sftp_session_end_cb (GMount       *mount,
     135                 :             :                      GAsyncResult *result,
     136                 :             :                      gpointer      user_data)
     137                 :             : {
     138                 :           0 :   g_autoptr (GError) error = NULL;
     139                 :             : 
     140         [ #  # ]:           0 :   if (!g_mount_unmount_with_operation_finish (mount, result, &error))
     141                 :           0 :     g_debug ("Failed unmounting: %s", error->message);
     142                 :           0 : }
     143                 :             : 
     144                 :             : static void
     145                 :           0 : sftp_session_end (gpointer data)
     146                 :             : {
     147                 :           0 :   ValentSftpSession *session = data;
     148                 :           0 :   g_autoptr (GMount) mount = NULL;
     149                 :           0 :   g_autoptr (GMountOperation) op = NULL;
     150                 :             : 
     151                 :           0 :   mount = g_steal_pointer (&session->mount);
     152                 :           0 :   sftp_session_free (session);
     153                 :             : 
     154         [ #  # ]:           0 :   if (mount == NULL)
     155                 :             :     return;
     156                 :             : 
     157                 :           0 :   op = g_mount_operation_new ();
     158         [ #  # ]:           0 :   g_mount_unmount_with_operation (mount,
     159                 :             :                                   G_MOUNT_UNMOUNT_FORCE,
     160                 :             :                                   op,
     161                 :             :                                   NULL,
     162                 :             :                                   (GAsyncReadyCallback)sftp_session_end_cb,
     163                 :             :                                   NULL);
     164                 :             : }
     165                 :             : 
     166                 :             : static gboolean
     167                 :           4 : sftp_session_find (ValentSftpPlugin *self)
     168                 :             : {
     169                 :           8 :   g_autofree char *host = NULL;
     170                 :           4 :   g_autofree char *host_pattern = NULL;
     171                 :           4 :   g_autoptr (GRegex) regex = NULL;
     172         [ +  - ]:           4 :   g_autolist (GMount) mounts = NULL;
     173                 :             : 
     174   [ -  +  -  - ]:           4 :   if (self->session && self->session->mount)
     175                 :             :     return TRUE;
     176                 :             : 
     177         [ +  - ]:           4 :   if ((host = get_device_host (self)) == NULL)
     178                 :             :     return FALSE;
     179                 :             : 
     180                 :             :   // TODO: is this reasonable?
     181                 :           4 :   host_pattern = g_strdup_printf ("sftp://(%s):([22-65535])", host);
     182                 :           4 :   regex = g_regex_new (host_pattern, G_REGEX_OPTIMIZE, 0, NULL);
     183                 :             : 
     184                 :             :   /* Search through each mount in the volume monitor... */
     185                 :           4 :   mounts = g_volume_monitor_get_mounts (self->monitor);
     186                 :             : 
     187         [ -  + ]:           4 :   for (const GList *iter = mounts; iter; iter = iter->next)
     188                 :             :     {
     189                 :           4 :       g_autoptr (GFile) root = NULL;
     190   [ #  #  #  # ]:           0 :       g_autofree char *uri = NULL;
     191                 :             : 
     192                 :           0 :       root = g_mount_get_root (iter->data);
     193                 :           0 :       uri = g_file_get_uri (root);
     194                 :             : 
     195                 :             :       /* The URI matches our mount */
     196         [ #  # ]:           0 :       if (g_regex_match (regex, uri, 0, NULL))
     197                 :             :         {
     198         [ #  # ]:           0 :           if (self->session == NULL)
     199                 :           0 :             self->session = g_new0 (ValentSftpSession, 1);
     200                 :             : 
     201                 :           0 :           g_set_object (&self->session->mount, iter->data);
     202                 :           0 :           g_set_str (&self->session->uri, uri);
     203                 :             : 
     204                 :           0 :           return TRUE;
     205                 :             :         }
     206                 :             :     }
     207                 :             : 
     208                 :             :   return FALSE;
     209                 :             : }
     210                 :             : 
     211                 :             : 
     212                 :             : /*
     213                 :             :  * GVolumeMonitor Callbacks
     214                 :             :  */
     215                 :             : static void
     216                 :           0 : on_mount_added (GVolumeMonitor   *volume_monitor,
     217                 :             :                 GMount           *mount,
     218                 :             :                 ValentSftpPlugin *self)
     219                 :             : {
     220                 :           0 :   g_autoptr (GFile) root = NULL;
     221         [ #  # ]:           0 :   g_autofree char *uri = NULL;
     222                 :             : 
     223         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     224                 :             : 
     225         [ #  # ]:           0 :   if (self->session == NULL)
     226                 :           0 :     return;
     227                 :             : 
     228                 :           0 :   root = g_mount_get_root (mount);
     229                 :           0 :   uri = g_file_get_uri (root);
     230                 :             : 
     231         [ #  # ]:           0 :   if (g_strcmp0 (self->session->uri, uri) == 0)
     232                 :           0 :     g_set_object (&self->session->mount, mount);
     233                 :             : }
     234                 :             : 
     235                 :             : static void
     236                 :           0 : on_mount_removed (GVolumeMonitor   *volume_monitor,
     237                 :             :                   GMount           *mount,
     238                 :             :                   ValentSftpPlugin *self)
     239                 :             : {
     240                 :           0 :   g_autoptr (GFile) root = NULL;
     241         [ #  # ]:           0 :   g_autofree char *uri = NULL;
     242                 :             : 
     243         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     244                 :             : 
     245         [ #  # ]:           0 :   if (self->session == NULL)
     246                 :           0 :     return;
     247                 :             : 
     248                 :           0 :   root = g_mount_get_root (mount);
     249                 :           0 :   uri = g_file_get_uri (root);
     250                 :             : 
     251         [ #  # ]:           0 :   if (g_strcmp0 (self->session->uri, uri) == 0)
     252         [ #  # ]:           0 :     g_clear_pointer (&self->session, sftp_session_free);
     253                 :             : }
     254                 :             : 
     255                 :             : 
     256                 :             : /* GMountOperation Callbacks
     257                 :             :  *
     258                 :             :  * Rather than setting the password ahead of time, we set it upon request to
     259                 :             :  * avoid password authentication if possible.
     260                 :             :  *
     261                 :             :  * All host keys are accepted since we connect to known hosts as communicated
     262                 :             :  * over the TLS encrypted `ValentLanChannel`.
     263                 :             :  */
     264                 :             : static void
     265                 :           0 : ask_password_cb (GMountOperation   *op,
     266                 :             :                  char              *message,
     267                 :             :                  char              *default_user,
     268                 :             :                  char              *default_domain,
     269                 :             :                  GAskPasswordFlags  flags,
     270                 :             :                  gpointer           user_data)
     271                 :             : {
     272                 :           0 :   ValentSftpSession *session = user_data;
     273                 :             : 
     274         [ #  # ]:           0 :   if (flags & G_ASK_PASSWORD_NEED_USERNAME)
     275                 :           0 :     g_mount_operation_set_username (op, session->username);
     276                 :             : 
     277         [ #  # ]:           0 :   if (flags & G_ASK_PASSWORD_NEED_PASSWORD)
     278                 :             :     {
     279                 :           0 :       g_mount_operation_set_password (op, session->password);
     280                 :           0 :       g_mount_operation_set_password_save (op, G_PASSWORD_SAVE_NEVER);
     281                 :             :     }
     282                 :             : 
     283                 :           0 :   g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED);
     284                 :           0 : }
     285                 :             : 
     286                 :             : static void
     287                 :           0 : ask_question_cb (GMountOperation *op,
     288                 :             :                  char            *message,
     289                 :             :                  GStrv            choices,
     290                 :             :                  gpointer         user_data)
     291                 :             : {
     292                 :           0 :   g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED);
     293                 :           0 : }
     294                 :             : 
     295                 :             : /**
     296                 :             :  * remove_host_key:
     297                 :             :  * @host: An IP or hostname
     298                 :             :  *
     299                 :             :  * Remove all host keys associated with @host from the ssh-agent.
     300                 :             :  */
     301                 :             : static void
     302                 :           0 : remove_host_key (const char *host)
     303                 :             : {
     304         [ #  # ]:           0 :   g_assert (host != NULL);
     305                 :             : 
     306         [ #  # ]:           0 :   for (uint16_t port = 1739; port <= 1764; port++)
     307                 :             :     {
     308                 :           0 :       g_autoptr (GSubprocess) proc = NULL;
     309         [ #  # ]:           0 :       g_autofree char *match = NULL;
     310                 :             : 
     311                 :           0 :       match = g_strdup_printf ("[%s]:%d", host, port);
     312                 :           0 :       proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE |
     313                 :             :                                G_SUBPROCESS_FLAGS_STDERR_MERGE,
     314                 :             :                                NULL,
     315                 :             :                                "ssh-keygen", "-R", match,
     316                 :             :                                NULL);
     317                 :             : 
     318         [ #  # ]:           0 :       if (proc != NULL)
     319                 :           0 :         g_subprocess_wait_async (proc, NULL, NULL, NULL);
     320                 :             :     }
     321                 :           0 : }
     322                 :             : 
     323                 :             : /*
     324                 :             :  * Packet Handlers
     325                 :             :  */
     326                 :             : static void
     327                 :           0 : mount_cb (GFile            *file,
     328                 :             :           GAsyncResult     *result,
     329                 :             :           ValentSftpPlugin *self)
     330                 :             : {
     331                 :           0 :   g_autoptr (GError) error = NULL;
     332                 :             : 
     333         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     334                 :             : 
     335                 :             :   /* On success we will acquire the mount from the volume monitor */
     336         [ #  # ]:           0 :   if (g_file_mount_enclosing_volume_finish (file, result, &error))
     337                 :             :     return;
     338                 :             : 
     339                 :             :   /* On the off-chance this happens, we will just ensure we have the mount */
     340   [ #  #  #  # ]:           0 :   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ALREADY_MOUNTED) &&
     341                 :           0 :       sftp_session_find (self))
     342                 :             :     return;
     343                 :             : 
     344                 :             :   /* On failure, we're particularly interested in host key failures so that
     345                 :             :    * we can remove those from the ssh-agent. These are reported by GVfs as
     346                 :             :    * G_IO_ERROR_FAILED with a localized string, so we just assume. */
     347         [ #  # ]:           0 :   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED))
     348                 :             :     {
     349                 :           0 :       g_warning ("%s(): Error mounting: %s", G_STRFUNC, error->message);
     350                 :             : 
     351   [ #  #  #  # ]:           0 :       if (self->session && self->session->host)
     352                 :           0 :         remove_host_key (self->session->host);
     353                 :             :     }
     354                 :             : 
     355   [ #  #  #  # ]:           0 :   g_clear_pointer (&self->session, sftp_session_free);
     356                 :             : }
     357                 :             : 
     358                 :             : static void
     359                 :           0 : ssh_add_cb (GSubprocess      *proc,
     360                 :             :             GAsyncResult     *result,
     361                 :             :             ValentSftpPlugin *self)
     362                 :             : {
     363                 :           0 :   ValentSftpSession *session = self->session;
     364                 :           0 :   g_autoptr (GError) error = NULL;
     365   [ #  #  #  # ]:           0 :   g_autoptr (GFile) file = NULL;
     366   [ #  #  #  # ]:           0 :   g_autoptr (GMountOperation) op = NULL;
     367                 :             : 
     368         [ #  # ]:           0 :   g_assert (self->session != NULL);
     369                 :             : 
     370         [ #  # ]:           0 :   if (!g_subprocess_wait_check_finish (proc, result, &error))
     371                 :             :     {
     372                 :           0 :       g_warning ("%s(): Failed to add host key: %s", G_STRFUNC, error->message);
     373         [ #  # ]:           0 :       g_clear_pointer (&self->session, sftp_session_free);
     374         [ #  # ]:           0 :       return;
     375                 :             :     }
     376                 :             : 
     377                 :             :   /* Prepare the mount operation */
     378                 :           0 :   op = g_mount_operation_new ();
     379                 :           0 :   g_signal_connect (op, "ask-password", G_CALLBACK (ask_password_cb), session);
     380                 :           0 :   g_signal_connect (op, "ask-question", G_CALLBACK (ask_question_cb), NULL);
     381                 :             : 
     382                 :             :   /* Start the mount operation */
     383                 :           0 :   file = g_file_new_for_uri (session->uri);
     384         [ #  # ]:           0 :   g_file_mount_enclosing_volume (file,
     385                 :             :                                  G_MOUNT_MOUNT_NONE,
     386                 :             :                                  op,
     387                 :             :                                  NULL,
     388                 :             :                                  (GAsyncReadyCallback)mount_cb,
     389                 :             :                                  self);
     390                 :             : }
     391                 :             : 
     392                 :             : static void
     393                 :           0 : sftp_session_begin (ValentSftpPlugin  *self,
     394                 :             :                     ValentSftpSession *session)
     395                 :             : {
     396                 :           0 :   g_autoptr (ValentContext) context = NULL;
     397   [ #  #  #  # ]:           0 :   g_autoptr (GSubprocess) proc = NULL;
     398         [ #  # ]:           0 :   g_autoptr (GError) error = NULL;
     399   [ #  #  #  # ]:           0 :   g_autoptr (GFile) private_key = NULL;
     400                 :             : 
     401         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     402                 :             : 
     403                 :             :   /* Get the root context and add the private key to the ssh-agent */
     404                 :           0 :   context = valent_context_new (NULL, NULL, NULL);
     405                 :           0 :   private_key = valent_context_get_config_file (context, "private.pem");
     406                 :           0 :   proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE |
     407                 :             :                            G_SUBPROCESS_FLAGS_STDERR_MERGE,
     408                 :             :                            &error,
     409                 :             :                            "ssh-add", g_file_peek_path (private_key),
     410                 :             :                            NULL);
     411                 :             : 
     412         [ #  # ]:           0 :   if (proc == NULL)
     413                 :             :     {
     414                 :           0 :       g_warning ("%s(): Failed to add host key: %s", G_STRFUNC, error->message);
     415         [ #  # ]:           0 :       g_clear_pointer (&self->session, sftp_session_free);
     416         [ #  # ]:           0 :       return;
     417                 :             :     }
     418                 :             : 
     419         [ #  # ]:           0 :   g_subprocess_wait_check_async (proc,
     420                 :             :                                  NULL,
     421                 :             :                                  (GAsyncReadyCallback)ssh_add_cb,
     422                 :             :                                  self);
     423                 :             : }
     424                 :             : 
     425                 :             : 
     426                 :             : /*
     427                 :             :  * Packet Handlers
     428                 :             :  */
     429                 :             : static void
     430                 :           1 : handle_sftp_error (ValentSftpPlugin *self,
     431                 :             :                    JsonNode         *packet)
     432                 :             : {
     433                 :           1 :   ValentDevice *device;
     434                 :           2 :   g_autoptr (GNotification) notification = NULL;
     435         [ +  - ]:           1 :   g_autoptr (GIcon) error_icon = NULL;
     436         [ +  - ]:           1 :   g_autofree char *error_title = NULL;
     437                 :           1 :   const char *error_message;
     438                 :           1 :   const char *device_name;
     439                 :           1 :   JsonObject *body;
     440                 :             : 
     441         [ +  - ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     442                 :             : 
     443                 :           1 :   body = valent_packet_get_body (packet);
     444                 :             : 
     445                 :           1 :   device = valent_extension_get_object (VALENT_EXTENSION (self));
     446                 :           1 :   device_name = valent_device_get_name (device);
     447                 :             : 
     448                 :           1 :   error_icon = g_themed_icon_new ("dialog-error-symbolic");
     449                 :           1 :   error_title = g_strdup_printf ("%s: SFTP", device_name);
     450                 :           1 :   error_message = json_object_get_string_member (body, "errorMessage");
     451                 :             : 
     452                 :             :   /* Send notification */
     453                 :           1 :   notification = g_notification_new (error_title);
     454                 :           1 :   g_notification_set_body (notification, error_message);
     455                 :           1 :   g_notification_set_icon (notification, error_icon);
     456                 :           1 :   g_notification_set_priority (notification, G_NOTIFICATION_PRIORITY_HIGH);
     457                 :           1 :   valent_device_plugin_show_notification (VALENT_DEVICE_PLUGIN (self),
     458                 :             :                                           "sftp-error",
     459                 :             :                                           notification);
     460                 :           1 : }
     461                 :             : 
     462                 :             : static void
     463                 :           0 : handle_sftp_mount (ValentSftpPlugin *self,
     464                 :             :                    JsonNode         *packet)
     465                 :             : {
     466         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     467                 :             : 
     468                 :             :   /* Check if we're already mounted or mounting */
     469         [ #  # ]:           0 :   if (self->session != NULL)
     470                 :             :     return;
     471                 :             : 
     472                 :             :   /* Parse the connection data */
     473                 :           0 :   self->session = sftp_session_new (self, packet);
     474                 :             : 
     475         [ #  # ]:           0 :   if (self->session != NULL)
     476                 :           0 :     sftp_session_begin (self, self->session);
     477                 :             : }
     478                 :             : 
     479                 :             : static void
     480                 :           1 : valent_sftp_plugin_handle_sftp (ValentSftpPlugin *self,
     481                 :             :                                 JsonNode         *packet)
     482                 :             : {
     483         [ +  - ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     484                 :             : 
     485                 :             :   /* The request for mount information failed, most likely due to the remote
     486                 :             :    * device not being setup yet.
     487                 :             :    */
     488         [ +  - ]:           1 :   if (valent_packet_check_field (packet, "errorMessage"))
     489                 :           1 :     handle_sftp_error (self, packet);
     490                 :             : 
     491                 :             :   /* Otherwise we've been sent the information necessary to open an SSH/SFTP
     492                 :             :    * connection to the remote device.
     493                 :             :    */
     494                 :             :   else
     495                 :           0 :     handle_sftp_mount (self, packet);
     496                 :           1 : }
     497                 :             : 
     498                 :             : /*
     499                 :             :  * Packet Providers
     500                 :             :  */
     501                 :             : static void
     502                 :           1 : valent_sftp_plugin_handle_request (ValentSftpPlugin *self,
     503                 :             :                                    JsonNode         *packet)
     504                 :             : {
     505                 :           1 :   GSettings *settings;
     506                 :           1 :   g_autoptr (JsonBuilder) builder = NULL;
     507   [ -  -  -  + ]:           1 :   g_autoptr (JsonNode) response = NULL;
     508                 :             : 
     509         [ +  - ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     510                 :             : 
     511         [ -  + ]:           1 :   if (!valent_packet_check_field (packet, "startBrowsing"))
     512         [ #  # ]:           0 :     return;
     513                 :             : 
     514                 :           1 :   settings = valent_extension_get_settings (VALENT_EXTENSION (self));
     515                 :           1 :   valent_packet_init (&builder, "kdeconnect.sftp");
     516                 :             : 
     517         [ -  + ]:           1 :   if (g_settings_get_boolean (settings, "local-allow"))
     518                 :             :     {
     519                 :           0 :       uint16_t local_port;
     520                 :             : 
     521                 :           0 :       json_builder_set_member_name (builder, "user");
     522                 :           0 :       json_builder_add_string_value (builder, g_get_user_name ());
     523                 :             : 
     524                 :           0 :       local_port = g_settings_get_uint (settings, "local-port");
     525                 :           0 :       json_builder_set_member_name (builder, "port");
     526                 :           0 :       json_builder_add_int_value (builder, local_port);
     527                 :             : 
     528                 :           0 :       json_builder_set_member_name (builder, "multiPaths");
     529                 :           0 :       json_builder_begin_array (builder);
     530                 :           0 :       json_builder_add_string_value (builder, g_get_home_dir ());
     531                 :           0 :       json_builder_end_array (builder);
     532                 :             : 
     533                 :           0 :       json_builder_set_member_name (builder, "pathNames");
     534                 :           0 :       json_builder_begin_array (builder);
     535                 :           0 :       json_builder_add_string_value (builder, _("Home"));
     536                 :           0 :       json_builder_end_array (builder);
     537                 :             :     }
     538                 :             :   else
     539                 :             :     {
     540                 :           1 :       json_builder_set_member_name (builder, "errorMessage");
     541                 :           1 :       json_builder_add_string_value (builder, _("Permission denied"));
     542                 :             :     }
     543                 :             : 
     544                 :           1 :   response = valent_packet_end (&builder);
     545         [ +  - ]:           1 :   valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), response);
     546                 :             : }
     547                 :             : 
     548                 :             : static void
     549                 :           1 : valent_sftp_plugin_sftp_request (ValentSftpPlugin *self)
     550                 :             : {
     551                 :           1 :   g_autoptr (JsonBuilder) builder = NULL;
     552   [ -  -  -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     553                 :             : 
     554         [ +  - ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     555                 :             : 
     556         [ -  + ]:           1 :   if (sftp_session_find (self))
     557         [ #  # ]:           0 :     return;
     558                 :             : 
     559                 :           1 :   valent_packet_init (&builder, "kdeconnect.sftp.request");
     560                 :           1 :   json_builder_set_member_name (builder, "startBrowsing");
     561                 :           1 :   json_builder_add_boolean_value (builder, TRUE);
     562                 :           1 :   packet = valent_packet_end (&builder);
     563                 :             : 
     564         [ +  - ]:           1 :   valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), packet);
     565                 :             : }
     566                 :             : 
     567                 :             : /*
     568                 :             :  * GActions
     569                 :             :  */
     570                 :             : static void
     571                 :           1 : mount_action (GSimpleAction *action,
     572                 :             :               GVariant      *parameter,
     573                 :             :               gpointer       user_data)
     574                 :             : {
     575                 :           1 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (user_data);
     576                 :             : 
     577         [ +  - ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     578                 :             : 
     579   [ -  +  -  - ]:           1 :   if (self->session != NULL && self->session->uri != NULL)
     580                 :           0 :     g_app_info_launch_default_for_uri_async (self->session->uri,
     581                 :             :                                              NULL, NULL, NULL, NULL);
     582                 :             :   else
     583                 :           1 :     valent_sftp_plugin_sftp_request (self);
     584                 :           1 : }
     585                 :             : 
     586                 :             : static const GActionEntry actions[] = {
     587                 :             :     {"browse", mount_action, NULL, NULL, NULL}
     588                 :             : };
     589                 :             : 
     590                 :             : 
     591                 :             : /*
     592                 :             :  * ValentDevicePlugin
     593                 :             :  */
     594                 :             : static void
     595                 :          11 : valent_sftp_plugin_update_state (ValentDevicePlugin *plugin,
     596                 :             :                                  ValentDeviceState   state)
     597                 :             : {
     598                 :          11 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (plugin);
     599                 :          11 :   gboolean available;
     600                 :             : 
     601         [ +  - ]:          11 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     602                 :             : 
     603                 :          11 :   available = (state & VALENT_DEVICE_STATE_CONNECTED) != 0 &&
     604                 :             :               (state & VALENT_DEVICE_STATE_PAIRED) != 0;
     605                 :             : 
     606                 :          11 :   valent_extension_toggle_actions (VALENT_EXTENSION (plugin), available);
     607                 :             : 
     608                 :             :   /* GMounts */
     609         [ +  + ]:          11 :   if (available)
     610                 :             :     {
     611                 :           3 :       GSettings *settings;
     612                 :             : 
     613                 :           3 :       sftp_session_find (self);
     614                 :             : 
     615                 :           3 :       settings = valent_extension_get_settings (VALENT_EXTENSION (plugin));
     616                 :             : 
     617         [ -  + ]:           3 :       if (g_settings_get_boolean (settings, "auto-mount"))
     618                 :           0 :         valent_sftp_plugin_sftp_request (self);
     619                 :             :     }
     620                 :          11 : }
     621                 :             : 
     622                 :             : static void
     623                 :           2 : valent_sftp_plugin_handle_packet (ValentDevicePlugin *plugin,
     624                 :             :                                   const char         *type,
     625                 :             :                                   JsonNode           *packet)
     626                 :             : {
     627                 :           2 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (plugin);
     628                 :             : 
     629         [ +  - ]:           2 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     630         [ -  + ]:           2 :   g_assert (type != NULL);
     631         [ -  + ]:           2 :   g_assert (VALENT_IS_PACKET (packet));
     632                 :             : 
     633         [ +  + ]:           2 :   if (g_str_equal (type, "kdeconnect.sftp"))
     634                 :           1 :     valent_sftp_plugin_handle_sftp (self, packet);
     635                 :             : 
     636         [ +  - ]:           1 :   else if (g_str_equal (type, "kdeconnect.sftp.request"))
     637                 :           1 :     valent_sftp_plugin_handle_request (self, packet);
     638                 :             : 
     639                 :             :   else
     640                 :           0 :     g_warn_if_reached ();
     641                 :           2 : }
     642                 :             : 
     643                 :             : /*
     644                 :             :  * ValentObject
     645                 :             :  */
     646                 :             : static void
     647                 :           8 : valent_sftp_plugin_destroy (ValentObject *object)
     648                 :             : {
     649                 :           8 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (object);
     650                 :           8 :   ValentDevicePlugin *plugin = VALENT_DEVICE_PLUGIN (object);
     651                 :             : 
     652                 :             :   /* Stop watching the volume monitor and unmount any current session */
     653         [ +  + ]:           8 :   if (self->monitor != NULL)
     654                 :             :     {
     655                 :           4 :       g_signal_handlers_disconnect_by_data (self->monitor, self);
     656         [ +  - ]:           4 :       g_clear_object (&self->monitor);
     657                 :             :     }
     658         [ -  + ]:           8 :   g_clear_pointer (&self->session, sftp_session_end);
     659                 :             : 
     660                 :           8 :   valent_device_plugin_set_menu_item (plugin, "device.sftp.browse", NULL);
     661                 :             : 
     662                 :           8 :   VALENT_OBJECT_CLASS (valent_sftp_plugin_parent_class)->destroy (object);
     663                 :           8 : }
     664                 :             : 
     665                 :             : /*
     666                 :             :  * GObject
     667                 :             :  */
     668                 :             : static void
     669                 :           4 : valent_sftp_plugin_constructed (GObject *object)
     670                 :             : {
     671                 :           4 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (object);
     672                 :           4 :   ValentDevicePlugin *plugin = VALENT_DEVICE_PLUGIN (object);
     673                 :             : 
     674                 :           4 :   g_action_map_add_action_entries (G_ACTION_MAP (plugin),
     675                 :             :                                    actions,
     676                 :             :                                    G_N_ELEMENTS (actions),
     677                 :             :                                    plugin);
     678                 :           4 :   valent_device_plugin_set_menu_action (plugin,
     679                 :             :                                         "device.sftp.browse",
     680                 :           4 :                                         _("Browse Files"),
     681                 :             :                                         "folder-remote-symbolic");
     682                 :             : 
     683                 :             :   /* Watch the volume monitor */
     684                 :           4 :   self->monitor = g_volume_monitor_get ();
     685                 :           4 :   g_signal_connect_object (self->monitor,
     686                 :             :                            "mount-added",
     687                 :             :                            G_CALLBACK (on_mount_added),
     688                 :             :                            self, 0);
     689                 :           4 :   g_signal_connect_object (self->monitor,
     690                 :             :                            "mount-removed",
     691                 :             :                            G_CALLBACK (on_mount_removed),
     692                 :             :                            self, 0);
     693                 :             : 
     694                 :           4 :   G_OBJECT_CLASS (valent_sftp_plugin_parent_class)->constructed (object);
     695                 :           4 : }
     696                 :             : 
     697                 :             : static void
     698                 :          18 : valent_sftp_plugin_class_init (ValentSftpPluginClass *klass)
     699                 :             : {
     700                 :          18 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     701                 :          18 :   ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
     702                 :          18 :   ValentDevicePluginClass *plugin_class = VALENT_DEVICE_PLUGIN_CLASS (klass);
     703                 :             : 
     704                 :          18 :   object_class->constructed = valent_sftp_plugin_constructed;
     705                 :             : 
     706                 :          18 :   vobject_class->destroy = valent_sftp_plugin_destroy;
     707                 :             : 
     708                 :          18 :   plugin_class->handle_packet = valent_sftp_plugin_handle_packet;
     709                 :          18 :   plugin_class->update_state = valent_sftp_plugin_update_state;
     710                 :             : }
     711                 :             : 
     712                 :             : static void
     713                 :           4 : valent_sftp_plugin_init (ValentSftpPlugin *self)
     714                 :             : {
     715                 :           4 : }
     716                 :             : 
        

Generated by: LCOV version 2.0-1