File evolution-data-server-google-oauth2.patch of Package evolution-data-server.29421
From e2b9dd3478e873050de4a886ba1d3eb828615aa9 Mon Sep 17 00:00:00 2001
From: Milan Crha <mcrha@redhat.com>
Date: Wed, 4 May 2022 15:30:49 +0200
Subject: [PATCH] I#388 - Google OAuth out-of-band (oob) flow will be
deprecated
Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/388
---
src/libedataserver/e-oauth2-service-google.c | 62 +++++++++++++++++---
1 file changed, 55 insertions(+), 7 deletions(-)
diff -urp evolution-data-server-3.26.6.orig/src/libedataserver/e-source-credentials-provider-impl-google.c evolution-data-server-3.26.6/src/libedataserver/e-source-credentials-provider-impl-google.c
--- evolution-data-server-3.26.6.orig/src/libedataserver/e-source-credentials-provider-impl-google.c 2018-03-05 04:10:55.000000000 -0600
+++ evolution-data-server-3.26.6/src/libedataserver/e-source-credentials-provider-impl-google.c 2023-06-07 15:30:11.128600286 -0500
@@ -311,7 +311,7 @@ e_source_credentials_google_is_supported
/* The "refresh token" code is mostly copied from e-credentials-prompter-impl-google.c,
which cannot be linked here, because the build dependency is opposite. */
-#define GOOGLE_TOKEN_URI "https://www.googleapis.com/oauth2/v3/token"
+#define GOOGLE_TOKEN_URI "https://oauth2.googleapis.com/token"
static gchar *
cpi_google_create_refresh_token_post_data (const gchar *refresh_token)
diff -urp evolution-data-server-3.26.6.orig/src/libedataserverui/e-credentials-prompter-impl-google.c evolution-data-server-3.26.6/src/libedataserverui/e-credentials-prompter-impl-google.c
--- evolution-data-server-3.26.6.orig/src/libedataserverui/e-credentials-prompter-impl-google.c 2018-03-05 04:10:55.000000000 -0600
+++ evolution-data-server-3.26.6/src/libedataserverui/e-credentials-prompter-impl-google.c 2023-06-08 11:20:05.105541388 -0500
@@ -30,10 +30,9 @@
#ifdef ENABLE_GOOGLE_AUTH
#include <webkit2/webkit2.h>
-/* https://developers.google.com/identity/protocols/OAuth2InstalledApp */
-#define GOOGLE_AUTH_URI "https://accounts.google.com/o/oauth2/auth"
-#define GOOGLE_TOKEN_URI "https://www.googleapis.com/oauth2/v3/token"
-#define GOOGLE_REDIRECT_URI "urn:ietf:wg:oauth:2.0:oob"
+/* https://developers.google.com/identity/protocols/oauth2/native-app */
+#define GOOGLE_AUTH_URI "https://accounts.google.com/o/oauth2/v2/auth"
+#define GOOGLE_TOKEN_URI "https://oauth2.googleapis.com/token"
static const gchar *GOOGLE_SCOPE =
/* GMail IMAP and SMTP access */
@@ -70,6 +69,43 @@ struct _ECredentialsPrompterImplGooglePr
G_DEFINE_TYPE (ECredentialsPrompterImplGoogle, e_credentials_prompter_impl_google, E_TYPE_CREDENTIALS_PROMPTER_IMPL)
#ifdef ENABLE_GOOGLE_AUTH
+static const gchar *
+eos_google_get_redirect_uri ()
+{
+ static gchar *value = NULL;
+
+ if (value)
+ return value;
+
+ const gchar *client_id = GOOGLE_CLIENT_ID;
+
+ if (client_id) {
+ GPtrArray *array;
+ gchar **strv;
+ gchar *joinstr;
+ guint ii;
+
+ strv = g_strsplit (client_id, ".", -1);
+ array = g_ptr_array_new ();
+
+ for (ii = 0; strv[ii]; ii++) {
+ g_ptr_array_insert (array, 0, strv[ii]);
+ }
+
+ g_ptr_array_add (array, NULL);
+
+ joinstr = g_strjoinv (".", (gchar **) array->pdata);
+ /* Use reverse-DNS of the client ID with the below path */
+ value = g_strconcat (joinstr, ":/oauth2redirect", NULL);
+
+ g_ptr_array_free (array, TRUE);
+ g_strfreev (strv);
+ g_free (joinstr);
+ }
+
+ return value;
+}
+
static gchar *
cpi_google_create_auth_uri (ESource *source)
{
@@ -86,7 +122,7 @@ cpi_google_create_auth_uri (ESource *sou
add_to_form ("response_type", "code");
add_to_form ("client_id", GOOGLE_CLIENT_ID);
- add_to_form ("redirect_uri", GOOGLE_REDIRECT_URI);
+ add_to_form ("redirect_uri", eos_google_get_redirect_uri ());
add_to_form ("scope", GOOGLE_SCOPE);
if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
@@ -123,7 +159,7 @@ cpi_google_create_token_post_data (const
"code", authorization_code,
"client_id", GOOGLE_CLIENT_ID,
"client_secret", GOOGLE_CLIENT_SECRET,
- "redirect_uri", GOOGLE_REDIRECT_URI,
+ "redirect_uri", eos_google_get_redirect_uri (),
"grant_type", "authorization_code",
NULL);
}
@@ -460,12 +496,70 @@ cpi_google_get_access_token_thread (gpoi
return NULL;
}
+static gboolean
+eos_google_extract_authorization_code (const gchar *page_title,
+ const gchar *page_uri,
+ gchar **out_authorization_code)
+{
+ g_return_val_if_fail (out_authorization_code != NULL, FALSE);
+
+ *out_authorization_code = NULL;
+
+ if (page_title && *page_title) {
+ /* Known response, but no authorization code */
+ if (g_ascii_strncasecmp (page_title, "Denied ", 7) == 0)
+ return TRUE;
+
+ if (g_ascii_strncasecmp (page_title, "Success code=", 13) == 0) {
+ *out_authorization_code = g_strdup (page_title + 13);
+ return TRUE;
+ }
+ }
+
+ if (page_uri && *page_uri) {
+ SoupURI *suri;
+
+ suri = soup_uri_new (page_uri);
+ if (suri) {
+ const gchar *query = soup_uri_get_query (suri);
+ gboolean known = FALSE;
+
+ if (query && *query) {
+ GHashTable *params;
+
+ params = soup_form_decode (query);
+ if (params) {
+ const gchar *code;
+
+ code = g_hash_table_lookup (params, "code");
+ if (code && *code) {
+ *out_authorization_code = g_strdup (code);
+ known = TRUE;
+ } else if (g_hash_table_lookup (params, "error")) {
+ known = TRUE;
+ }
+
+ g_hash_table_destroy (params);
+ }
+ }
+
+ soup_uri_free (suri);
+
+ if (known)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
static void
cpi_google_document_load_changed_cb (WebKitWebView *web_view,
WebKitLoadEvent load_event,
ECredentialsPrompterImplGoogle *prompter_google)
{
- const gchar *title;
+ const gchar *title, *uri;
+ gchar *authorization_code = NULL;
g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL_GOOGLE (prompter_google));
@@ -474,16 +568,18 @@ cpi_google_document_load_changed_cb (Web
return;
title = webkit_web_view_get_title (web_view);
- if (!title)
+ uri = webkit_web_view_get_uri (web_view);
+ if (!title || !uri)
+ return;
+
+ if (!eos_google_extract_authorization_code (title, uri, &authorization_code))
return;
- if (g_ascii_strncasecmp (title, "Denied ", 7) == 0) {
+ if (!authorization_code) {
g_cancellable_cancel (prompter_google->priv->cancellable);
gtk_dialog_response (prompter_google->priv->dialog, GTK_RESPONSE_CANCEL);
return;
- }
-
- if (g_ascii_strncasecmp (title, "Success code=", 13) == 0) {
+ } else {
ECredentialsPrompter *prompter;
ECredentialsPrompterImpl *prompter_impl;
AccessTokenThreadData *td;
@@ -504,7 +600,7 @@ cpi_google_document_load_changed_cb (Web
td->cancellable = g_object_ref (prompter_google->priv->cancellable);
td->cred_source = g_object_ref (prompter_google->priv->cred_source);
td->registry = g_object_ref (e_credentials_prompter_get_registry (prompter));
- td->authorization_code = g_strdup (title + 13);
+ td->authorization_code = authorization_code;
thread = g_thread_new (G_STRFUNC, cpi_google_get_access_token_thread, td);
g_thread_unref (thread);