Standalone: add external accounts, refresh on logout

merge-requests/700/head
Alex Gleason 2021-08-30 16:41:05 -07:00
rodzic dca2d98dfc
commit c624afdfb7
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
7 zmienionych plików z 38 dodań i 142 usunięć

Wyświetl plik

@ -18,6 +18,7 @@ import { createApp } from 'soapbox/actions/apps';
import { obtainOAuthToken, revokeOAuthToken } from 'soapbox/actions/oauth';
import sourceCode from 'soapbox/utils/code';
import { getFeatures } from 'soapbox/utils/features';
import { isStandalone } from 'soapbox/utils/state';
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
@ -177,6 +178,7 @@ export function logOut(intl) {
return (dispatch, getState) => {
const state = getState();
const account = getLoggedInAccount(state);
const standalone = isStandalone(state);
const params = {
client_id: state.getIn(['auth', 'app', 'client_id']),
@ -185,7 +187,7 @@ export function logOut(intl) {
};
return dispatch(revokeOAuthToken(params)).finally(() => {
dispatch({ type: AUTH_LOGGED_OUT, account });
dispatch({ type: AUTH_LOGGED_OUT, account, standalone });
dispatch(snackbar.success(intl.formatMessage(messages.loggedOut)));
});
};

Wyświetl plik

@ -9,7 +9,7 @@
import { baseClient } from '../api';
import { createApp } from 'soapbox/actions/apps';
import { obtainOAuthToken } from 'soapbox/actions/oauth';
import { authLoggedIn, verifyCredentials } from 'soapbox/actions/auth';
import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
import { parseBaseURL } from 'soapbox/utils/auth';
import { getFeatures } from 'soapbox/utils/features';
import sourceCode from 'soapbox/utils/code';
@ -73,6 +73,7 @@ export function loginWithCode(code) {
return dispatch(obtainOAuthToken(params, baseURL))
.then(token => dispatch(authLoggedIn(token)))
.then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL)))
.then(account => dispatch(switchAccount(account.id)))
.then(() => window.location.href = '/');
};
}

Wyświetl plik

@ -1,129 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<LoginPage /> renders correctly on load 1`] = `
<form
className="simple_form new_user"
method="post"
onSubmit={[Function]}
>
<fieldset
disabled={false}
>
<div
className="fields-group"
>
<div
className="input email user_email"
>
<input
aria-label="Username"
autoComplete="off"
className="string email"
name="username"
placeholder="Username"
required={true}
type="text"
/>
</div>
<div
className="input password user_password"
>
<input
aria-label="Password"
autoComplete="off"
className="password"
name="password"
placeholder="Password"
required={true}
type="password"
/>
</div>
<p
className="hint subtle-hint"
>
<a
href="/auth/reset_password"
onClick={[Function]}
>
Trouble logging in?
</a>
</p>
</div>
</fieldset>
<div
className="actions"
>
<button
className="btn button button-primary"
name="button"
type="submit"
>
Log in
</button>
</div>
</form>
`;
exports[`<LoginPage /> renders correctly on load 1`] = `null`;
exports[`<LoginPage /> renders correctly on load 2`] = `
<form
className="simple_form new_user"
method="post"
onSubmit={[Function]}
>
<fieldset
disabled={false}
>
<div
className="fields-group"
>
<div
className="input email user_email"
>
<input
aria-label="Username"
autoComplete="off"
className="string email"
name="username"
placeholder="Username"
required={true}
type="text"
/>
</div>
<div
className="input password user_password"
>
<input
aria-label="Password"
autoComplete="off"
className="password"
name="password"
placeholder="Password"
required={true}
type="password"
/>
</div>
<p
className="hint subtle-hint"
>
<a
href="/auth/reset_password"
onClick={[Function]}
>
Trouble logging in?
</a>
</p>
</div>
</fieldset>
<div
className="actions"
>
<button
className="btn button button-primary"
name="button"
type="submit"
>
Log in
</button>
</div>
</form>
`;
exports[`<LoginPage /> renders correctly on load 2`] = `null`;

Wyświetl plik

@ -6,10 +6,12 @@ import { injectIntl } from 'react-intl';
import LoginForm from './login_form';
import OtpAuthForm from './otp_auth_form';
import { logIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
import { isStandalone } from 'soapbox/utils/state';
const mapStateToProps = state => ({
me: state.get('me'),
isLoading: false,
standalone: isStandalone(state),
});
export default @connect(mapStateToProps)
@ -55,8 +57,11 @@ class LoginPage extends ImmutablePureComponent {
}
render() {
const { standalone } = this.props;
const { isLoading, mfa_auth_needed, mfa_token, shouldRedirect } = this.state;
if (standalone) return <Redirect to='/auth/external' />;
if (shouldRedirect) return <Redirect to='/' />;
if (mfa_auth_needed) return <OtpAuthForm mfa_token={mfa_token} />;

Wyświetl plik

@ -9,19 +9,7 @@ import Footer from './components/footer';
import LandingPage from '../landing_page';
import AboutPage from '../about';
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
import { isPrerendered } from 'soapbox/precheck';
const validInstance = state => {
const v = state.getIn(['instance', 'version']);
return v && typeof v === 'string' && v !== '0.0.0';
};
const isStandalone = state => {
const hasInstance = validInstance(state);
const instanceFetchFailed = state.getIn(['meta', 'instance_fetch_failed']);
return !isPrerendered && !hasInstance && instanceFetchFailed;
};
import { isStandalone } from 'soapbox/utils/state';
const mapStateToProps = (state, props) => ({
soapbox: getSoapboxConfig(state),

Wyświetl plik

@ -261,7 +261,10 @@ const userSwitched = (oldState, state) => {
};
const maybeReload = (oldState, state, action) => {
if (userSwitched(oldState, state)) {
const loggedOutStandalone = action.type === AUTH_LOGGED_OUT && action.standalone;
const switched = userSwitched(oldState, state);
if (switched || loggedOutStandalone) {
reload(state);
}
};

Wyświetl plik

@ -1,4 +1,13 @@
/**
* State: general Redux state utility functions.
* @module soapbox/utils/state
*/
import { getSoapboxConfig } from'soapbox/actions/soapbox';
import { createSelector } from 'reselect';
import { isPrerendered } from 'soapbox/precheck';
import { isURL } from 'soapbox/utils/auth';
import { BACKEND_URL } from 'soapbox/build_config';
export const displayFqn = state => {
const soapbox = getSoapboxConfig(state);
@ -8,3 +17,15 @@ export const displayFqn = state => {
export const federationRestrictionsDisclosed = state => {
return state.hasIn(['instance', 'pleroma', 'metadata', 'federation', 'mrf_policies']);
};
/**
* Determine whether Soapbox FE is running in standalone mode.
* Standalone mode runs separately from any backend and can login anywhere.
* @param {object} state
* @returns {boolean}
*/
export const isStandalone = state => createSelector([
state => state.getIn(['meta', 'instance_fetch_failed'], false),
], instanceFetchFailed => {
return isURL(BACKEND_URL) ? false : (!isPrerendered && instanceFetchFailed);
});