Skip to content

Commit

Permalink
Enable oauth2 authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
willemarcel committed May 29, 2024
1 parent 2026623 commit 0205188
Show file tree
Hide file tree
Showing 16 changed files with 105 additions and 228 deletions.
42 changes: 0 additions & 42 deletions public/local-landing.html

This file was deleted.

13 changes: 0 additions & 13 deletions public/oauth-landing.html

This file was deleted.

2 changes: 2 additions & 0 deletions src/AppDesktop.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -60,6 +61,7 @@ export const AppDesktop = () => {
<Route path="/saved-filters" component={SavedFilters} />
<Route path="/trusted-users" component={TrustedUsers} />
<Route path="/watchlist" component={Watchlist} />
<Route path="/authorized" component={Authorized} />
</CSSTransitionGroup>
)}
/>
Expand Down
3 changes: 2 additions & 1 deletion src/AppMobile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -41,6 +41,7 @@ export const AppMobile = () => {
<Route path="/saved-filters" component={SavedFilters} />
<Route path="/trusted-users" component={TrustedUsers} />
<Route path="/watchlist" component={Watchlist} />
<Route path="/authorized" component={Authorized} />
<Route exact path="/teams" component={MappingTeams} />
<Route path={'/teams/:id'} component={EditMappingTeam} />
</div>
Expand Down
43 changes: 8 additions & 35 deletions src/components/changeset/sign_in_button.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand All @@ -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 };
1 change: 0 additions & 1 deletion src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
27 changes: 11 additions & 16 deletions src/network/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
})
Expand All @@ -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();
});
}

Expand Down
44 changes: 21 additions & 23 deletions src/store/auth_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { push } from 'react-router-redux';
import { fromJS } from 'immutable';

import {
postTokensOSMCha,
postFinalTokensOSMCha,
fetchUserDetails,
updateUserDetails
Expand All @@ -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',
Expand All @@ -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);

Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down
6 changes: 0 additions & 6 deletions src/store/auth_reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
20 changes: 12 additions & 8 deletions src/store/changesets_page_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,21 +114,25 @@ export function* fetchChangesetsPageSaga({
})
);
} catch (error) {
const token = yield select(tokenSelector);
yield put(
action(CHANGESETS_PAGE.error, {
pageIndex: oldPageIndex,
error
})
);
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
})
);
}
}
}

Expand Down
Loading

0 comments on commit 0205188

Please sign in to comment.