1 /*
2  * Copyright (C) 2021 Red Hat (www.redhat.com)
3  *
4  * This library is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include "evolution-data-server-config.h"
18 
19 #include <glib/gi18n-lib.h>
20 
21 #include "e-oauth2-service.h"
22 #include "e-oauth2-service-base.h"
23 
24 #include "e-oauth2-service-yahoo.h"
25 
26 /* https://developer.yahoo.com/oauth2/guide/openid_connect/getting_started.html */
27 
28 /* Forward Declarations */
29 static void e_oauth2_service_yahoo_oauth2_service_init (EOAuth2ServiceInterface *iface);
30 
G_DEFINE_TYPE_WITH_CODE(EOAuth2ServiceYahoo,e_oauth2_service_yahoo,E_TYPE_OAUTH2_SERVICE_BASE,G_IMPLEMENT_INTERFACE (E_TYPE_OAUTH2_SERVICE,e_oauth2_service_yahoo_oauth2_service_init))31 G_DEFINE_TYPE_WITH_CODE (EOAuth2ServiceYahoo, e_oauth2_service_yahoo, E_TYPE_OAUTH2_SERVICE_BASE,
32 	G_IMPLEMENT_INTERFACE (E_TYPE_OAUTH2_SERVICE, e_oauth2_service_yahoo_oauth2_service_init))
33 
34 static gboolean
35 eos_yahoo_guess_can_process (EOAuth2Service *service,
36 			      const gchar *protocol,
37 			      const gchar *hostname)
38 {
39 	return hostname &&
40 		e_util_utf8_strstrcase (hostname, ".yahoo.com");
41 }
42 
43 static const gchar *
eos_yahoo_get_name(EOAuth2Service * service)44 eos_yahoo_get_name (EOAuth2Service *service)
45 {
46 	return "Yahoo";
47 }
48 
49 static const gchar *
eos_yahoo_get_display_name(EOAuth2Service * service)50 eos_yahoo_get_display_name (EOAuth2Service *service)
51 {
52 	/* Translators: This is a user-visible string, display name of an OAuth2 service. */
53 	return C_("OAuth2Service", "Yahoo!");
54 }
55 
56 static const gchar *
eos_yahoo_read_settings(EOAuth2Service * service,const gchar * key_name)57 eos_yahoo_read_settings (EOAuth2Service *service,
58 			 const gchar *key_name)
59 {
60 	G_LOCK_DEFINE_STATIC (user_settings);
61 	gchar *value;
62 
63 	G_LOCK (user_settings);
64 
65 	value = g_object_get_data (G_OBJECT (service), key_name);
66 	if (!value) {
67 		GSettings *settings;
68 
69 		settings = g_settings_new ("org.gnome.evolution-data-server");
70 		value = g_settings_get_string (settings, key_name);
71 		g_object_unref (settings);
72 
73 		if (value && *value) {
74 			g_object_set_data_full (G_OBJECT (service), key_name, value, g_free);
75 		} else {
76 			g_free (value);
77 			value = (gchar *) "";
78 
79 			g_object_set_data (G_OBJECT (service), key_name, value);
80 		}
81 	}
82 
83 	G_UNLOCK (user_settings);
84 
85 	return value;
86 }
87 
88 static const gchar *
eos_yahoo_get_client_id(EOAuth2Service * service,ESource * source)89 eos_yahoo_get_client_id (EOAuth2Service *service,
90 			 ESource *source)
91 {
92 	const gchar *client_id;
93 
94 	client_id = eos_yahoo_read_settings (service, "oauth2-yahoo-client-id");
95 
96 	if (client_id && *client_id)
97 		return client_id;
98 
99 	return YAHOO_CLIENT_ID;
100 }
101 
102 static const gchar *
eos_yahoo_get_client_secret(EOAuth2Service * service,ESource * source)103 eos_yahoo_get_client_secret (EOAuth2Service *service,
104 			     ESource *source)
105 {
106 	const gchar *client_secret;
107 
108 	client_secret = eos_yahoo_read_settings (service, "oauth2-yahoo-client-secret");
109 
110 	if (client_secret && *client_secret)
111 		return client_secret;
112 
113 	return YAHOO_CLIENT_SECRET;
114 }
115 
116 static const gchar *
eos_yahoo_get_authentication_uri(EOAuth2Service * service,ESource * source)117 eos_yahoo_get_authentication_uri (EOAuth2Service *service,
118 				  ESource *source)
119 {
120 	return "https://api.login.yahoo.com/oauth2/request_auth";
121 }
122 
123 static const gchar *
eos_yahoo_get_refresh_uri(EOAuth2Service * service,ESource * source)124 eos_yahoo_get_refresh_uri (EOAuth2Service *service,
125 			   ESource *source)
126 {
127 	return "https://api.login.yahoo.com/oauth2/get_token";
128 }
129 
130 static const gchar *
eos_yahoo_get_redirect_uri(EOAuth2Service * service,ESource * source)131 eos_yahoo_get_redirect_uri (EOAuth2Service *service,
132 			    ESource *source)
133 {
134 	return "https://wiki.gnome.org/Apps/Evolution/YahooOAuth2/";
135 }
136 
137 static void
eos_yahoo_prepare_authentication_uri_query(EOAuth2Service * service,ESource * source,GHashTable * uri_query)138 eos_yahoo_prepare_authentication_uri_query (EOAuth2Service *service,
139 					    ESource *source,
140 					    GHashTable *uri_query)
141 {
142 	const gchar *YAHOO_SCOPE =
143 		/* Mail */
144 		"mail-w "
145 		/* Calendar */
146 		"ycal-w "
147 		/* Contacts */
148 		"sdct-w";
149 	gchar *nonce_str;
150 	guint64 nonce_val;
151 
152 	g_return_if_fail (uri_query != NULL);
153 
154 	nonce_val = getpid () + g_get_real_time () + g_get_monotonic_time() + g_random_int () + g_random_int ();
155 	nonce_str = g_strdup_printf ("%" G_GUINT64_FORMAT "d", nonce_val);
156 
157 	e_oauth2_service_util_set_to_form (uri_query, "scope", YAHOO_SCOPE);
158 	e_oauth2_service_util_set_to_form (uri_query, "nonce", nonce_str);
159 
160 	g_free (nonce_str);
161 }
162 
163 static gboolean
eos_yahoo_extract_authorization_code(EOAuth2Service * service,ESource * source,const gchar * page_title,const gchar * page_uri,const gchar * page_content,gchar ** out_authorization_code)164 eos_yahoo_extract_authorization_code (EOAuth2Service *service,
165 				      ESource *source,
166 				      const gchar *page_title,
167 				      const gchar *page_uri,
168 				      const gchar *page_content,
169 				      gchar **out_authorization_code)
170 {
171 	g_return_val_if_fail (out_authorization_code != NULL, FALSE);
172 
173 	*out_authorization_code = NULL;
174 
175 	if (page_uri && *page_uri) {
176 		SoupURI *suri;
177 
178 		suri = soup_uri_new (page_uri);
179 		if (suri) {
180 			const gchar *query = soup_uri_get_query (suri);
181 			gboolean known = FALSE;
182 
183 			if (query && *query) {
184 				GHashTable *params;
185 
186 				params = soup_form_decode (query);
187 				if (params) {
188 					const gchar *response;
189 
190 					response = g_hash_table_lookup (params, "code");
191 					if (response) {
192 						*out_authorization_code = g_strdup (response);
193 						known = TRUE;
194 					}
195 
196 					g_hash_table_destroy (params);
197 				}
198 			}
199 
200 			soup_uri_free (suri);
201 
202 			if (known)
203 				return TRUE;
204 		}
205 	}
206 
207 	return FALSE;
208 }
209 
210 static void
e_oauth2_service_yahoo_oauth2_service_init(EOAuth2ServiceInterface * iface)211 e_oauth2_service_yahoo_oauth2_service_init (EOAuth2ServiceInterface *iface)
212 {
213 	iface->guess_can_process = eos_yahoo_guess_can_process;
214 	iface->get_name = eos_yahoo_get_name;
215 	iface->get_display_name = eos_yahoo_get_display_name;
216 	iface->get_client_id = eos_yahoo_get_client_id;
217 	iface->get_client_secret = eos_yahoo_get_client_secret;
218 	iface->get_authentication_uri = eos_yahoo_get_authentication_uri;
219 	iface->get_refresh_uri = eos_yahoo_get_refresh_uri;
220 	iface->get_redirect_uri = eos_yahoo_get_redirect_uri;
221 	iface->prepare_authentication_uri_query = eos_yahoo_prepare_authentication_uri_query;
222 	iface->extract_authorization_code = eos_yahoo_extract_authorization_code;
223 }
224 
225 static void
e_oauth2_service_yahoo_class_init(EOAuth2ServiceYahooClass * klass)226 e_oauth2_service_yahoo_class_init (EOAuth2ServiceYahooClass *klass)
227 {
228 }
229 
230 static void
e_oauth2_service_yahoo_init(EOAuth2ServiceYahoo * oauth2_yahoo)231 e_oauth2_service_yahoo_init (EOAuth2ServiceYahoo *oauth2_yahoo)
232 {
233 }
234