From a731ac88cfe4680f2f5d7e41000f2629a97da212 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 24 Mar 2021 00:05:06 -0500 Subject: [PATCH] Make login work again --- app/soapbox/actions/auth.js | 13 ++++++----- app/soapbox/actions/me.js | 2 +- .../auth_login/components/login_page.js | 7 +++--- .../public_layout/components/header.js | 7 +++--- app/soapbox/reducers/auth.js | 23 ++++++++++++++++--- app/soapbox/reducers/me.js | 4 +++- app/soapbox/reducers/settings.js | 13 ++++++++--- 7 files changed, 47 insertions(+), 22 deletions(-) diff --git a/app/soapbox/actions/auth.js b/app/soapbox/actions/auth.js index e70c0bcbe..6b0418b8b 100644 --- a/app/soapbox/actions/auth.js +++ b/app/soapbox/actions/auth.js @@ -94,8 +94,9 @@ function createUserToken(username, password) { grant_type: 'password', username: username, password: password, - }).then(response => { - dispatch(authLoggedIn(response.data)); + }).then(({ data: token }) => { + dispatch(authLoggedIn(token)); + return token; }); }; } @@ -143,7 +144,7 @@ export function verifyCredentials(token) { method: 'get', url: '/api/v1/accounts/verify_credentials', headers: { - 'Authorization': `Bearer ${token.get('access_token')}`, + 'Authorization': `Bearer ${token}`, }, }; @@ -198,10 +199,10 @@ export function switchAccount(accountId) { export function fetchOwnAccounts() { return throttle((dispatch, getState) => { const state = getState(); - state.getIn(['auth', 'users']).forEach((token, id) => { - const account = state.getIn(['accounts', id]); + state.getIn(['auth', 'users']).forEach(user => { + const account = state.getIn(['accounts', user.get('id')]); if (!account) { - dispatch(verifyCredentials(token)); + dispatch(verifyCredentials(user.get('access_token'))); } }); }, 2000); diff --git a/app/soapbox/actions/me.js b/app/soapbox/actions/me.js index 7ccf07757..5b58b50b1 100644 --- a/app/soapbox/actions/me.js +++ b/app/soapbox/actions/me.js @@ -18,7 +18,7 @@ export function fetchMe() { const state = getState(); const me = state.getIn(['auth', 'me']); - const token = state.getIn(['auth', 'users', me]); + const token = state.getIn(['auth', 'users', me, 'access_token']); if (!token) { dispatch({ type: ME_FETCH_SKIP }); return noOp(); diff --git a/app/soapbox/features/auth_login/components/login_page.js b/app/soapbox/features/auth_login/components/login_page.js index 3e2cea0e1..30e0cc94b 100644 --- a/app/soapbox/features/auth_login/components/login_page.js +++ b/app/soapbox/features/auth_login/components/login_page.js @@ -4,8 +4,7 @@ import { Redirect } from 'react-router-dom'; import ImmutablePureComponent from 'react-immutable-pure-component'; import LoginForm from './login_form'; import OtpAuthForm from './otp_auth_form'; -import { logIn } from 'soapbox/actions/auth'; -import { fetchMe } from 'soapbox/actions/me'; +import { logIn, verifyCredentials } from 'soapbox/actions/auth'; const mapStateToProps = state => ({ me: state.get('me'), @@ -35,8 +34,8 @@ class LoginPage extends ImmutablePureComponent { handleSubmit = (event) => { const { dispatch } = this.props; const { username, password } = this.getFormData(event.target); - dispatch(logIn(username, password)).then(() => { - return dispatch(fetchMe()); + dispatch(logIn(username, password)).then(({ access_token }) => { + return dispatch(verifyCredentials(access_token)); }).catch(error => { if (error.response.data.error === 'mfa_required') { this.setState({ mfa_auth_needed: true, mfa_token: error.response.data.mfa_token }); diff --git a/app/soapbox/features/public_layout/components/header.js b/app/soapbox/features/public_layout/components/header.js index 453be4b1d..7d3d864b5 100644 --- a/app/soapbox/features/public_layout/components/header.js +++ b/app/soapbox/features/public_layout/components/header.js @@ -8,8 +8,7 @@ import SiteLogo from './site_logo'; import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types'; import { defineMessages, injectIntl } from 'react-intl'; import PropTypes from 'prop-types'; -import { logIn } from 'soapbox/actions/auth'; -import { fetchMe } from 'soapbox/actions/me'; +import { logIn, verifyCredentials } from 'soapbox/actions/auth'; import OtpAuthForm from 'soapbox/features/auth_login/components/otp_auth_form'; import IconButton from 'soapbox/components/icon_button'; @@ -55,8 +54,8 @@ class Header extends ImmutablePureComponent { handleSubmit = (event) => { const { dispatch } = this.props; const { username, password } = this.getFormData(event.target); - dispatch(logIn(username, password)).then(() => { - return dispatch(fetchMe()); + dispatch(logIn(username, password)).then(({ access_token }) => { + return dispatch(verifyCredentials(access_token)); }).catch(error => { if (error.response.data.error === 'mfa_required') { this.setState({ mfa_auth_needed: true, mfa_token: error.response.data.mfa_token }); diff --git a/app/soapbox/reducers/auth.js b/app/soapbox/reducers/auth.js index 6a4a4f502..c6ae6035c 100644 --- a/app/soapbox/reducers/auth.js +++ b/app/soapbox/reducers/auth.js @@ -4,19 +4,34 @@ import { AUTH_APP_AUTHORIZED, AUTH_LOGGED_OUT, SWITCH_ACCOUNT, + VERIFY_CREDENTIALS_SUCCESS, } from '../actions/auth'; import { Map as ImmutableMap, fromJS } from 'immutable'; const defaultState = ImmutableMap({ app: ImmutableMap(), - user: ImmutableMap(), - users: ImmutableMap(), + tokens: ImmutableMap(), me: null, }); const localState = fromJS(JSON.parse(localStorage.getItem('soapbox:auth'))); const initialState = defaultState.merge(localState); +const importToken = (state, token) => { + return state.setIn(['tokens', token.access_token], fromJS(token)); +}; + +const importCredentials = (state, token, account) => { + return state.withMutations(state => { + state.setIn(['users', account.id], ImmutableMap({ + id: account.id, + access_token: token, + })); + state.setIn(['tokens', token, 'account'], account.id); + state.update('me', null, me => me || account.id); + }); +}; + const reducer = (state, action) => { switch(action.type) { case AUTH_APP_CREATED: @@ -24,9 +39,11 @@ const reducer = (state, action) => { case AUTH_APP_AUTHORIZED: return state.update('app', ImmutableMap(), app => app.merge(fromJS(action.app))); case AUTH_LOGGED_IN: - return state.set('user', fromJS(action.token)); + return importToken(state, action.token); case AUTH_LOGGED_OUT: return state.set('user', ImmutableMap()); + case VERIFY_CREDENTIALS_SUCCESS: + return importCredentials(state, action.token, action.account); case SWITCH_ACCOUNT: return state.set('me', action.accountId); default: diff --git a/app/soapbox/reducers/me.js b/app/soapbox/reducers/me.js index d5304c4e4..a7bd1a94f 100644 --- a/app/soapbox/reducers/me.js +++ b/app/soapbox/reducers/me.js @@ -4,7 +4,7 @@ import { ME_FETCH_SKIP, ME_PATCH_SUCCESS, } from '../actions/me'; -import { AUTH_LOGGED_OUT } from '../actions/auth'; +import { AUTH_LOGGED_OUT, VERIFY_CREDENTIALS_SUCCESS } from '../actions/auth'; const initialState = null; @@ -13,6 +13,8 @@ export default function me(state = initialState, action) { case ME_FETCH_SUCCESS: case ME_PATCH_SUCCESS: return action.me.id; + case VERIFY_CREDENTIALS_SUCCESS: + return state || action.account.id; case ME_FETCH_FAIL: case ME_FETCH_SKIP: case AUTH_LOGGED_OUT: diff --git a/app/soapbox/reducers/settings.js b/app/soapbox/reducers/settings.js index be4f6b88d..297cf2ff1 100644 --- a/app/soapbox/reducers/settings.js +++ b/app/soapbox/reducers/settings.js @@ -3,6 +3,7 @@ import { NOTIFICATIONS_FILTER_SET } from '../actions/notifications'; import { EMOJI_USE } from '../actions/emojis'; import { LIST_DELETE_SUCCESS, LIST_FETCH_FAIL } from '../actions/lists'; import { ME_FETCH_SUCCESS } from 'soapbox/actions/me'; +import { VERIFY_CREDENTIALS_SUCCESS } from 'soapbox/actions/auth'; import { Map as ImmutableMap, fromJS } from 'immutable'; // Default settings are in action/settings.js @@ -17,12 +18,18 @@ const updateFrequentEmojis = (state, emoji) => state.update('frequentlyUsedEmoji const filterDeadListColumns = (state, listId) => state.update('columns', columns => columns.filterNot(column => column.get('id') === 'LIST' && column.get('params').get('id') === listId)); +const importSettings = (state, account) => { + account = fromJS(account); + const prefs = account.getIn(['pleroma', 'settings_store', FE_NAME], ImmutableMap()); + return state.merge(prefs); +}; + export default function settings(state = initialState, action) { switch(action.type) { case ME_FETCH_SUCCESS: - const me = fromJS(action.me); - let fePrefs = me.getIn(['pleroma', 'settings_store', FE_NAME], ImmutableMap()); - return state.merge(fePrefs); + return importSettings(state, action.me); + case VERIFY_CREDENTIALS_SUCCESS: + return importSettings(state, action.account); case NOTIFICATIONS_FILTER_SET: case SETTING_CHANGE: return state