From 32c279802a428046c5709353bffd699b270c708d Mon Sep 17 00:00:00 2001 From: Wille Marcel Date: Wed, 29 May 2024 20:48:18 -0300 Subject: [PATCH 1/4] Remove force https code --- package.json | 4 ++-- public/index.html | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index ddb0053a..e7445000 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osmcha-frontend", - "version": "0.87.5", + "version": "0.88.0", "license": "ISC", "engines": { "node": ">=7.0" @@ -70,7 +70,7 @@ "scripts": { "precommit": "lint-staged", "flow": "flow", - "start": "HTTPS=true react-scripts start", + "start": "react-scripts start", "lint": "eslint src", "test": "npm run lint && react-scripts test --env=jsdom", "coverage": "react-scripts test --env=jsdom --coverage", diff --git a/public/index.html b/public/index.html index 588a426c..38d20e20 100644 --- a/public/index.html +++ b/public/index.html @@ -14,15 +14,6 @@ - - - \ No newline at end of file diff --git a/public/oauth-landing.html b/public/oauth-landing.html deleted file mode 100644 index f2f1cfed..00000000 --- a/public/oauth-landing.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/AppDesktop.js b/src/AppDesktop.js index 76c968d2..8f3fed3e 100644 --- a/src/AppDesktop.js +++ b/src/AppDesktop.js @@ -11,6 +11,7 @@ import { CMap } from './views/map'; import { NavbarChangeset } from './views/navbar_changeset'; import { NavbarSidebar } from './views/navbar_sidebar'; import { Home } from './views/home'; +import { Authorized } from './views/authorized'; import { Modal } from './views/modal'; import { User } from './views/user'; import { SavedFilters } from './views/saved_filters'; @@ -60,6 +61,7 @@ export const AppDesktop = () => { + )} /> diff --git a/src/AppMobile.js b/src/AppMobile.js index 985dbbaa..785358b3 100644 --- a/src/AppMobile.js +++ b/src/AppMobile.js @@ -9,7 +9,7 @@ import { ChangesetsList } from './views/changesets_list'; import { CMap } from './views/map'; import { NavbarChangeset } from './views/navbar_changeset'; import { NavbarSidebar } from './views/navbar_sidebar'; -// import { Home } from './views/home'; +import { Authorized } from './views/authorized'; import { Modal } from './views/modal'; import { User } from './views/user'; import { SavedFilters } from './views/saved_filters'; @@ -41,6 +41,7 @@ export const AppMobile = () => { + diff --git a/src/components/changeset/sign_in_button.js b/src/components/changeset/sign_in_button.js index f4f88035..a159e618 100644 --- a/src/components/changeset/sign_in_button.js +++ b/src/components/changeset/sign_in_button.js @@ -1,39 +1,19 @@ import React from 'react'; import { connect } from 'react-redux'; -import { createPopup } from '../../utils/create_popup'; -import { handlePopupCallback } from '../../utils/handle_popup_callback'; -import { osmAuthUrl } from '../../config/constants'; -import { isDev, isLocal } from '../../config'; import type { RootStateType } from '../../store'; -import { getFinalToken } from '../../store/auth_actions'; -import { getChangesetsPage } from '../../store/changesets_page_actions'; -import { getChangeset } from '../../store/changeset_actions'; +import { getAuthUrl } from '../../network/auth'; class SignInButton extends React.PureComponent { props: { text: string, oAuthToken: ?string, - pageIndex: number, - getFinalToken: string => mixed, - getChangeset: string => mixed, - getChangesetsPage: string => mixed + pageIndex: number }; handleLoginClick = () => { - var oAuthToken = this.props.oAuthToken; - if (!oAuthToken) return; - - let url; - if (isDev || isLocal) { - url = `/local-landing.html#${oAuthToken}`; - } else { - url = `${osmAuthUrl}?oauth_token=${oAuthToken}`; - } - - createPopup('oauth_popup', url); - handlePopupCallback().then(oAuthObj => { - this.props.getFinalToken(oAuthObj.oauth_verifier); + getAuthUrl().then(res => { + window.location.assign(res.auth_url); }); }; render() { @@ -54,16 +34,9 @@ class SignInButton extends React.PureComponent { } } -SignInButton = connect( - (state: RootStateType, props) => ({ - oAuthToken: state.auth.get('oAuthToken'), - pageIndex: state.changesetsPage.get('pageIndex') || 0 - }), - { - getFinalToken, - getChangeset, - getChangesetsPage - } -)(SignInButton); +SignInButton = connect((state: RootStateType, props) => ({ + oAuthToken: state.auth.get('oAuthToken'), + pageIndex: state.changesetsPage.get('pageIndex') || 0 +}))(SignInButton); export { SignInButton }; diff --git a/src/config/constants.js b/src/config/constants.js index b1b98199..40a88a66 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -18,7 +18,6 @@ export const osmchaUrl = API_URL.replace('api/v1', ''); export const osmUrl = process.env.REACT_APP_OSM_URL || 'https://www.openstreetmap.org'; -export const osmAuthUrl = `${osmUrl}/oauth/authorize`; export const isOfficialOSM = osmUrl === 'https://www.openstreetmap.org'; export const apiOSM = process.env.REACT_APP_OSM_API || 'https://api.openstreetmap.org/api/0.6'; diff --git a/src/network/auth.js b/src/network/auth.js index 8060f8dc..9493eb90 100644 --- a/src/network/auth.js +++ b/src/network/auth.js @@ -4,17 +4,11 @@ import { osmchaSocialTokenUrl } from '../config/constants'; import { API_URL } from '../config'; import { handleErrors } from './aoi'; -export function postFinalTokensOSMCha( - oauth_token: string, - oauth_token_secret: string, - oauth_verifier: string -) { +export function postFinalTokensOSMCha(code: string) { return request .post(osmchaSocialTokenUrl) .type('form') - .send({ oauth_token: oauth_token }) - .send({ oauth_verifier: oauth_verifier }) - .send({ oauth_token_secret: oauth_token_secret }) + .send({ code: code }) .then(r => { return r.body; }) @@ -23,14 +17,15 @@ export function postFinalTokensOSMCha( return Promise.reject(e); }); } -export function postTokensOSMCha() { - return request - .post(osmchaSocialTokenUrl) - .type('form') - .then(r => r.body) - .catch(e => { - console.error(e); - return Promise.reject(e); + +export function getAuthUrl() { + return fetch(`${API_URL}/social-auth/`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' } + }) + .then(handleErrors) + .then(res => { + return res.json(); }); } diff --git a/src/store/auth_actions.js b/src/store/auth_actions.js index ae80be36..945876e8 100644 --- a/src/store/auth_actions.js +++ b/src/store/auth_actions.js @@ -5,7 +5,6 @@ import { push } from 'react-router-redux'; import { fromJS } from 'immutable'; import { - postTokensOSMCha, postFinalTokensOSMCha, fetchUserDetails, updateUserDetails @@ -24,7 +23,6 @@ import type { RootStateType } from './'; export const AUTH = { postSocialToken: 'AUTH_POST_SOCIAL_TOKEN', - saveOAuth: 'AUTH_SAVE_OAUTH_OBJ', getFinalToken: 'AUTH_GET_FINAL_TOKEN', saveToken: 'AUTH_SAVE_TOKEN', logout: 'AUTH_LOGOUT', @@ -43,8 +41,8 @@ export function action(type: string, payload: ?Object) { // starting point for react component to start fetch export const getOAuthToken = () => action(AUTH.postSocialToken); -export const getFinalToken = (oauth_verifier: string) => - action(AUTH.getFinalToken, { oauth_verifier }); +export const getFinalToken = (code: string) => + action(AUTH.getFinalToken, { code }); export const logUserOut = () => action(AUTH.logout); @@ -150,8 +148,6 @@ export function* watchAuth(): any { export function* logoutFlow(): any { yield call(removeItem, 'token'); - yield call(removeItem, 'oauth_token'); - yield call(removeItem, 'oauth_token_secret'); yield put(action(AUTH.clearSession)); yield put(action(TRUSTEDLIST.clear)); // get CHANGESET_PAGE without user metadata @@ -170,34 +166,36 @@ export function* logoutFlow(): any { } export function* authTokenFlow(): any { - const { oauth_token, oauth_token_secret } = yield call(postTokensOSMCha); - yield put( - action(AUTH.saveOAuth, { - oauth_token, - oauth_token_secret - }) - ); + console.log('Authorization flow started'); // yield take(ACTION) waits for the particular action // to emit and resume the flow. next in action would // be to wait for the action `GET_FINAL_TOKEN` // and resume the flow - const { oauth_verifier } = yield take(AUTH.getFinalToken); - const { token } = yield call( - postFinalTokensOSMCha, - oauth_token, - oauth_token_secret, - oauth_verifier + const { code } = yield take(AUTH.getFinalToken); + yield put( + modal({ + kind: 'warning', + title: 'Login in progress', + description: 'Please, wait. We are logging you in.', + autoDismiss: 1 + }) ); + const { token } = yield call(postFinalTokensOSMCha, code); if (!token || token === '') { throw new Error('invalid token'); } + yield put( + modal({ + kind: 'success', + title: 'Successful authentication', + description: 'You are now logged in!', + autoDismiss: 2 + }) + ); yield call(setItem, 'token', token); - yield call(setItem, 'oauth_token', oauth_token); - yield call(setItem, 'oauth_token_secret', oauth_token_secret); yield put( action(AUTH.saveToken, { - token, - oauth_verifier + token }) ); return token; diff --git a/src/store/auth_reducer.js b/src/store/auth_reducer.js index 5dad9341..58ec8a50 100644 --- a/src/store/auth_reducer.js +++ b/src/store/auth_reducer.js @@ -20,12 +20,6 @@ export function authReducer( action: Object ): AuthType { switch (action.type) { - case AUTH.saveOAuth: { - return state - .set('oAuthToken', action.oauth_token) - .set('oAuthTokenSecret', action.oauth_token_secret) - .set('error', null); - } case AUTH.saveToken: { return state.set('token', action.token).set('error', null); } diff --git a/src/store/changesets_page_actions.js b/src/store/changesets_page_actions.js index 9245db0c..4c64f5ae 100644 --- a/src/store/changesets_page_actions.js +++ b/src/store/changesets_page_actions.js @@ -114,6 +114,7 @@ export function* fetchChangesetsPageSaga({ }) ); } catch (error) { + const token = yield select(tokenSelector); yield put( action(CHANGESETS_PAGE.error, { pageIndex: oldPageIndex, @@ -121,14 +122,17 @@ export function* fetchChangesetsPageSaga({ }) ); error.name = `Failed to load page ${pageIndex}`; - yield put( - modal({ - error, - callback: action, - callbackLabel: 'Retry', - callbackArgs: [CHANGESETS_PAGE.fetch, { pageIndex }] - }) - ); + if (token) { + yield put( + modal({ + error, + callback: action, + callbackLabel: 'Retry', + callbackArgs: [CHANGESETS_PAGE.fetch, { pageIndex }], + autoDismiss: 1 + }) + ); + } } } diff --git a/src/store/tests/auth.test.js b/src/store/tests/auth.test.js index 004251a6..2eacd30e 100644 --- a/src/store/tests/auth.test.js +++ b/src/store/tests/auth.test.js @@ -15,19 +15,13 @@ import { watchAuth, authTokenFlow, AUTH, tokenSelector } from '../auth_actions'; import { authReducer } from '../auth_reducer'; const token = '2d2289bd78985b2b46af29607ee50fa37cb1723a'; -const oauth_verifier = 'xbiZdWS1EYS608suvHrL'; -const oauth_token_secret = 'C2l9h7YEC1AzSyCi1aTKmsOi0WmEU7DMolabWrPZ'; -const oauth_token = 'zi2Lu2r5H1z5ZTbQ2YIjZJHRnwmOHKpBfvWu83ZG'; +const code = 'xbiZdWS1EYS608suvHrL'; describe('auth actions testing', () => { it('test authTokenFlow ', async () => { const result = await expectSaga(authTokenFlow) .withReducer(authReducer) .provide([ - [ - matchers.call.fn(postTokensOSMCha), - { oauth_token_secret, oauth_token } - ], [ matchers.call.fn(postFinalTokensOSMCha), { @@ -36,37 +30,23 @@ describe('auth actions testing', () => { ], [matchers.call.fn(setItem)] ]) - .put({ - type: AUTH.saveOAuth, - oauth_token_secret, - oauth_token - }) .dispatch({ type: AUTH.getFinalToken, - oauth_verifier + code }) .delay(100) .dispatch({ type: AUTH.saveToken, token, - oauth_verifier + code }) .run(); const { effects, storeState } = result; expect(effects.call).toHaveLength(5); expect(effects.put).toHaveLength(1); expect(effects.call[0]).toEqual(call(postTokensOSMCha)); - expect(effects.call[1]).toEqual( - call( - postFinalTokensOSMCha, - oauth_token, - oauth_token_secret, - oauth_verifier - ) - ); + expect(effects.call[1]).toEqual(call(postFinalTokensOSMCha, code)); const finalStore = fromJS({ - oAuthToken: oauth_token, - oAuthTokenSecret: oauth_token_secret, error: null, token, userDetails: null diff --git a/src/utils/create_popup.js b/src/utils/create_popup.js deleted file mode 100644 index 90efb27e..00000000 --- a/src/utils/create_popup.js +++ /dev/null @@ -1,19 +0,0 @@ -export function createPopup( - title: string = 'Authentication', - location: string -) { - const width = 500; - const height = 600; - const settings = [ - ['width', width], - ['height', height], - ['left', window.innerWidth.width / 2 - width / 2], - ['top', window.innerHeight.height / 2 - height / 2] - ] - .map(x => x.join('=')) - .join(','); - - const popup = window.open('about:blank', title, settings); - if (!popup) return; - popup.location = location; -} diff --git a/src/utils/handle_popup_callback.js b/src/utils/handle_popup_callback.js deleted file mode 100644 index beb22a18..00000000 --- a/src/utils/handle_popup_callback.js +++ /dev/null @@ -1,21 +0,0 @@ -const parseQueryString = queryString => { - const query = {}; - queryString.split('&').forEach(pair => { - const [key, value] = pair.split('='); - query[decodeURIComponent(key)] = decodeURIComponent(value) || null; - }); - - return query; -}; - -export function handlePopupCallback() { - // TO-FIX what if it never resolves - return new Promise((res, rej) => { - window.authComplete = location => { - const queryString = location.split('?')[1]; - const creds = parseQueryString(queryString); - delete window.authComplete; - return res(creds); - }; - }); -} diff --git a/src/utils/index.js b/src/utils/index.js index ad192c85..bf542350 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,11 +1,9 @@ export * from './analytics'; export * from './cmap'; export * from './component'; -export * from './create_popup'; export * from './dispatch_event'; export * from './element_in_view'; export * from './filters'; -export * from './handle_popup_callback'; export * from './number_with_commas'; export * from './promise'; export * from './query_params'; diff --git a/src/views/authorized.js b/src/views/authorized.js new file mode 100644 index 00000000..9ac57699 --- /dev/null +++ b/src/views/authorized.js @@ -0,0 +1,41 @@ +// @flow +import React from 'react'; +import { connect } from 'react-redux'; +import { push } from 'react-router-redux'; + +import { getFinalToken } from '../store/auth_actions'; +import type { RootStateType } from '../store'; + +class Authorized extends React.PureComponent { + props: { + location: Object, + getFinalToken: string => mixed, + push: any => any + }; + state = { + isReadyToRedirect: false + }; + + componentDidMount() { + const params = new URLSearchParams(this.props.location.search); + let authCode = params.get('code'); + this.props.getFinalToken(authCode); + this.props.push({ ...this.props.location, search: '', pathname: '/' }); + } + + render() { + return
Logging in...
; + } +} + +Authorized = connect( + (state: RootStateType, props) => ({ + location: state.routing.location + }), + { + getFinalToken, + push + } +)(Authorized); + +export { Authorized }; diff --git a/src/views/navbar_sidebar.js b/src/views/navbar_sidebar.js index d149fbeb..7a7278f3 100644 --- a/src/views/navbar_sidebar.js +++ b/src/views/navbar_sidebar.js @@ -8,10 +8,8 @@ import { Button } from '../components/button'; import { Navbar } from '../components/navbar'; import { Dropdown } from '../components/dropdown'; -import { createPopup } from '../utils/create_popup'; -import { handlePopupCallback, isMobile } from '../utils'; -import { osmAuthUrl } from '../config/constants'; -import { isDev, isLocal } from '../config'; +import { isMobile } from '../utils'; +import { getAuthUrl } from '../network/auth'; import { getOAuthToken, @@ -35,19 +33,8 @@ class NavbarSidebar extends React.PureComponent { }; handleLoginClick = () => { - var oAuthToken = this.props.oAuthToken; - if (!oAuthToken) return; - - let url; - if (isDev || isLocal) { - url = `/local-landing.html#${oAuthToken}`; - } else { - url = `${osmAuthUrl}?oauth_token=${oAuthToken}`; - } - - createPopup('oauth_popup', url); - handlePopupCallback().then(oAuthObj => { - this.props.getFinalToken(oAuthObj.oauth_verifier); + getAuthUrl().then(res => { + window.location.assign(res.auth_url); }); }; From 6b3daf84fe6cdfdf7dbb8cb01e819faeec88c0b5 Mon Sep 17 00:00:00 2001 From: Wille Marcel Date: Thu, 30 May 2024 08:06:39 -0300 Subject: [PATCH 4/4] Fix cache regular expression --- config-overrides.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config-overrides.js b/config-overrides.js index 94ae57f3..9dfa9473 100644 --- a/config-overrides.js +++ b/config-overrides.js @@ -26,7 +26,7 @@ const RUNTIME_CACHING = [ } }, { - urlPattern: /real-changesets.s3.us-west-2.amazonaws.com\//, + urlPattern: /^https:\/\/real-changesets\.s3\.us-west-2\.amazonaws\.com\/.*/, handler: 'cacheFirst', options: { cache: {