From 2212488b777035a619633284515c657075c9ed0d Mon Sep 17 00:00:00 2001 From: Dmitry Samoylik Date: Mon, 10 Feb 2025 14:30:49 +0300 Subject: [PATCH] Added yandex provider --- data/icons/meson.build | 2 + data/icons/scalable/goa-account-yandex.svg | 45 ++ .../symbolic/goa-account-yandex-symbolic.svg | 45 ++ meson.build | 12 + meson_options.txt | 4 + src/goabackend/goaoauth2handler.c | 7 + src/goabackend/goaprovider.c | 4 + src/goabackend/goayandexprovider.c | 402 ++++++++++++++++++ src/goabackend/goayandexprovider.h | 37 ++ src/goabackend/meson.build | 1 + 10 files changed, 559 insertions(+) create mode 100644 data/icons/scalable/goa-account-yandex.svg create mode 100644 data/icons/symbolic/goa-account-yandex-symbolic.svg create mode 100644 src/goabackend/goayandexprovider.c create mode 100644 src/goabackend/goayandexprovider.h diff --git a/data/icons/meson.build b/data/icons/meson.build index fdc661a..e32b7cf 100644 --- a/data/icons/meson.build +++ b/data/icons/meson.build @@ -6,6 +6,7 @@ icon_scalable_data = [ 'goa-account-ms365.svg', 'goa-account-msn.svg', 'goa-account-owncloud.svg', + 'goa-account-yandex.svg', ] icon_symbolic_data = [ @@ -14,6 +15,7 @@ icon_symbolic_data = [ 'goa-account-google-symbolic.svg', 'goa-account-msn-symbolic.svg', 'goa-account-owncloud-symbolic.svg', + 'goa-account-yandex-symbolic.svg', ] icons = [ diff --git a/data/icons/scalable/goa-account-yandex.svg b/data/icons/scalable/goa-account-yandex.svg new file mode 100644 index 0000000..dd7624f --- /dev/null +++ b/data/icons/scalable/goa-account-yandex.svg @@ -0,0 +1,45 @@ + + + + + + + diff --git a/data/icons/symbolic/goa-account-yandex-symbolic.svg b/data/icons/symbolic/goa-account-yandex-symbolic.svg new file mode 100644 index 0000000..528713f --- /dev/null +++ b/data/icons/symbolic/goa-account-yandex-symbolic.svg @@ -0,0 +1,45 @@ + + + + + + + diff --git a/meson.build b/meson.build index 95e17de..9d08775 100644 --- a/meson.build +++ b/meson.build @@ -174,6 +174,18 @@ config_h.set_quoted('GOA_GOOGLE_CLIENT_SECRET', google_client_secret) enable_google = get_option('google') config_h.set('GOA_GOOGLE_ENABLED', enable_google) +# Yandex +config_h.set_quoted('GOA_YANDEX_NAME', 'yandex') + +yandex_client_id = get_option('yandex_client_id') +config_h.set_quoted('GOA_YANDEX_CLIENT_ID', yandex_client_id) + +yandex_client_secret = get_option('yandex_client_secret') +config_h.set_quoted('GOA_YANDEX_CLIENT_SECRET', yandex_client_secret) + +enable_yandex = get_option('yandex') +config_h.set('GOA_YANDEX_ENABLED', enable_yandex) + # IMAP/SMTP config_h.set_quoted('GOA_IMAP_SMTP_NAME', 'imap_smtp') diff --git a/meson_options.txt b/meson_options.txt index 7b2d208..dfe22af 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,6 +8,10 @@ option('google', type: 'boolean', value: true, description: 'Enable Google provi option('google_client_id', type: 'string', value: '44438659992-7kgjeitenc16ssihbtdjbgguch7ju55s.apps.googleusercontent.com', description: 'Google OAuth 2.0 client id') option('google_client_secret', type: 'string', value: '-gMLuQyDiI0XrQS_vx_mhuYF', description: 'Google OAuth 2.0 client secret') +option('yandex', type: 'boolean', value: true, description: 'Enable Yandex provider') +option('yandex_client_id', type: 'string', value: 'aab3f89a0d504003bfa3bb5326f68575', description: 'Yandex OAuth 2.0 client id') +option('yandex_client_secret', type: 'string', value: '4e6f4755f2ec457e9a80f0f43683fc32', description: 'Yandex OAuth 2.0 client secret') + option('imap_smtp', type: 'boolean', value: true, description: 'Enable IMAP/SMTP provider') option('kerberos', type: 'boolean', value: true, description: 'Enable kerberos provider') diff --git a/src/goabackend/goaoauth2handler.c b/src/goabackend/goaoauth2handler.c index d510d3b..cd295c4 100644 --- a/src/goabackend/goaoauth2handler.c +++ b/src/goabackend/goaoauth2handler.c @@ -56,6 +56,11 @@ oauth2_providers[] = { .client_id = GOA_MS_GRAPH_CLIENT_ID, }, +#endif +#ifdef GOA_YANDEX_ENABLED + { + .client_id = GOA_YANDEX_CLIENT_ID, + }, #endif { NULL }, }; @@ -141,6 +146,8 @@ main (int argc, return EXIT_FAILURE; } + g_printerr("argv1: %s client_id: %s \n", argv[1], client_id); + if (!secret_password_store_sync (&oauth2_schema, SECRET_COLLECTION_SESSION, "GNOME Online Accounts OAuth2 URI", diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c index b763c1e..1e5ce4f 100644 --- a/src/goabackend/goaprovider.c +++ b/src/goabackend/goaprovider.c @@ -30,6 +30,7 @@ #include "goawebdavprovider.h" #include "goawindowsliveprovider.h" #include "goamsgraphprovider.h" +#include "goayandexprovider.h" #ifdef GOA_FEDORA_ENABLED #include "goafedoraprovider.h" @@ -1176,6 +1177,9 @@ static struct * important because it affects the order in which they are * returned by goa_provider_get_all. */ +#ifdef GOA_YANDEX_ENABLED + { GOA_YANDEX_NAME, goa_yandex_provider_get_type }, +#endif #ifdef GOA_GOOGLE_ENABLED { GOA_GOOGLE_NAME, goa_google_provider_get_type }, #endif diff --git a/src/goabackend/goayandexprovider.c b/src/goabackend/goayandexprovider.c new file mode 100644 index 0000000..d8c79a9 --- /dev/null +++ b/src/goabackend/goayandexprovider.c @@ -0,0 +1,402 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright © 2011 – 2017 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" +#include + +#include +#include + +#include "goaprovider.h" +#include "goaprovider-priv.h" +#include "goaoauth2provider.h" +#include "goayandexprovider.h" +#include "goaobjectskeletonutils.h" +#include "goarestproxy.h" + +struct _GoaYandexProvider +{ + GoaOAuth2Provider parent_instance; + gchar *redirect_uri; +}; + +G_DEFINE_TYPE_WITH_CODE (GoaYandexProvider, goa_yandex_provider, GOA_TYPE_OAUTH2_PROVIDER, + goa_provider_ensure_extension_points_registered (); + g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME, + g_define_type_id, + GOA_YANDEX_NAME, + 0)); + +/* ---------------------------------------------------------------------------------------------------- */ + +static const gchar * +get_provider_type (GoaProvider *provider) +{ + return GOA_YANDEX_NAME; +} + +static gchar * +get_provider_name (GoaProvider *provider, + GoaObject *object) +{ + return g_strdup (_("Yandex")); +} + +static GoaProviderGroup +get_provider_group (GoaProvider *provider) +{ + return GOA_PROVIDER_GROUP_BRANDED; +} + +static GoaProviderFeatures +get_provider_features (GoaProvider *provider) +{ + return GOA_PROVIDER_FEATURE_BRANDED | + GOA_PROVIDER_FEATURE_MAIL | + GOA_PROVIDER_FEATURE_CALENDAR | +// GOA_PROVIDER_FEATURE_CONTACTS | + GOA_PROVIDER_FEATURE_FILES; +} + +static const gchar * +get_authorization_uri (GoaOAuth2Provider *oauth2_provider) +{ + return "https://oauth.yandex.ru/authorize"; +} + +static const gchar * +get_token_uri (GoaOAuth2Provider *oauth2_provider) +{ + return "https://oauth.yandex.ru/token"; +} + +static const gchar * +get_redirect_uri (GoaOAuth2Provider *oauth2_provider) +{ + G_LOCK_DEFINE_STATIC (redirect_uri); + GoaYandexProvider *self = GOA_YANDEX_PROVIDER (oauth2_provider); + + G_LOCK (redirect_uri); + + if (!self->redirect_uri) { + self->redirect_uri = g_strconcat ("goa-oauth2://localhost/", GOA_YANDEX_CLIENT_ID, NULL); + // self->redirect_uri = GOA_YANDEX_CLIENT_ID":goa-oauth2://localhost/"; + // self->redirect_uri = "goa-oauth2://localhost/"; + } + + G_UNLOCK (redirect_uri); + + return self->redirect_uri; + +} + +static const gchar * +get_scope (GoaOAuth2Provider *oauth2_provider) +{ + return "login:email login:info mail:imap_full mail:imap_ro mail:smtp calendar:all yadisk:disk cloud_api:disk.read cloud_api:disk.write"; +} + +static guint +get_credentials_generation (GoaProvider *provider) +{ + return 37; +} + +static const gchar * +get_client_id (GoaOAuth2Provider *oauth2_provider) +{ + return GOA_YANDEX_CLIENT_ID; +} + +static const gchar * +get_client_secret (GoaOAuth2Provider *oauth2_provider) +{ + return GOA_YANDEX_CLIENT_SECRET; +} + +static gboolean +get_use_pkce (GoaOAuth2Provider *oauth2_provider) +{ + return FALSE; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gchar * +get_identity_sync (GoaOAuth2Provider *oauth2_provider, + const gchar *access_token, + gchar **out_presentation_identity, + GCancellable *cancellable, + GError **error) +{ + GError *identity_error = NULL; + RestProxy *proxy = NULL; + RestProxyCall *call = NULL; + JsonParser *parser = NULL; + JsonObject *json_object; + gchar *ret = NULL; + gchar *id = NULL; + + /* TODO: cancellable */ + + proxy = goa_rest_proxy_new ("https://login.yandex.ru/info", FALSE); + call = rest_proxy_new_call (proxy); + rest_proxy_call_set_method (call, "GET"); + rest_proxy_call_add_param (call, "oauth_token", access_token); + + if (!rest_proxy_call_sync (call, error)) + goto out; + if (rest_proxy_call_get_status_code (call) != 200) + { + g_set_error (error, + GOA_ERROR, + GOA_ERROR_FAILED, + _("Expected status 200 when requesting your identity, instead got status %d (%s)"), + rest_proxy_call_get_status_code (call), + rest_proxy_call_get_status_message (call)); + goto out; + } + + parser = json_parser_new (); + if (!json_parser_load_from_data (parser, + rest_proxy_call_get_payload (call), + rest_proxy_call_get_payload_length (call), + &identity_error)) + { + g_warning ("json_parser_load_from_data() failed: %s (%s, %d)", + identity_error->message, + g_quark_to_string (identity_error->domain), + identity_error->code); + g_set_error (error, + GOA_ERROR, + GOA_ERROR_FAILED, + _("Could not parse response")); + goto out; + } + + json_object = json_node_get_object (json_parser_get_root (parser)); + if (!json_object_has_member (json_object, "default_email")) + { + g_warning ("Did not find emails in JSON data"); + g_set_error (error, + GOA_ERROR, + GOA_ERROR_FAILED, + _("Could not parse response")); + goto out; + } + + id = g_strdup (json_object_get_string_member (json_object, "default_email")); + + ret = id; + id = NULL; + if (out_presentation_identity != NULL) + *out_presentation_identity = g_strdup(ret); + + out: + g_clear_object (&parser); + g_clear_error (&identity_error); + g_clear_object (&call); + g_clear_object (&proxy); + g_free (id); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +build_object (GoaProvider *provider, + GoaObjectSkeleton *object, + GKeyFile *key_file, + const gchar *group, + GDBusConnection *connection, + gboolean just_added, + GError **error) +{ + GoaAccount *account = NULL; + GoaMail *mail = NULL; + gchar *uri_caldav; + gchar *uri_drive; + gchar *uri_carddav; + gboolean ret = FALSE; + gboolean mail_enabled; + gboolean files_enabled; + gboolean calendar_enabled; + gboolean contacts_enabled; + const gchar *email_address; + gchar *u_name, *u_name_pos; + + /* Chain up */ + if (!GOA_PROVIDER_CLASS (goa_yandex_provider_parent_class)->build_object (provider, + object, + key_file, + group, + connection, + just_added, + error)) + goto out; + + account = goa_object_get_account (GOA_OBJECT (object)); + email_address = goa_account_get_identity (account); + + /* Email */ + mail = goa_object_get_mail (GOA_OBJECT (object)); + mail_enabled = g_key_file_get_boolean (key_file, group, "MailEnabled", NULL); + if (mail_enabled) + { + if (mail == NULL) + { + mail = goa_mail_skeleton_new (); + g_object_set (G_OBJECT (mail), + "email-address", email_address, + "imap-supported", TRUE, + "imap-host", "imap.yandex.ru", + "imap-user-name", email_address, + "imap-use-ssl", TRUE, + "smtp-supported", TRUE, + "smtp-host", "smtp.yandex.ru", + "smtp-user-name", email_address, + "smtp-use-auth", TRUE, + "smtp-auth-xoauth2", TRUE, + "smtp-use-ssl", TRUE, + "smtp-use-tls", TRUE, + NULL); + goa_object_skeleton_set_mail (object, mail); + } + } + else + { + if (mail != NULL) + goa_object_skeleton_set_mail (object, NULL); + } + + /* Calendar */ + calendar_enabled = g_key_file_get_boolean (key_file, group, "CalendarEnabled", NULL); + uri_caldav = g_strconcat ("https://caldav.yandex.ru/", NULL); + goa_object_skeleton_attach_calendar (object, uri_caldav, calendar_enabled, FALSE); + g_free (uri_caldav); + + /* Contacts */ + // contacts_enabled = g_key_file_get_boolean (key_file, group, "ContactsEnabled", NULL); + // uri_carddav = g_strconcat ("https://carddav.yandex.ru/", NULL); + // goa_object_skeleton_attach_contacts (object, uri_carddav, contacts_enabled, FALSE); + // g_free (uri_carddav); + + /* Files */ + files_enabled = g_key_file_get_boolean (key_file, group, "FilesEnabled", NULL); + u_name = g_strdup(email_address); + u_name_pos = g_utf8_strchr(u_name, -1, '@'); + if (u_name_pos){ + *u_name_pos = '\0'; + } + uri_drive = g_strconcat ("davs://", u_name, "@webdav.yandex.ru/", NULL); + goa_object_skeleton_attach_files (object, uri_drive, files_enabled, FALSE); + g_free (u_name); + g_free (uri_drive); + + + if (just_added) + { + goa_account_set_mail_disabled (account, !mail_enabled); + goa_account_set_calendar_disabled (account, !calendar_enabled); + goa_account_set_contacts_disabled (account, !contacts_enabled); + goa_account_set_files_disabled (account, !files_enabled); + + g_signal_connect (account, + "notify::mail-disabled", + G_CALLBACK (goa_util_account_notify_property_cb), + (gpointer) "MailEnabled"); + g_signal_connect (account, + "notify::calendar-disabled", + G_CALLBACK (goa_util_account_notify_property_cb), + (gpointer) "CalendarEnabled"); + // g_signal_connect (account, + // "notify::contacts-disabled", + // G_CALLBACK (goa_util_account_notify_property_cb), + // (gpointer) "ContactsEnabled"); + g_signal_connect (account, + "notify::files-disabled", + G_CALLBACK (goa_util_account_notify_property_cb), + (gpointer) "FilesEnabled"); + } + + ret = TRUE; + + out: + g_clear_object (&mail); + g_clear_object (&account); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +add_account_key_values (GoaOAuth2Provider *oauth2_provider, + GVariantBuilder *builder) +{ + g_variant_builder_add (builder, "{ss}", "MailEnabled", "true"); + g_variant_builder_add (builder, "{ss}", "CalendarEnabled", "true"); + // g_variant_builder_add (builder, "{ss}", "ContactsEnabled", "true"); + g_variant_builder_add (builder, "{ss}", "FilesEnabled", "true"); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +goa_yandex_finalize (GObject *object) +{ + GoaYandexProvider *self = GOA_YANDEX_PROVIDER (object); + + g_free (self->redirect_uri); + + G_OBJECT_CLASS (goa_yandex_provider_parent_class)->finalize (object); +} + +static void +goa_yandex_provider_init (GoaYandexProvider *self) +{ +} + +static void +goa_yandex_provider_class_init (GoaYandexProviderClass *klass) +{ + GoaProviderClass *provider_class; + GoaOAuth2ProviderClass *oauth2_class; + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = goa_yandex_finalize; + + provider_class = GOA_PROVIDER_CLASS (klass); + provider_class->get_provider_type = get_provider_type; + provider_class->get_provider_name = get_provider_name; + provider_class->get_provider_group = get_provider_group; + provider_class->get_provider_features = get_provider_features; + provider_class->build_object = build_object; + provider_class->get_credentials_generation = get_credentials_generation; + + oauth2_class = GOA_OAUTH2_PROVIDER_CLASS (klass); + oauth2_class->get_authorization_uri = get_authorization_uri; + oauth2_class->get_client_id = get_client_id; + oauth2_class->get_client_secret = get_client_secret; + oauth2_class->get_identity_sync = get_identity_sync; + oauth2_class->get_redirect_uri = get_redirect_uri; + oauth2_class->get_scope = get_scope; + oauth2_class->get_token_uri = get_token_uri; + oauth2_class->get_use_pkce = get_use_pkce; + oauth2_class->add_account_key_values = add_account_key_values; +} diff --git a/src/goabackend/goayandexprovider.h b/src/goabackend/goayandexprovider.h new file mode 100644 index 0000000..bd4315f --- /dev/null +++ b/src/goabackend/goayandexprovider.h @@ -0,0 +1,37 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright © 2011 – 2017 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __GOA_YANDEX_PROVIDER_H__ +#define __GOA_YANDEX_PROVIDER_H__ + +#include + +#include "goaoauth2provider-priv.h" + +G_BEGIN_DECLS + +#define GOA_TYPE_YANDEX_PROVIDER (goa_yandex_provider_get_type ()) +G_DECLARE_FINAL_TYPE (GoaYandexProvider, goa_yandex_provider, GOA, YANDEX_PROVIDER, GoaOAuth2Provider); + +G_END_DECLS + +#endif /* __GOA_YANDEX_PROVIDER_H__ */ diff --git a/src/goabackend/meson.build b/src/goabackend/meson.build index 150a9fb..23dda34 100644 --- a/src/goabackend/meson.build +++ b/src/goabackend/meson.build @@ -26,6 +26,7 @@ libgoa_backend_sources = files( 'goautils.c', 'goawebdavprovider.c', 'goawindowsliveprovider.c', + 'goayandexprovider.c', ) enum_headers = files('goabackendenums.h') -- 2.39.5