2021-06-26 15:04:27 -07:00
|
|
|
import { defineMessages } from 'react-intl';
|
2021-03-31 12:47:54 -07:00
|
|
|
import api, { baseClient } from '../api';
|
2021-03-23 19:01:50 -07:00
|
|
|
import { importFetchedAccount } from './importer';
|
2020-09-29 17:10:57 -07:00
|
|
|
import snackbar from 'soapbox/actions/snackbar';
|
2021-03-26 13:29:15 -07:00
|
|
|
import { createAccount } from 'soapbox/actions/accounts';
|
2021-05-07 19:49:08 -07:00
|
|
|
import { fetchMeSuccess, fetchMeFail } from 'soapbox/actions/me';
|
2021-08-21 18:41:29 -07:00
|
|
|
import { getLoggedInAccount, parseBaseURL } from 'soapbox/utils/auth';
|
2021-08-21 17:05:59 -07:00
|
|
|
import { createApp } from 'soapbox/actions/apps';
|
2021-08-21 17:37:28 -07:00
|
|
|
import { obtainOAuthToken, revokeOAuthToken } from 'soapbox/actions/oauth';
|
2021-08-21 20:46:33 -07:00
|
|
|
import sourceCode from 'soapbox/utils/code';
|
2020-04-04 13:28:57 -07:00
|
|
|
|
2021-03-23 17:06:55 -07:00
|
|
|
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
|
|
|
|
|
2020-04-05 16:39:22 -07:00
|
|
|
export const AUTH_APP_CREATED = 'AUTH_APP_CREATED';
|
|
|
|
export const AUTH_APP_AUTHORIZED = 'AUTH_APP_AUTHORIZED';
|
|
|
|
export const AUTH_LOGGED_IN = 'AUTH_LOGGED_IN';
|
2020-04-11 12:41:13 -07:00
|
|
|
export const AUTH_LOGGED_OUT = 'AUTH_LOGGED_OUT';
|
2020-04-05 14:54:51 -07:00
|
|
|
|
2021-03-23 17:06:55 -07:00
|
|
|
export const VERIFY_CREDENTIALS_REQUEST = 'VERIFY_CREDENTIALS_REQUEST';
|
|
|
|
export const VERIFY_CREDENTIALS_SUCCESS = 'VERIFY_CREDENTIALS_SUCCESS';
|
|
|
|
export const VERIFY_CREDENTIALS_FAIL = 'VERIFY_CREDENTIALS_FAIL';
|
|
|
|
|
2020-05-24 16:22:36 -07:00
|
|
|
export const RESET_PASSWORD_REQUEST = 'RESET_PASSWORD_REQUEST';
|
|
|
|
export const RESET_PASSWORD_SUCCESS = 'RESET_PASSWORD_SUCCESS';
|
|
|
|
export const RESET_PASSWORD_FAIL = 'RESET_PASSWORD_FAIL';
|
|
|
|
|
2020-06-05 13:27:31 -07:00
|
|
|
export const CHANGE_EMAIL_REQUEST = 'CHANGE_EMAIL_REQUEST';
|
|
|
|
export const CHANGE_EMAIL_SUCCESS = 'CHANGE_EMAIL_SUCCESS';
|
|
|
|
export const CHANGE_EMAIL_FAIL = 'CHANGE_EMAIL_FAIL';
|
|
|
|
|
2020-07-20 13:23:38 -07:00
|
|
|
export const DELETE_ACCOUNT_REQUEST = 'DELETE_ACCOUNT_REQUEST';
|
|
|
|
export const DELETE_ACCOUNT_SUCCESS = 'DELETE_ACCOUNT_SUCCESS';
|
|
|
|
export const DELETE_ACCOUNT_FAIL = 'DELETE_ACCOUNT_FAIL';
|
2020-06-28 08:51:55 -07:00
|
|
|
|
2020-06-05 13:27:31 -07:00
|
|
|
export const CHANGE_PASSWORD_REQUEST = 'CHANGE_PASSWORD_REQUEST';
|
|
|
|
export const CHANGE_PASSWORD_SUCCESS = 'CHANGE_PASSWORD_SUCCESS';
|
|
|
|
export const CHANGE_PASSWORD_FAIL = 'CHANGE_PASSWORD_FAIL';
|
|
|
|
|
2021-06-26 15:04:27 -07:00
|
|
|
const messages = defineMessages({
|
|
|
|
loggedOut: { id: 'auth.logged_out', defaultMessage: 'Logged out.' },
|
|
|
|
invalidCredentials: { id: 'auth.invalid_credentials', defaultMessage: 'Wrong username or password' },
|
|
|
|
});
|
|
|
|
|
2020-04-29 16:29:41 -07:00
|
|
|
const noOp = () => () => new Promise(f => f());
|
2020-04-29 12:07:22 -07:00
|
|
|
|
2020-04-29 14:53:10 -07:00
|
|
|
function createAppAndToken() {
|
|
|
|
return (dispatch, getState) => {
|
2021-08-21 17:05:59 -07:00
|
|
|
return dispatch(createAuthApp()).then(() => {
|
2020-04-29 17:10:53 -07:00
|
|
|
return dispatch(createAppToken());
|
2020-04-29 12:07:22 -07:00
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-08-21 17:05:59 -07:00
|
|
|
function createAuthApp() {
|
2020-04-04 13:28:57 -07:00
|
|
|
return (dispatch, getState) => {
|
2021-08-21 17:05:59 -07:00
|
|
|
const params = {
|
2021-08-21 20:46:33 -07:00
|
|
|
client_name: sourceCode.displayName,
|
2020-04-04 13:28:57 -07:00
|
|
|
redirect_uris: 'urn:ietf:wg:oauth:2.0:oob',
|
2020-04-29 12:07:22 -07:00
|
|
|
scopes: 'read write follow push admin',
|
2021-08-21 17:05:59 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
return dispatch(createApp(params)).then(app => {
|
|
|
|
return dispatch({ type: AUTH_APP_CREATED, app });
|
2020-04-29 12:07:22 -07:00
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-04-29 14:53:10 -07:00
|
|
|
function createAppToken() {
|
2020-04-29 12:07:22 -07:00
|
|
|
return (dispatch, getState) => {
|
|
|
|
const app = getState().getIn(['auth', 'app']);
|
|
|
|
|
2021-08-21 17:37:28 -07:00
|
|
|
const params = {
|
2020-04-29 12:07:22 -07:00
|
|
|
client_id: app.get('client_id'),
|
|
|
|
client_secret: app.get('client_secret'),
|
2020-04-29 14:53:10 -07:00
|
|
|
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
|
|
|
grant_type: 'client_credentials',
|
2021-08-21 17:37:28 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
return dispatch(obtainOAuthToken(params)).then(token => {
|
|
|
|
return dispatch({ type: AUTH_APP_AUTHORIZED, app, token });
|
2020-04-04 13:28:57 -07:00
|
|
|
});
|
2020-04-14 11:44:40 -07:00
|
|
|
};
|
2020-04-04 13:28:57 -07:00
|
|
|
}
|
|
|
|
|
2020-04-29 17:10:53 -07:00
|
|
|
function createUserToken(username, password) {
|
2020-04-04 13:28:57 -07:00
|
|
|
return (dispatch, getState) => {
|
2020-04-05 14:54:51 -07:00
|
|
|
const app = getState().getIn(['auth', 'app']);
|
2021-08-21 17:37:28 -07:00
|
|
|
|
|
|
|
const params = {
|
2020-04-29 14:53:10 -07:00
|
|
|
client_id: app.get('client_id'),
|
2020-04-05 16:39:22 -07:00
|
|
|
client_secret: app.get('client_secret'),
|
2020-04-29 14:53:10 -07:00
|
|
|
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
|
|
|
grant_type: 'password',
|
|
|
|
username: username,
|
|
|
|
password: password,
|
2021-08-21 17:37:28 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
return dispatch(obtainOAuthToken(params)).then(token => {
|
2021-03-23 22:05:06 -07:00
|
|
|
dispatch(authLoggedIn(token));
|
|
|
|
return token;
|
2020-04-29 17:38:24 -07:00
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function refreshUserToken() {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
const refreshToken = getState().getIn(['auth', 'user', 'refresh_token']);
|
|
|
|
const app = getState().getIn(['auth', 'app']);
|
|
|
|
|
|
|
|
if (!refreshToken) return dispatch(noOp());
|
|
|
|
|
2021-08-21 17:37:28 -07:00
|
|
|
const params = {
|
2020-04-29 17:38:24 -07:00
|
|
|
client_id: app.get('client_id'),
|
|
|
|
client_secret: app.get('client_secret'),
|
|
|
|
refresh_token: refreshToken,
|
|
|
|
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
|
|
|
grant_type: 'refresh_token',
|
2021-08-21 17:37:28 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
return dispatch(obtainOAuthToken(params)).then(token => {
|
|
|
|
dispatch(authLoggedIn(token));
|
2020-04-29 17:10:53 -07:00
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-08-07 13:17:13 -07:00
|
|
|
export function otpVerify(code, mfa_token) {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
const app = getState().getIn(['auth', 'app']);
|
|
|
|
return api(getState, 'app').post('/oauth/mfa/challenge', {
|
|
|
|
client_id: app.get('client_id'),
|
|
|
|
client_secret: app.get('client_secret'),
|
|
|
|
mfa_token: mfa_token,
|
|
|
|
code: code,
|
|
|
|
challenge_type: 'totp',
|
|
|
|
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
2021-03-26 14:42:47 -07:00
|
|
|
}).then(({ data: token }) => {
|
|
|
|
dispatch(authLoggedIn(token));
|
|
|
|
return token;
|
2020-08-07 13:17:13 -07:00
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-08-21 18:41:29 -07:00
|
|
|
export function verifyCredentials(token, accountUrl) {
|
|
|
|
const baseURL = parseBaseURL(accountUrl);
|
|
|
|
|
2021-03-23 17:06:55 -07:00
|
|
|
return (dispatch, getState) => {
|
|
|
|
dispatch({ type: VERIFY_CREDENTIALS_REQUEST });
|
|
|
|
|
2021-08-21 18:41:29 -07:00
|
|
|
return baseClient(token, baseURL).get('/api/v1/accounts/verify_credentials').then(({ data: account }) => {
|
2021-03-23 19:01:50 -07:00
|
|
|
dispatch(importFetchedAccount(account));
|
2021-03-23 17:06:55 -07:00
|
|
|
dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account });
|
2021-05-09 08:37:49 -07:00
|
|
|
if (account.id === getState().get('me')) dispatch(fetchMeSuccess(account));
|
2021-03-23 17:06:55 -07:00
|
|
|
return account;
|
|
|
|
}).catch(error => {
|
2021-05-09 08:37:49 -07:00
|
|
|
if (getState().get('me') === null) dispatch(fetchMeFail(error));
|
2021-03-23 17:06:55 -07:00
|
|
|
dispatch({ type: VERIFY_CREDENTIALS_FAIL, token, error });
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-06-26 15:04:27 -07:00
|
|
|
export function logIn(intl, username, password) {
|
2020-04-29 17:10:53 -07:00
|
|
|
return (dispatch, getState) => {
|
2020-05-28 19:17:38 -07:00
|
|
|
return dispatch(createAppAndToken()).then(() => {
|
2020-04-29 17:10:53 -07:00
|
|
|
return dispatch(createUserToken(username, password));
|
|
|
|
}).catch(error => {
|
2020-08-07 13:17:13 -07:00
|
|
|
if (error.response.data.error === 'mfa_required') {
|
|
|
|
throw error;
|
2020-09-29 21:12:33 -07:00
|
|
|
} else if(error.response.data.error) {
|
|
|
|
dispatch(snackbar.error(error.response.data.error));
|
2020-08-07 13:17:13 -07:00
|
|
|
} else {
|
2021-06-26 15:04:27 -07:00
|
|
|
dispatch(snackbar.error(intl.formatMessage(messages.invalidCredentials)));
|
2020-08-07 13:17:13 -07:00
|
|
|
}
|
2020-04-11 12:41:13 -07:00
|
|
|
throw error;
|
2020-04-04 13:28:57 -07:00
|
|
|
});
|
2020-04-14 11:44:40 -07:00
|
|
|
};
|
2020-04-04 13:28:57 -07:00
|
|
|
}
|
2020-04-05 14:54:51 -07:00
|
|
|
|
2021-06-26 15:04:27 -07:00
|
|
|
export function logOut(intl) {
|
2020-04-11 12:41:13 -07:00
|
|
|
return (dispatch, getState) => {
|
2020-09-28 11:05:20 -07:00
|
|
|
const state = getState();
|
2021-08-21 14:54:53 -07:00
|
|
|
const account = getLoggedInAccount(state);
|
2020-09-28 11:05:20 -07:00
|
|
|
|
2021-08-21 17:37:28 -07:00
|
|
|
const params = {
|
2020-09-28 11:05:20 -07:00
|
|
|
client_id: state.getIn(['auth', 'app', 'client_id']),
|
|
|
|
client_secret: state.getIn(['auth', 'app', 'client_secret']),
|
2021-08-21 14:54:53 -07:00
|
|
|
token: state.getIn(['auth', 'users', account.get('url'), 'access_token']),
|
2021-08-21 17:37:28 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
return dispatch(revokeOAuthToken(params)).finally(() => {
|
2021-08-21 14:54:53 -07:00
|
|
|
dispatch({ type: AUTH_LOGGED_OUT, account });
|
2021-06-26 15:04:27 -07:00
|
|
|
dispatch(snackbar.success(intl.formatMessage(messages.loggedOut)));
|
2020-09-28 11:05:20 -07:00
|
|
|
});
|
2020-04-11 12:41:13 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-03-29 22:45:23 -07:00
|
|
|
export function switchAccount(accountId, background = false) {
|
2021-08-21 14:54:53 -07:00
|
|
|
return (dispatch, getState) => {
|
|
|
|
const account = getState().getIn(['accounts', accountId]);
|
|
|
|
dispatch({ type: SWITCH_ACCOUNT, account, background });
|
|
|
|
};
|
2021-03-23 17:06:55 -07:00
|
|
|
}
|
|
|
|
|
2021-03-23 19:01:50 -07:00
|
|
|
export function fetchOwnAccounts() {
|
2021-03-25 11:47:01 -07:00
|
|
|
return (dispatch, getState) => {
|
2021-03-23 19:01:50 -07:00
|
|
|
const state = getState();
|
2021-03-23 22:05:06 -07:00
|
|
|
state.getIn(['auth', 'users']).forEach(user => {
|
|
|
|
const account = state.getIn(['accounts', user.get('id')]);
|
2021-03-23 19:01:50 -07:00
|
|
|
if (!account) {
|
2021-08-21 18:41:29 -07:00
|
|
|
dispatch(verifyCredentials(user.get('access_token'), user.get('url')));
|
2021-03-23 19:01:50 -07:00
|
|
|
}
|
|
|
|
});
|
2021-03-25 11:47:01 -07:00
|
|
|
};
|
2021-03-23 19:01:50 -07:00
|
|
|
}
|
|
|
|
|
2020-04-23 16:41:20 -07:00
|
|
|
export function register(params) {
|
|
|
|
return (dispatch, getState) => {
|
2020-08-30 16:48:00 -07:00
|
|
|
params.fullname = params.username;
|
2021-03-26 13:29:15 -07:00
|
|
|
|
2020-05-29 07:55:38 -07:00
|
|
|
return dispatch(createAppAndToken()).then(() => {
|
2021-03-26 13:29:15 -07:00
|
|
|
return dispatch(createAccount(params));
|
2021-04-18 10:41:51 -07:00
|
|
|
}).then(({ token }) => {
|
|
|
|
dispatch(authLoggedIn(token));
|
|
|
|
return token;
|
2020-04-23 16:41:20 -07:00
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-04-23 18:48:25 -07:00
|
|
|
export function fetchCaptcha() {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
return api(getState).get('/api/pleroma/captcha');
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-05-24 16:22:36 -07:00
|
|
|
export function resetPassword(nickNameOrEmail) {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
dispatch({ type: RESET_PASSWORD_REQUEST });
|
|
|
|
const params =
|
|
|
|
nickNameOrEmail.includes('@')
|
|
|
|
? { email: nickNameOrEmail }
|
|
|
|
: { nickname: nickNameOrEmail };
|
|
|
|
return api(getState).post('/auth/password', params).then(() => {
|
|
|
|
dispatch({ type: RESET_PASSWORD_SUCCESS });
|
|
|
|
}).catch(error => {
|
2020-05-24 17:37:15 -07:00
|
|
|
dispatch({ type: RESET_PASSWORD_FAIL, error });
|
|
|
|
throw error;
|
2020-05-24 16:22:36 -07:00
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-06-05 13:27:31 -07:00
|
|
|
export function changeEmail(email, password) {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
dispatch({ type: CHANGE_EMAIL_REQUEST, email });
|
|
|
|
return api(getState).post('/api/pleroma/change_email', {
|
|
|
|
email,
|
|
|
|
password,
|
|
|
|
}).then(response => {
|
|
|
|
if (response.data.error) throw response.data.error; // This endpoint returns HTTP 200 even on failure
|
|
|
|
dispatch({ type: CHANGE_EMAIL_SUCCESS, email, response });
|
|
|
|
}).catch(error => {
|
|
|
|
dispatch({ type: CHANGE_EMAIL_FAIL, email, error, skipAlert: true });
|
|
|
|
throw error;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-06-26 15:04:27 -07:00
|
|
|
export function deleteAccount(intl, password) {
|
2020-06-28 08:51:55 -07:00
|
|
|
return (dispatch, getState) => {
|
2021-08-21 14:54:53 -07:00
|
|
|
const account = getLoggedInAccount(getState());
|
|
|
|
|
2020-07-20 13:23:38 -07:00
|
|
|
dispatch({ type: DELETE_ACCOUNT_REQUEST });
|
|
|
|
return api(getState).post('/api/pleroma/delete_account', {
|
2020-06-28 08:51:55 -07:00
|
|
|
password,
|
|
|
|
}).then(response => {
|
|
|
|
if (response.data.error) throw response.data.error; // This endpoint returns HTTP 200 even on failure
|
2020-07-20 13:23:38 -07:00
|
|
|
dispatch({ type: DELETE_ACCOUNT_SUCCESS, response });
|
2021-08-21 14:54:53 -07:00
|
|
|
dispatch({ type: AUTH_LOGGED_OUT, account });
|
2021-06-26 15:04:27 -07:00
|
|
|
dispatch(snackbar.success(intl.formatMessage(messages.loggedOut)));
|
2020-06-28 08:51:55 -07:00
|
|
|
}).catch(error => {
|
2020-07-20 13:23:38 -07:00
|
|
|
dispatch({ type: DELETE_ACCOUNT_FAIL, error, skipAlert: true });
|
2020-06-28 08:51:55 -07:00
|
|
|
throw error;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-06-05 13:27:31 -07:00
|
|
|
export function changePassword(oldPassword, newPassword, confirmation) {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
dispatch({ type: CHANGE_PASSWORD_REQUEST });
|
|
|
|
return api(getState).post('/api/pleroma/change_password', {
|
|
|
|
password: oldPassword,
|
|
|
|
new_password: newPassword,
|
|
|
|
new_password_confirmation: confirmation,
|
|
|
|
}).then(response => {
|
|
|
|
if (response.data.error) throw response.data.error; // This endpoint returns HTTP 200 even on failure
|
|
|
|
dispatch({ type: CHANGE_PASSWORD_SUCCESS, response });
|
|
|
|
}).catch(error => {
|
|
|
|
dispatch({ type: CHANGE_PASSWORD_FAIL, error, skipAlert: true });
|
|
|
|
throw error;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-03-23 19:52:08 -07:00
|
|
|
export function authLoggedIn(token) {
|
2020-04-05 14:54:51 -07:00
|
|
|
return {
|
|
|
|
type: AUTH_LOGGED_IN,
|
2021-03-23 19:52:08 -07:00
|
|
|
token,
|
2020-04-05 14:54:51 -07:00
|
|
|
};
|
|
|
|
}
|