From 51f08c19a1ae1f7cde06307eb93b6a2be9df0ecc Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Sep 2023 21:36:39 +0200 Subject: [PATCH] Chore: update to OAuth 2.0, fix #1548 --- land.html | 5 +- package-lock.json | 71 ++++------------------------ package.json | 4 +- src/Logic/Osm/OsmConnection.ts | 85 +++++++++++++++++++--------------- src/land.ts | 12 +++++ 5 files changed, 73 insertions(+), 104 deletions(-) create mode 100644 src/land.ts diff --git a/land.html b/land.html index cd155ea56..a9fd46b34 100644 --- a/land.html +++ b/land.html @@ -2,9 +2,6 @@ MapComplete Auth - + diff --git a/package-lock.json b/package-lock.json index 8b49afc9a..9d1829c33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mapcomplete", - "version": "0.31.2", + "version": "0.31.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mapcomplete", - "version": "0.31.2", + "version": "0.31.4", "license": "GPL-3.0-or-later", "dependencies": { "@rgossiaux/svelte-headlessui": "^1.0.2", @@ -40,7 +40,7 @@ "mangrove-reviews-typescript": "^1.1.0", "maplibre-gl": "^3.2.0", "opening_hours": "^3.6.0", - "osm-auth": "^1.0.2", + "osm-auth": "^2.2.0", "osmtogeojson": "^3.0.0-beta.5", "papaparse": "^5.3.1", "pic4carto": "^2.1.15", @@ -7300,17 +7300,6 @@ "node": ">=4" } }, - "node_modules/jshashes": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/jshashes/-/jshashes-1.0.8.tgz", - "integrity": "sha512-btmQZ/w1rj8Lb6nEwvhjM7nBYoj54yaEFo2PWh3RkxZ8qNwuvOxvQYN/JxVuwoMmdIluL+XwYVJ+pEEZoSYybQ==", - "bin": { - "hashes": "bin/hashes" - }, - "engines": { - "node": "*" - } - }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -8189,18 +8178,6 @@ "node": ">= 0.4" } }, - "node_modules/ohauth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ohauth/-/ohauth-1.0.1.tgz", - "integrity": "sha512-R9ZUN3+FVCwzeOOHCJpzA9jw/byRxp5O9X06mTL6Sp/LIQn/rLrMv6cwYctX+hoIKzRUsalGJXZ1kG5wBmSskQ==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dependencies": { - "jshashes": "~1.0.8" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8372,16 +8349,14 @@ } }, "node_modules/osm-auth": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/osm-auth/-/osm-auth-1.1.2.tgz", - "integrity": "sha512-oLaU+c/TP7eKAZpBN4S1mv/N94IXp5A+wLpDfAVlpq/b6iikas8ZthXPqhM8QKg/qB8RaKvZPJgxqYS+5m8G8g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/osm-auth/-/osm-auth-2.2.0.tgz", + "integrity": "sha512-x93jAMaYWqPgfVeOMydFLFpFC8ERnlIKXwiUOrYYWTDEWqq15K/BI5UAjzuYXvLg0WxVxM8YC4N1T30SZeKJBQ==", "dependencies": { - "ohauth": "~1.0.1", - "resolve-url": "~0.2.1", "store": "~2.0.12" }, "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/osm-polygon-features": { @@ -9191,12 +9166,6 @@ "protocol-buffers-schema": "^3.3.1" } }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "deprecated": "https://github.com/lydell/resolve-url#deprecated" - }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -17830,11 +17799,6 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "jshashes": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/jshashes/-/jshashes-1.0.8.tgz", - "integrity": "sha512-btmQZ/w1rj8Lb6nEwvhjM7nBYoj54yaEFo2PWh3RkxZ8qNwuvOxvQYN/JxVuwoMmdIluL+XwYVJ+pEEZoSYybQ==" - }, "json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -18513,14 +18477,6 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, - "ohauth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ohauth/-/ohauth-1.0.1.tgz", - "integrity": "sha512-R9ZUN3+FVCwzeOOHCJpzA9jw/byRxp5O9X06mTL6Sp/LIQn/rLrMv6cwYctX+hoIKzRUsalGJXZ1kG5wBmSskQ==", - "requires": { - "jshashes": "~1.0.8" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -18651,12 +18607,10 @@ "dev": true }, "osm-auth": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/osm-auth/-/osm-auth-1.1.2.tgz", - "integrity": "sha512-oLaU+c/TP7eKAZpBN4S1mv/N94IXp5A+wLpDfAVlpq/b6iikas8ZthXPqhM8QKg/qB8RaKvZPJgxqYS+5m8G8g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/osm-auth/-/osm-auth-2.2.0.tgz", + "integrity": "sha512-x93jAMaYWqPgfVeOMydFLFpFC8ERnlIKXwiUOrYYWTDEWqq15K/BI5UAjzuYXvLg0WxVxM8YC4N1T30SZeKJBQ==", "requires": { - "ohauth": "~1.0.1", - "resolve-url": "~0.2.1", "store": "~2.0.12" } }, @@ -19236,11 +19190,6 @@ "protocol-buffers-schema": "^3.3.1" } }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" - }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", diff --git a/package.json b/package.json index 20ce152ef..bdbeb8cb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mapcomplete", - "version": "0.31.4", + "version": "0.32.0", "repository": "https://github.com/pietervdvn/MapComplete", "description": "A small website to edit OSM easily", "bugs": "https://github.com/pietervdvn/MapComplete/issues", @@ -93,7 +93,7 @@ "mangrove-reviews-typescript": "^1.1.0", "maplibre-gl": "^3.2.0", "opening_hours": "^3.6.0", - "osm-auth": "^1.0.2", + "osm-auth": "^2.2.0", "osmtogeojson": "^3.0.0-beta.5", "papaparse": "^5.3.1", "pic4carto": "^2.1.15", diff --git a/src/Logic/Osm/OsmConnection.ts b/src/Logic/Osm/OsmConnection.ts index a14d30849..42c6a9304 100644 --- a/src/Logic/Osm/OsmConnection.ts +++ b/src/Logic/Osm/OsmConnection.ts @@ -1,7 +1,9 @@ -import osmAuth from "osm-auth" -import { Store, Stores, UIEventSource } from "../UIEventSource" -import { OsmPreferences } from "./OsmPreferences" -import { Utils } from "../../Utils" +// @ts-ignore +import {osmAuth} from "osm-auth" +import {Store, Stores, UIEventSource} from "../UIEventSource" +import {OsmPreferences} from "./OsmPreferences" +import {Utils} from "../../Utils" +import {LocalStorageSource} from "../Web/LocalStorageSource"; export default class UserDetails { public loggedIn = false @@ -22,22 +24,26 @@ export default class UserDetails { } } +export interface AuthConfig { + oauth_client_id: string + oauth_secret: string + url: string +} + export type OsmServiceState = "online" | "readonly" | "offline" | "unknown" | "unreachable" export class OsmConnection { - public static readonly oauth_configs = { + public static readonly oauth_configs: Record = { osm: { - oauth_consumer_key: "hivV7ec2o49Two8g9h8Is1VIiVOgxQ1iYexCbvem", - oauth_secret: "wDBRTCem0vxD7txrg1y6p5r8nvmz8tAhET7zDASI", + oauth_client_id: 'sa1ngLJBJ8McmzHElN8NYtIDm5TZTYEYhq3-0snO4Qc', + oauth_secret: 'XU_cD5Mvw9VKk9T0t_gO8V7cbRC4Hmw2Tb4Rv0Zmz-U', url: "https://www.openstreetmap.org", - // OAUTH 1.0 application - // https://www.openstreetmap.org/user/Pieter%20Vander%20Vennet/oauth_clients/7404 }, "osm-test": { - oauth_consumer_key: "Zgr7EoKb93uwPv2EOFkIlf3n9NLwj5wbyfjZMhz2", - oauth_secret: "3am1i1sykHDMZ66SGq4wI2Z7cJMKgzneCHp3nctn", - url: "https://master.apis.dev.openstreetmap.org", - }, + oauth_client_id: "HwUn6GPxGm1m9WwMarxTglhy6dBTM4YkaV1I9h6pDGU" + oauth_secret: "luFZtPJg7j96K6WM6RpcZ_3M-r6muuDq6fG1ygk0I_4", + url: "https://master.apis.dev.openstreetmap.org", + } } public auth public userDetails: UIEventSource @@ -53,11 +59,7 @@ export class OsmConnection { "not-attempted" ) public preferencesHandler: OsmPreferences - public readonly _oauth_config: { - oauth_consumer_key: string - oauth_secret: string - url: string - } + public readonly _oauth_config: AuthConfig private readonly _dryRun: Store private fakeUser: boolean private _onLoggedIn: ((userDetails: UserDetails) => void)[] = [] @@ -190,6 +192,7 @@ export class OsmConnection { const self = this console.log("Trying to log in...") this.updateAuthObject() + LocalStorageSource.Get("location_before_login").setData(window.location.href) this.auth.xhr( { method: "GET", @@ -202,13 +205,8 @@ export class OsmConnection { if (err.status == 401) { console.log("Clearing tokens...") // Not authorized - our token probably got revoked - // Reset all the tokens - const tokens = [ - "https://www.openstreetmap.orgoauth_request_token_secret", - "https://www.openstreetmap.orgoauth_token", - "https://www.openstreetmap.orgoauth_token_secret", - ] - tokens.forEach((token) => localStorage.removeItem(token)) + self.auth.logout(); + self.LogOut() } return } @@ -252,7 +250,7 @@ export class OsmConnection { if (homeEl !== undefined && homeEl[0] !== undefined) { const lat = parseFloat(homeEl[0].getAttribute("lat")) const lon = parseFloat(homeEl[0].getAttribute("lon")) - data.home = { lat: lat, lon: lon } + data.home = {lat: lat, lon: lon} } self.loadingStatus.setData("logged-in") @@ -310,6 +308,7 @@ export class OsmConnection { ): Promise { return await this.interact(path, "POST", header, content) } + public async put( path: string, content?: string, @@ -355,13 +354,13 @@ export class OsmConnection { console.warn("Dryrun enabled - not actually opening note with text ", text) return new Promise<{ id: number }>((ok) => { window.setTimeout( - () => ok({ id: Math.floor(Math.random() * 1000) }), + () => ok({id: Math.floor(Math.random() * 1000)}), Math.random() * 5000 ) }) } const auth = this.auth - const content = { lat, lon, text } + const content = {lat, lon, text} const response = await this.post("notes.json", JSON.stringify(content), { "Content-Type": "application/json", }) @@ -389,7 +388,7 @@ export class OsmConnection { console.warn("Dryrun enabled - not actually uploading GPX ", gpx) return new Promise<{ id: number }>((ok, error) => { window.setTimeout( - () => ok({ id: Math.floor(Math.random() * 1000) }), + () => ok({id: Math.floor(Math.random() * 1000)}), Math.random() * 5000 ) }) @@ -430,7 +429,7 @@ export class OsmConnection { }) const parsed = JSON.parse(response) console.log("Uploaded GPX track", parsed) - return { id: parsed } + return {id: parsed} } public addCommentToNote(id: number | string, text: string): Promise { @@ -486,15 +485,27 @@ export class OsmConnection { // Same for an iframe... this.auth = new osmAuth({ - oauth_consumer_key: this._oauth_config.oauth_consumer_key, - oauth_secret: this._oauth_config.oauth_secret, + client_id: this._oauth_config.oauth_client_id, url: this._oauth_config.url, - landing: standalone ? undefined : window.location.href, + scope: "read_prefs write_prefs write_api write_gpx write_notes", + redirect_uri: window.location.protocol + "//" + window.location.host + "/land.html", singlepage: !standalone, auto: true, }) } + /** + * To be called by land.html + */ + public finishLogin(callback: ((previousURL: string) => void)) { + this.auth.authenticate(function() { + // Fully authed at this point + console.log("Authentication successful!") + const previousLocation = LocalStorageSource.Get("location_before_login") + callback(previousLocation.data) + }); + } + private CheckForMessagesContinuously() { const self = this if (this.isChecking) { @@ -511,7 +522,7 @@ export class OsmConnection { private UpdateCapabilities(): void { const self = this - this.FetchCapabilities().then(({ api, gpx }) => { + this.FetchCapabilities().then(({api, gpx}) => { self.apiIsOnline.setData(api) self.gpxServiceIsOnline.setData(gpx) }) @@ -519,18 +530,18 @@ export class OsmConnection { private async FetchCapabilities(): Promise<{ api: OsmServiceState; gpx: OsmServiceState }> { if (Utils.runningFromConsole) { - return { api: "online", gpx: "online" } + return {api: "online", gpx: "online"} } const result = await Utils.downloadAdvanced(this.Backend() + "/api/0.6/capabilities") if (result["content"] === undefined) { console.log("Something went wrong:", result) - return { api: "unreachable", gpx: "unreachable" } + return {api: "unreachable", gpx: "unreachable"} } const xmlRaw = result["content"] const parsed = new DOMParser().parseFromString(xmlRaw, "text/xml") const statusEl = parsed.getElementsByTagName("status")[0] const api = statusEl.getAttribute("api") const gpx = statusEl.getAttribute("gpx") - return { api, gpx } + return {api, gpx} } } diff --git a/src/land.ts b/src/land.ts new file mode 100644 index 000000000..18ceedea4 --- /dev/null +++ b/src/land.ts @@ -0,0 +1,12 @@ +import {OsmConnection} from "./Logic/Osm/OsmConnection"; + +console.log("Authorizing..."); +new OsmConnection().finishLogin(previousURL => { + const fallback = window.location.protocol+"//"+window.location.host+"/index.html" + previousURL ??= fallback + if(previousURL.indexOf("/land") > 0){ + previousURL = fallback + } + console.log("Redirecting to", previousURL) + window.location.href = previousURL +})