Codebase list gnome-maps / 83a2f47
Add proposed patch to fix build with librest 0.9 Jeremy Bicha 1 year, 8 months ago
2 changed file(s) with 439 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 From: Marcus Lundblad <ml@dfupdate.se>
1 Date: Sun, 21 Aug 2022 00:57:33 +0200
2 Subject: WIP: Migrate to OAuth2 for OSM editing
3
4 https://gitlab.gnome.org/GNOME/gnome-maps/-/merge_requests/239
5 ---
6 data/org.gnome.Maps.gschema.xml | 4 +-
7 data/ui/osm-account-dialog.ui | 17 +------
8 lib/maps-osm-oauth-proxy-call.c | 6 +--
9 lib/maps-osm-oauth-proxy-call.h | 10 ++--
10 org.gnome.Maps.json | 6 +--
11 src/osmAccountDialog.js | 21 ++------
12 src/osmConnection.js | 110 +++++++++++++++++-----------------------
13 src/osmEdit.js | 16 ++----
14 8 files changed, 70 insertions(+), 120 deletions(-)
15
16 diff --git a/data/org.gnome.Maps.gschema.xml b/data/org.gnome.Maps.gschema.xml
17 index 2ed4ad6..91b7f24 100644
18 --- a/data/org.gnome.Maps.gschema.xml
19 +++ b/data/org.gnome.Maps.gschema.xml
20 @@ -51,10 +51,10 @@
21 <summary>Number of recent routes to store</summary>
22 <description>Number of recently visited routes to store.</description>
23 </key>
24 - <key name="osm-username" type="s">
25 + <key name="osm-username-oauth2" type="s">
26 <default>""</default>
27 <summary>OpenStreetMap username or e-mail address</summary>
28 - <description>Indicates if the user has signed in to edit OpenStreetMap data.</description>
29 + <description>Indicates if the user has signed in to edit OpenStreetMap data using OAith2.</description>
30 </key>
31 <key name="transportation-type" enum="org.gnome.maps.TransportationType">
32 <default>'pedestrian'</default>
33 diff --git a/data/ui/osm-account-dialog.ui b/data/ui/osm-account-dialog.ui
34 index 31d636e..46ee878 100644
35 --- a/data/ui/osm-account-dialog.ui
36 +++ b/data/ui/osm-account-dialog.ui
37 @@ -62,19 +62,6 @@ Then fill in the obtained verification code here in the next step.</property>
38 </layout>
39 </object>
40 </child>
41 - <child>
42 - <object class="GtkSpinner" id="signInSpinner">
43 - <property name="height_request">16</property>
44 - <property name="width_request">16</property>
45 - <property name="spinning">True</property>
46 - <property name="halign">end</property>
47 - <property name="hexpand">1</property>
48 - <layout>
49 - <property name="column">0</property>
50 - <property name="row">3</property>
51 - </layout>
52 - </object>
53 - </child>
54 <child>
55 <object class="GtkLinkButton">
56 <property name="focusable">1</property>
57 @@ -83,7 +70,7 @@ Then fill in the obtained verification code here in the next step.</property>
58 <property name="halign">end</property>
59 <property name="hexpand">1</property>
60 <layout>
61 - <property name="column">1</property>
62 + <property name="column">0</property>
63 <property name="row">3</property>
64 </layout>
65 </object>
66 @@ -96,7 +83,7 @@ Then fill in the obtained verification code here in the next step.</property>
67 <class name="suggested-action"/>
68 </style>
69 <layout>
70 - <property name="column">2</property>
71 + <property name="column">1</property>
72 <property name="row">3</property>
73 </layout>
74 </object>
75 diff --git a/lib/maps-osm-oauth-proxy-call.c b/lib/maps-osm-oauth-proxy-call.c
76 index 5e9e754..47359c6 100644
77 --- a/lib/maps-osm-oauth-proxy-call.c
78 +++ b/lib/maps-osm-oauth-proxy-call.c
79 @@ -33,7 +33,7 @@ struct _MapsOSMOAuthProxyCallPrivate
80 };
81
82 G_DEFINE_TYPE_WITH_PRIVATE(MapsOSMOAuthProxyCall, maps_osm_oauth_proxy_call,
83 - OAUTH_TYPE_PROXY_CALL);
84 + REST_TYPE_OAUTH2_PROXY_CALL);
85
86 static gboolean
87 maps_osm_oauth_proxy_call_serialize_params (RestProxyCall *call,
88 @@ -85,9 +85,9 @@ maps_osm_oauth_proxy_call_init (MapsOSMOAuthProxyCall *call)
89 }
90
91 MapsOSMOAuthProxyCall *
92 -maps_osm_oauth_proxy_call_new (OAuthProxy *proxy, const char *payload)
93 +maps_osm_oauth_proxy_call_new (RestOAuth2Proxy *proxy, const char *payload)
94 {
95 - g_return_val_if_fail (OAUTH_IS_PROXY (proxy), NULL);
96 + g_return_val_if_fail (REST_IS_OAUTH2_PROXY (proxy), NULL);
97 g_return_val_if_fail (payload != NULL, NULL);
98
99 MapsOSMOAuthProxyCall *call =
100 diff --git a/lib/maps-osm-oauth-proxy-call.h b/lib/maps-osm-oauth-proxy-call.h
101 index e9c240d..03c6a36 100644
102 --- a/lib/maps-osm-oauth-proxy-call.h
103 +++ b/lib/maps-osm-oauth-proxy-call.h
104 @@ -22,8 +22,8 @@
105
106 #include <glib-object.h>
107
108 -#include <rest/oauth-proxy-call.h>
109 -#include <rest/oauth-proxy.h>
110 +#include <rest/rest-oauth2-proxy-call.h>
111 +#include <rest/rest-oauth2-proxy.h>
112
113 G_BEGIN_DECLS
114
115 @@ -40,17 +40,17 @@ typedef struct _MapsOSMOAuthProxyCallClass MapsOSMOAuthProxyCallClass;
116
117 struct _MapsOSMOAuthProxyCall
118 {
119 - OAuthProxyCall parent;
120 + RestOAuth2ProxyCall parent;
121 MapsOSMOAuthProxyCallPrivate *priv;
122 };
123
124 struct _MapsOSMOAuthProxyCallClass
125 {
126 - OAuthProxyCallClass parent_class;
127 + RestOAuth2ProxyCallClass parent_class;
128 };
129
130 GType maps_osm_oauth_proxy_call_get_type(void);
131 -MapsOSMOAuthProxyCall *maps_osm_oauth_proxy_call_new (OAuthProxy *proxy,
132 +MapsOSMOAuthProxyCall *maps_osm_oauth_proxy_call_new (RestOAuth2Proxy *proxy,
133 const char *content);
134
135 G_END_DECLS
136 diff --git a/org.gnome.Maps.json b/org.gnome.Maps.json
137 index 35a27a5..9558cf4 100644
138 --- a/org.gnome.Maps.json
139 +++ b/org.gnome.Maps.json
140 @@ -90,9 +90,9 @@
141 ],
142 "sources" : [
143 {
144 - "type" : "archive",
145 - "url" : "https://gitlab.gnome.org/GNOME/librest/-/archive/1.0.0/librest-1.0.0.tar.gz",
146 - "sha256" : "eeba5ddbf91a29decec01c3ccce64b922bd9bf52d631e307e185227295aea51d"
147 + "type" : "git",
148 + "url" : "https://gitlab.gnome.org/GNOME/librest.git",
149 + "branch": "master"
150 }
151 ]
152 },
153 diff --git a/src/osmAccountDialog.js b/src/osmAccountDialog.js
154 index 378960b..035a77d 100644
155 --- a/src/osmAccountDialog.js
156 +++ b/src/osmAccountDialog.js
157 @@ -76,24 +76,10 @@ export class OSMAccountDialog extends Gtk.Dialog {
158 }
159
160 _performSignIn() {
161 - // turn on signing in spinner
162 - this._signInSpinner.visible = true;
163 - this._signInButton.sensitive = false;
164 + // switch to the verification view
165 + this._stack.visible_child_name = 'verify';
166
167 - Application.osmEdit.performOAuthSignIn(this._onOAuthTokenAuthorized.bind(this));
168 - }
169 -
170 - _onOAuthTokenAuthorized(success) {
171 - if (success) {
172 - // switch to the verification view
173 - this._stack.visible_child_name = 'verify';
174 - } else {
175 - this._errorLabel.visible = true;
176 - this._errorLabel.label = _("Failed to authorize access");
177 - this._signInButton.label = _("Try again");
178 - }
179 -
180 - this._signInSpinner.visible = false;
181 + Application.osmEdit.performOAuthSignIn();
182 }
183
184 _onVerifyButtonClicked() {
185 @@ -169,7 +155,6 @@ GObject.registerClass({
186 Template: 'resource:///org/gnome/Maps/ui/osm-account-dialog.ui',
187 InternalChildren: ['stack',
188 'signInButton',
189 - 'signInSpinner',
190 'verificationEntry',
191 'verifyButton',
192 'errorLabel',
193 diff --git a/src/osmConnection.js b/src/osmConnection.js
194 index 5a18f35..4ab1f92 100644
195 --- a/src/osmConnection.js
196 +++ b/src/osmConnection.js
197 @@ -38,10 +38,11 @@ const BASE_URL = 'https://api.openstreetmap.org/api';
198 const API_VERSION = '0.6';
199
200 /* OAuth constants */
201 -const CONSUMER_KEY = '2lbpDoED0ZspGssTBAJ8zOCtrtmUoX4KnmZUIWIK';
202 -const CONSUMER_SECRET = 'AO9BhDl9sJ33DjaZgQmYcNIuM3ZSml4xtugai6gE';
203 -const OAUTH_ENDPOINT_URL = 'https://www.openstreetmap.org/oauth';
204 -const LOGIN_URL = 'https://www.openstreetmap.org/login';
205 +const CLIENT_KEY = 'ATOMKAKOXQuAJXpFxkm__nDVRlJLYYmP-0P54UfDnZI';
206 +const CLIENT_SECRET = '9vda-8M_lt0cLJMLJlbTfJVRDGiS2-pPbeSNMRqBQ0k';
207 +const AUTH_URL = 'https://www.openstreetmap.org/oauth2/authorize';
208 +const ACCESS_TOKEN_URL = 'https://www.openstreetmap.org/oauth2/token';
209 +const REDIRECT_URL = 'urn:ietf:wg:oauth:2.0:oob';
210
211 const SECRET_SCHEMA = new Secret.Schema("org.gnome.Maps",
212 Secret.SchemaFlags.NONE,
213 @@ -55,9 +56,10 @@ export class OSMConnection {
214 this._session = new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version });
215
216 /* OAuth proxy used for making OSM uploads */
217 - this._callProxy = Rest.OAuthProxy.new(CONSUMER_KEY, CONSUMER_SECRET,
218 - BASE_URL + '/' + API_VERSION,
219 - false);
220 + this._callProxy = Rest.OAuth2Proxy.new(AUTH_URL, ACCESS_TOKEN_URL,
221 + REDIRECT_URL,
222 + CLIENT_KEY, CLIENT_SECRET,
223 + BASE_URL + '/' + API_VERSION);
224 GnomeMaps.osm_init();
225 }
226
227 @@ -93,7 +95,7 @@ export class OSMConnection {
228 OAuth access token enrolled, so, if the currently instantiated
229 proxy instance doesn't have a token set, we could safely count on
230 it being present in the keyring */
231 - if (this._callProxy.get_token() === null) {
232 + if (this._callProxy.get_access_token() === null) {
233 Secret.password_lookup(SECRET_SCHEMA, {}, null, (s, res) => {
234 this._onPasswordLookedUp(res,
235 comment,
236 @@ -108,25 +110,29 @@ export class OSMConnection {
237 let password = Secret.password_lookup_finish(result);
238
239 if (password) {
240 - let token = password.split(':')[0];
241 - let secret = password.split(':')[1];
242 -
243 - this._callProxy.token = token;
244 - this._callProxy.token_secret = secret;
245 + this._callProxy.access_token = password;
246 this._doOpenChangeset(comment, callback);
247 } else {
248 callback(false, null, null);
249 }
250 }
251
252 + _createCallWithPayload(payload, method, func) {
253 + let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, payload);
254 +
255 + call.set_method(method);
256 + call.set_function(func);
257 + call.add_header('Authorization',
258 + 'Bearer ' + this._callProxy.access_token);
259 +
260 + return call;
261 + }
262 +
263 _doOpenChangeset(comment, callback) {
264 let changeset =
265 GnomeMaps.OSMChangeset.new(comment, 'gnome-maps ' + pkg.version);
266 let xml = changeset.serialize();
267 -
268 - let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
269 - call.set_method('PUT');
270 - call.set_function('/changeset/create');
271 + let call = this._createCallWithPayload(xml, 'PUT', '/changeset/create');
272
273 call.invoke_async(null, (call, res, userdata) =>
274 { this._onChangesetOpened(call, callback); });
275 @@ -146,10 +152,10 @@ export class OSMConnection {
276 object.changeset = changeset;
277
278 let xml = object.serialize();
279 - let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
280 -
281 - call.set_method('PUT');
282 - call.set_function(this._getCreateOrUpdateFunction(object, type));
283 + let call =
284 + this._createCallWithPayload(xml, 'PUT',
285 + this._getCreateOrUpdateFunction(object,
286 + type));
287
288 call.invoke_async(null, (call, res, userdata) =>
289 { this._onObjectUploaded(call, callback); });
290 @@ -168,10 +174,9 @@ export class OSMConnection {
291 object.changeset = changeset;
292
293 let xml = object.serialize();
294 - let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
295 -
296 - call.set_method('DELETE');
297 - call.set_function(this._getDeleteFunction(object, type));
298 + let call =
299 + this._createCallWithPayload(xml, 'DELETE',
300 + this._getDeleteFunction(object, type));
301
302 call.invoke_async(null, (call, res, userdata) =>
303 { this._onObjectDeleted(call, callback); });
304 @@ -219,46 +224,28 @@ export class OSMConnection {
305 return type + '/' + id;
306 }
307
308 - requestOAuthToken(callback) {
309 - /* OAuth proxy used for enrolling access tokens */
310 - this._oauthProxy = Rest.OAuthProxy.new(CONSUMER_KEY, CONSUMER_SECRET,
311 - OAUTH_ENDPOINT_URL, false);
312 - this._oauthProxy.request_token_async('request_token', 'oob', (p, error, w, u) => {
313 - this._onRequestOAuthToken(error, callback);
314 - }, this._oauthProxy);
315 - }
316 -
317 - _onRequestOAuthToken(error, callback) {
318 - if (error) {
319 - Utils.debug(error);
320 - callback(false);
321 - return;
322 - }
323 -
324 - this._oauthToken = this._oauthProxy.get_token();
325 - this._oauthTokenSecret = this._oauthProxy.get_token_secret();
326 - callback(true);
327 - }
328 -
329 - authorizeOAuthToken(callback) {
330 - let auth = '/authorize?oauth_token=';
331 - let authorizeUrl = OAUTH_ENDPOINT_URL + auth + this._oauthToken;
332 + authorizeOAuthToken() {
333 + this._codeChallenge = Rest.PkceCodeChallenge.new_random();
334 + let [authorizeUrl, state] =
335 + this._callProxy.build_authorization_url(this._codeChallenge.get_challenge(),
336 + 'read_prefs write_api');
337
338 Utils.debug('Trying to open: ' + authorizeUrl);
339
340 try {
341 Gio.AppInfo.launch_default_for_uri(authorizeUrl, null);
342 - callback(true);
343 } catch (e) {
344 Utils.debug('error: ' + e.message);
345 - callback(false);
346 }
347 }
348
349 requestOAuthAccessToken(code, callback) {
350 - this._oauthProxy.access_token_async('access_token', code, (p, error, w, data) => {
351 - this._onAccessOAuthToken(error, callback);
352 - }, this._oauthProxy);
353 + this._callProxy.fetch_access_token_async(code,
354 + this._codeChallenge.get_verifier(),
355 + null,
356 + (source, res) => {
357 + this._onAccessOAuthToken(res, callback);
358 + });
359 }
360
361 fetchLoggedInUser(callback) {
362 @@ -292,21 +279,18 @@ export class OSMConnection {
363 }
364 }
365
366 - _onAccessOAuthToken(error, callback) {
367 - if (error) {
368 + _onAccessOAuthToken(res, callback) {
369 + let success = this._callProxy.fetch_access_token_finish(res);
370 + if (!success) {
371 callback(false);
372 return;
373 }
374
375 - let token = this._oauthProxy.token;
376 - let secret = this._oauthProxy.token_secret;
377 + let token = this._callProxy.access_token;
378
379 - this._callProxy.token = token;
380 - this._callProxy.token_secret = secret;
381 Secret.password_store(SECRET_SCHEMA, {}, Secret.COLLECTION_DEFAULT,
382 - "OSM OAuth access token and secret",
383 - this._oauthProxy.token + ":" +
384 - this._oauthProxy.token_secret, null,
385 + "OSM OAuth access token",
386 + token, null,
387 (source, result, userData) => {
388 this._onPasswordStored(result, callback);
389 });
390 diff --git a/src/osmEdit.js b/src/osmEdit.js
391 index 16f4174..e4fa02d 100644
392 --- a/src/osmEdit.js
393 +++ b/src/osmEdit.js
394 @@ -34,7 +34,7 @@ export class OSMEdit {
395 constructor() {
396 this._osmConnection = new OSMConnection();
397 this._osmObject = null; // currently edited object
398 - this._username = Application.settings.get('osm-username');
399 + this._username = Application.settings.get('osm-username-oauth2');
400 this._isSignedIn = this._username !== null && this._username.length > 0;
401 }
402
403 @@ -138,14 +138,8 @@ export class OSMEdit {
404 this._osmConnection.closeChangeset(changesetId, callback);
405 }
406
407 - performOAuthSignIn(callback) {
408 - this._osmConnection.requestOAuthToken((success) => {
409 - if (success) {
410 - this._osmConnection.authorizeOAuthToken(callback);
411 - } else {
412 - callback(false);
413 - }
414 - });
415 + performOAuthSignIn() {
416 + this._osmConnection.authorizeOAuthToken();
417 }
418
419 requestOAuthAccessToken(code, callback) {
420 @@ -164,7 +158,7 @@ export class OSMEdit {
421 * username to signify that we are signed in
422 */
423 this._username = username ?? '_unknown_';
424 - Application.settings.set('osm-username', this._username);
425 + Application.settings.set('osm-username-oauth2', this._username);
426 callback(true);
427 });
428 } else {
429 @@ -176,7 +170,7 @@ export class OSMEdit {
430 this._username = null;
431 this._isSignedIn = false;
432
433 - Application.settings.set('osm-username', '');
434 + Application.settings.set('osm-username-oauth2', '');
435 this._osmConnection.signOut();
436 }
437
0 WIP-Migrate-to-OAuth2-for-OSM-editing.patch