From bf9783980b1505d28c4a6512a02e12fe932496f3 Mon Sep 17 00:00:00 2001 From: Alexey Berezhok Date: Mon, 21 Aug 2023 19:05:32 +0300 Subject: [PATCH] Added support of yandex webdav --- ...001-Added-yandex-disk-webdav-support.patch | 299 ++++++++++++++++++ SPECS/gvfs.spec | 6 +- 2 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 SOURCES/0001-Added-yandex-disk-webdav-support.patch diff --git a/SOURCES/0001-Added-yandex-disk-webdav-support.patch b/SOURCES/0001-Added-yandex-disk-webdav-support.patch new file mode 100644 index 0000000..0e834d8 --- /dev/null +++ b/SOURCES/0001-Added-yandex-disk-webdav-support.patch @@ -0,0 +1,299 @@ +From 15b6ce16543e04deabc415f4ff70fca6c767bc7a Mon Sep 17 00:00:00 2001 +From: Alexey Berezhok +Date: Mon, 21 Aug 2023 18:52:07 +0300 +Subject: [PATCH] Added yandex disk webdav support + +--- + daemon/gvfsbackenddav.c | 241 +++++++++++++++++++++++++++++++++++++++- + 1 file changed, 239 insertions(+), 2 deletions(-) + +diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c +index 12de62e..7564924 100644 +--- a/daemon/gvfsbackenddav.c ++++ b/daemon/gvfsbackenddav.c +@@ -119,6 +119,204 @@ struct _GVfsBackendDav + + G_DEFINE_TYPE (GVfsBackendDav, g_vfs_backend_dav, G_VFS_TYPE_BACKEND_HTTP); + ++/*Yandex Oauth, looks like same as basik, but another token*/ ++ ++/* Standard GObject macros */ ++#define E_TYPE_SOUP_AUTH_BEARER \ ++ (e_soup_auth_bearer_get_type ()) ++#define E_SOUP_AUTH_BEARER(obj) \ ++ (G_TYPE_CHECK_INSTANCE_CAST \ ++ ((obj), E_TYPE_SOUP_AUTH_BEARER, ESoupAuthBearer)) ++#define E_SOUP_AUTH_BEARER_CLASS(cls) \ ++ (G_TYPE_CHECK_CLASS_CAST \ ++ ((cls), E_TYPE_SOUP_AUTH_BEARER, ESoupAuthBearerClass)) ++#define E_IS_SOUP_AUTH_BEARER(obj) \ ++ (G_TYPE_CHECK_INSTANCE_TYPE \ ++ ((obj), E_TYPE_SOUP_AUTH_BEARER)) ++#define E_IS_SOUP_AUTH_BEARER_CLASS(cls) \ ++ (G_TYPE_CHECK_CLASS_TYPE \ ++ ((cls), E_TYPE_SOUP_AUTH_BEARER)) ++#define E_SOUP_AUTH_BEARER_GET_CLASS(obj) \ ++ (G_TYPE_INSTANCE_GET_CLASS \ ++ ((obj), E_TYPE_SOUP_AUTH_BEARER, ESoupAuthBearerClass)) ++ ++G_BEGIN_DECLS ++ ++typedef struct _ESoupAuthBearer ESoupAuthBearer; ++typedef struct _ESoupAuthBearerClass ESoupAuthBearerClass; ++typedef struct _ESoupAuthBearerPrivate ESoupAuthBearerPrivate; ++ ++ ++struct _ESoupAuthBearer { ++ /*< private >*/ ++ SoupAuth parent; ++ ESoupAuthBearerPrivate *priv; ++}; ++ ++struct _ESoupAuthBearerClass { ++ SoupAuthClass parent_class; ++}; ++ ++GType e_soup_auth_bearer_get_type (void) G_GNUC_CONST; ++void e_soup_auth_bearer_set_access_token ++ (ESoupAuthBearer *bearer, ++ const gchar *access_token); ++gboolean ++e_soup_auth_bearer_set_custom_bearer_name (ESoupAuthBearer *bearer, ++const gchar *bearer_name); ++ ++G_END_DECLS ++ ++#define OAUTH_SAUTH_STRENGTH 1 ++ ++struct _ESoupAuthBearerPrivate { ++ GMutex property_lock; ++ gchar *access_token; ++}; ++ ++G_DEFINE_TYPE_WITH_PRIVATE ( ++ ESoupAuthBearer, ++ e_soup_auth_bearer, ++ SOUP_TYPE_AUTH) ++ ++static void ++e_soup_auth_bearer_finalize (GObject *object) ++{ ++ ESoupAuthBearerPrivate *priv; ++ ++ priv = E_SOUP_AUTH_BEARER (object)->priv; ++ ++ g_mutex_clear (&priv->property_lock); ++ g_free (priv->access_token); ++ ++ G_OBJECT_CLASS (e_soup_auth_bearer_parent_class)->finalize (object); ++} ++ ++static gboolean ++e_soup_auth_bearer_update (SoupAuth *auth, ++ SoupMessage *message, ++ GHashTable *auth_header) ++{ ++ ++ ESoupAuthBearer *bearer; ++ ++ g_return_val_if_fail (E_IS_SOUP_AUTH_BEARER (auth), FALSE); ++ ++ bearer = E_SOUP_AUTH_BEARER (auth); ++ ++ g_mutex_lock (&bearer->priv->property_lock); ++ ++ if (bearer->priv->access_token){ ++ memset (bearer->priv->access_token, 0, strlen (bearer->priv->access_token)); ++ g_free (bearer->priv->access_token); ++ bearer->priv->access_token = NULL; ++ } ++ ++ g_mutex_unlock (&bearer->priv->property_lock); ++ ++ return TRUE; ++} ++ ++static GSList * ++e_soup_auth_bearer_get_protection_space (SoupAuth *auth, ++ SoupURI *source_uri) ++{ ++ return g_slist_prepend (NULL, g_strdup ("")); ++} ++ ++static gboolean ++e_soup_auth_bearer_is_authenticated (SoupAuth *auth) ++{ ++ ESoupAuthBearer *bearer; ++ gboolean authenticated = FALSE; ++ ++ bearer = E_SOUP_AUTH_BEARER (auth); ++ ++ g_mutex_lock (&bearer->priv->property_lock); ++ ++ authenticated = (bearer->priv->access_token != NULL); ++ ++ g_mutex_unlock (&bearer->priv->property_lock); ++ ++ return authenticated; ++} ++ ++static gchar * ++e_soup_auth_bearer_get_authorization (SoupAuth *auth, ++ SoupMessage *message) ++{ ++ ESoupAuthBearer *bearer; ++ gchar *res; ++ ++ bearer = E_SOUP_AUTH_BEARER (auth); ++ ++ g_mutex_lock (&bearer->priv->property_lock); ++ res = g_strdup_printf ("OAuth %s", bearer->priv->access_token); ++ g_mutex_unlock (&bearer->priv->property_lock); ++ ++ return res; ++} ++ ++static void ++e_soup_auth_bearer_class_init (ESoupAuthBearerClass *class) ++{ ++ GObjectClass *object_class; ++ SoupAuthClass *auth_class; ++ ++ object_class = G_OBJECT_CLASS (class); ++ object_class->finalize = e_soup_auth_bearer_finalize; ++ ++ auth_class = SOUP_AUTH_CLASS (class); ++ auth_class->scheme_name = "Basic"; ++ auth_class->strength = OAUTH_SAUTH_STRENGTH; ++ auth_class->update = e_soup_auth_bearer_update; ++ auth_class->get_protection_space = e_soup_auth_bearer_get_protection_space; ++ auth_class->is_authenticated = e_soup_auth_bearer_is_authenticated; ++ auth_class->get_authorization = e_soup_auth_bearer_get_authorization; ++} ++ ++static void ++e_soup_auth_bearer_init (ESoupAuthBearer *bearer) ++{ ++ bearer->priv = e_soup_auth_bearer_get_instance_private (bearer); ++ g_mutex_init (&bearer->priv->property_lock); ++} ++ ++void ++e_soup_auth_bearer_set_access_token (ESoupAuthBearer *bearer, ++ const gchar *access_token) ++{ ++ gboolean was_authenticated; ++ gboolean now_authenticated; ++ ++ g_return_if_fail (E_IS_SOUP_AUTH_BEARER (bearer)); ++ ++ was_authenticated = soup_auth_is_authenticated (SOUP_AUTH (bearer)); ++ ++ g_mutex_lock (&bearer->priv->property_lock); ++ ++ if (g_strcmp0 (bearer->priv->access_token, access_token) == 0) { ++ g_mutex_unlock (&bearer->priv->property_lock); ++ return; ++ } ++ ++ g_free (bearer->priv->access_token); ++ bearer->priv->access_token = g_strdup (access_token); ++ ++ g_mutex_unlock (&bearer->priv->property_lock); ++ ++ now_authenticated = soup_auth_is_authenticated (SOUP_AUTH (bearer)); ++ ++ if (was_authenticated != now_authenticated) ++ g_object_notify ( ++ G_OBJECT (bearer), ++ SOUP_AUTH_IS_AUTHENTICATED); ++} ++ ++/* ++end of Yandex ouath ++*/ ++ + static void + g_vfs_backend_dav_finalize (GObject *object) + { +@@ -1509,6 +1707,7 @@ soup_authenticate_interactive (SoupSession *session, + char *new_username; + char *new_password; + char *prompt; ++ GType auth_type_oauth; + + data = (MountAuthData *) user_data; + +@@ -1578,7 +1777,13 @@ soup_authenticate_interactive (SoupSession *session, + + if (retrying == FALSE && have_auth) + { +- soup_auth_authenticate (auth, info->username, info->password); ++ auth_type_oauth = G_OBJECT_TYPE (auth); ++ if (auth_type_oauth == E_TYPE_SOUP_AUTH_BEARER){ ++ ESoupAuthBearer *soup_auth_oauth = (ESoupAuthBearer *)auth; ++ e_soup_auth_bearer_set_access_token (soup_auth_oauth, info->password); ++ } else { ++ soup_auth_authenticate (auth, info->username, info->password); ++ } + return; + } + +@@ -1615,7 +1820,13 @@ soup_authenticate_interactive (SoupSession *session, + if (new_username == NULL) + new_username = g_strdup (info->username); + +- soup_auth_authenticate (auth, new_username, new_password); ++ auth_type_oauth = G_OBJECT_TYPE (auth); ++ if (auth_type_oauth == E_TYPE_SOUP_AUTH_BEARER){ ++ ESoupAuthBearer *soup_auth_oauth = (ESoupAuthBearer *)auth; ++ e_soup_auth_bearer_set_access_token (soup_auth_oauth, new_password); ++ } else { ++ soup_auth_authenticate (auth, new_username, new_password); ++ } + + g_free (info->username); + g_free (info->password); +@@ -1860,6 +2071,7 @@ do_mount (GVfsBackend *backend, + char *last_good_path; + const char *host; + const char *type; ++ SoupAuth *soup_auth_oauth; + + g_debug ("+ mount\n"); + +@@ -1923,6 +2135,31 @@ do_mount (GVfsBackend *backend, + data->server_auth.pw_save = G_PASSWORD_SAVE_NEVER; + data->proxy_auth.pw_save = G_PASSWORD_SAVE_NEVER; + ++ if (!g_strcmp0("webdav.yandex.ru",mount_base->host)){ ++ SoupAuthManager *auth_manager; ++ GType auth_type_outh; ++ soup_auth_oauth = g_object_new ( ++ E_TYPE_SOUP_AUTH_BEARER, ++ SOUP_AUTH_HOST, mount_base->host, NULL); ++ SoupSessionFeature *feature; ++ feature = soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER); ++ auth_type_outh = G_OBJECT_TYPE (soup_auth_oauth); ++ ++ if (soup_session_feature_has_feature (feature, SOUP_TYPE_AUTH_BASIC)){ ++ soup_session_feature_remove_feature(feature, SOUP_TYPE_AUTH_BASIC); ++ } ++ ++ if (!soup_session_feature_has_feature (feature, auth_type_outh)) { ++ soup_session_feature_add_feature (feature, auth_type_outh); ++ } ++ ++ auth_manager = SOUP_AUTH_MANAGER (feature); ++ ++ soup_auth_manager_clear_cached_credentials (auth_manager); ++ soup_auth_manager_use_auth (auth_manager, mount_base, soup_auth_oauth); ++ g_object_unref(soup_auth_oauth); ++ } ++ + signal_id = g_signal_connect (session, "authenticate", + G_CALLBACK (soup_authenticate_interactive), + data); +-- +2.39.1 + diff --git a/SPECS/gvfs.spec b/SPECS/gvfs.spec index c5cc337..8d80e87 100644 --- a/SPECS/gvfs.spec +++ b/SPECS/gvfs.spec @@ -22,7 +22,7 @@ Name: gvfs Version: 1.48.1 -Release: 4%{?dist}.inferit +Release: 4%{?dist}.inferit.1 Summary: Backends for the gio framework in GLib License: GPLv3 and LGPLv2+ and BSD and MPLv2.0 @@ -34,6 +34,7 @@ Patch0: smb-Ignore-EINVAL-for-kerberos-ccache-login.patch Patch1: smb-Rework-anonymous-handling-to-avoid-EINVAL.patch #MSVSphere Patch1000: 0001-Updated-Russian-translation.patch +Patch1001: 0001-Added-yandex-disk-webdav-support.patch BuildRequires: meson BuildRequires: gcc @@ -431,6 +432,9 @@ killall -USR1 gvfsd >&/dev/null || : %{_datadir}/installed-tests %changelog +* Mon Aug 21 2023 Alexey Berezhok - 1.48.1-4.inferit.1 +- Added support of yandex webdav + * Thu Jul 20 2023 Sergey Cherevko - 1.48.1-4.inferit - Updated Russian translation - Rebuilt for MSVSphere 9.2