diff --git a/app/soapbox/actions/external_auth.js b/app/soapbox/actions/external_auth.js index b3258ab70..c6fc5d340 100644 --- a/app/soapbox/actions/external_auth.js +++ b/app/soapbox/actions/external_auth.js @@ -13,7 +13,9 @@ import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/ import { obtainOAuthToken } from 'soapbox/actions/oauth'; import { parseBaseURL } from 'soapbox/utils/auth'; import sourceCode from 'soapbox/utils/code'; +import { getWalletAndSign } from 'soapbox/utils/ethereum'; import { getFeatures } from 'soapbox/utils/features'; +import { getQuirks } from 'soapbox/utils/quirks'; import { baseClient } from '../api'; @@ -32,36 +34,86 @@ const fetchExternalInstance = baseURL => { }); }; -export function createAppAndRedirect(host) { +function createExternalApp(instance, baseURL) { + return (dispatch, getState) => { + // Mitra: skip creating the auth app + if (getQuirks(instance).noApps) return new Promise(f => f({})); + + const { scopes } = getFeatures(instance); + + const params = { + client_name: sourceCode.displayName, + redirect_uris: `${window.location.origin}/auth/external`, + website: sourceCode.homepage, + scopes, + }; + + return dispatch(createApp(params, baseURL)); + }; +} + +function externalAuthorize(instance, baseURL) { + return (dispatch, getState) => { + const { scopes } = getFeatures(instance); + + return dispatch(createExternalApp(instance, baseURL)).then(app => { + const { client_id, redirect_uri } = app; + + const query = new URLSearchParams({ + client_id, + redirect_uri, + response_type: 'code', + scope: scopes, + }); + + localStorage.setItem('soapbox:external:app', JSON.stringify(app)); + localStorage.setItem('soapbox:external:baseurl', baseURL); + localStorage.setItem('soapbox:external:scopes', scopes); + + window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`; + }); + }; +} + +export function externalEthereumLogin(instance, baseURL) { + return (dispatch, getState) => { + const loginMessage = instance.get('login_message'); + + return getWalletAndSign(loginMessage).then(({ wallet, signature }) => { + return dispatch(createExternalApp(instance, baseURL)).then(app => { + const params = { + grant_type: 'ethereum', + wallet_address: wallet.toLowerCase(), + client_id: app.client_id, + client_secret: app.client_secret, + password: signature, + redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', + scope: getFeatures(instance).scopes, + }; + + 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 = '/'); + }); + }); + }; +} + +export function externalLogin(host) { return (dispatch, getState) => { const baseURL = parseBaseURL(host) || parseBaseURL(`https://${host}`); return fetchExternalInstance(baseURL).then(instance => { - const { scopes } = getFeatures(instance); + const features = getFeatures(instance); + const quirks = getQuirks(instance); - const params = { - client_name: sourceCode.displayName, - redirect_uris: `${window.location.origin}/auth/external`, - website: sourceCode.homepage, - scopes, - }; - - return dispatch(createApp(params, baseURL)).then(app => { - const { client_id, redirect_uri } = app; - - const query = new URLSearchParams({ - client_id, - redirect_uri, - response_type: 'code', - scope: scopes, - }); - - localStorage.setItem('soapbox:external:app', JSON.stringify(app)); - localStorage.setItem('soapbox:external:baseurl', baseURL); - localStorage.setItem('soapbox:external:scopes', scopes); - - window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`; - }); + if (features.ethereumLogin && quirks.noOAuthForm) { + return dispatch(externalEthereumLogin(instance, baseURL)); + } else { + return dispatch(externalAuthorize(instance, baseURL)); + } }); }; } diff --git a/app/soapbox/features/auth_login/components/login_form.js b/app/soapbox/features/auth_login/components/login_form.js index 62b80f0af..549ebb338 100644 --- a/app/soapbox/features/auth_login/components/login_form.js +++ b/app/soapbox/features/auth_login/components/login_form.js @@ -15,11 +15,10 @@ const messages = defineMessages({ const mapStateToProps = state => { const instance = state.get('instance'); - const features = getFeatures(instance); return { baseURL: getBaseURL(state), - hasResetPasswordAPI: features.resetPasswordAPI, + features: getFeatures(instance), }; }; @@ -28,7 +27,7 @@ export default @connect(mapStateToProps) class LoginForm extends ImmutablePureComponent { render() { - const { intl, isLoading, handleSubmit, baseURL, hasResetPasswordAPI } = this.props; + const { intl, isLoading, handleSubmit, baseURL, features } = this.props; return (