[FIX] Change password not working on some cases (#4312)

* create iTotp enum

* migrate change user profile to method

* Fix minor i18n issues

* Use saveUserProfileMethod from Services

* Catch cancel event from TwoFactor modal

Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
Gleidson Daniel Silva 2022-06-23 16:59:57 -03:00 committed by GitHub
parent bc09527d78
commit 303d127949
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 11 deletions

5
app/definitions/ITotp.ts Normal file
View File

@ -0,0 +1,5 @@
export enum TwoFactorMethods {
TOTP = 'totp',
EMAIL = 'email',
PASSWORD = 'password'
}

View File

@ -71,6 +71,7 @@
"error-remove-last-owner": "This is the last owner. Please set a new owner before removing this one.",
"error-role-in-use": "Cannot delete role because it's in use",
"error-role-name-required": "Role name is required",
"error-password-same-as-current": "Entered password same as current password",
"error-the-field-is-required": "The field {{field}} is required.",
"error-too-many-requests": "Error, too many requests. Please slow down. You must wait {{seconds}} seconds before trying again.",
"error-user-is-not-activated": "User is not activated",
@ -836,5 +837,6 @@
"Mark_as_unread": "Mark as unread",
"Mark_as_unread_Info": "Display room as unread when there are unread messages",
"Show_badge_for_mentions": "Show badge for mentions",
"Show_badge_for_mentions_Info": "Display badge for direct mentions only"
"Show_badge_for_mentions_Info": "Display badge for direct mentions only",
"totp-invalid": "Code or password invalid"
}

View File

@ -69,6 +69,7 @@
"error-remove-last-owner": "Este é o último proprietário. Por favor, defina um novo proprietário antes de remover este.",
"error-role-in-use": "Não é possível remover o papel pois ele está em uso",
"error-role-name-required": "Nome do papel é obrigatório",
"error-password-same-as-current": "Senha digitada coincide com a senha atual",
"error-the-field-is-required": "O campo {{field}} é obrigatório.",
"error-too-many-requests": "Erro, muitas solicitações. Por favor, diminua a velocidade. Você deve esperar {{seconds}} segundos antes de tentar novamente.",
"error-user-is-not-activated": "O usuário não está ativo",
@ -743,5 +744,6 @@
"sending_email_confirmation": "enviando email de confirmação",
"Unsupported_format": "Formato não suportado",
"Downloaded_file": "Arquivo baixado",
"Error_Download_file": "Erro ao baixar o arquivo"
"Error_Download_file": "Erro ao baixar o arquivo",
"totp-invalid": "Código ou senha inválida"
}

View File

@ -918,6 +918,15 @@ export function getUserInfo(userId: string) {
export const toggleFavorite = (roomId: string, favorite: boolean) => sdk.post('rooms.favorite', { roomId, favorite });
export const saveUserProfileMethod = (
params: IProfileParams,
customFields = {},
twoFactorOptions: {
twoFactorCode: string;
twoFactorMethod: string;
} | null
) => sdk.current.methodCall('saveUserProfile', params, customFields, twoFactorOptions);
export const deleteOwnAccount = (password: string, confirmRelinquish = false): any =>
// RC 0.67.0
sdk.post('users.deleteOwnAccount', { password, confirmRelinquish });

View File

@ -41,6 +41,8 @@ import {
IProfileParams,
IUser
} from '../../definitions';
import { twoFactor } from '../../lib/services/twoFactor';
import { TwoFactorMethods } from '../../definitions/ITotp';
import { withActionSheet, IActionSheetProvider } from '../../containers/ActionSheet';
import { DeleteAccountActionSheetContent } from './components/DeleteAccountActionSheetContent';
@ -71,6 +73,10 @@ interface IProfileViewState {
customFields: {
[key: string | number]: string;
};
twoFactorCode: null | {
twoFactorCode: string;
twoFactorMethod: string;
};
}
class ProfileView extends React.Component<IProfileViewProps, IProfileViewState> {
@ -113,7 +119,8 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
url: ''
},
avatarSuggestions: {},
customFields: {}
customFields: {},
twoFactorCode: null
};
async componentDidMount() {
@ -194,14 +201,17 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
);
};
handleError = (e: any, func: string, action: string) => {
handleError = (e: any, _func: string, action: string) => {
if (e.data && e.data.error.includes('[error-too-many-requests]')) {
return showErrorAlert(e.data.error);
}
if (I18n.isTranslated(e.error)) {
return showErrorAlert(I18n.t(e.error));
}
showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t(action) }));
};
submit = async () => {
submit = async (): Promise<void> => {
Keyboard.dismiss();
if (!this.formIsChanged()) {
@ -210,7 +220,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
this.setState({ saving: true });
const { name, username, email, newPassword, currentPassword, avatar, customFields } = this.state;
const { name, username, email, newPassword, currentPassword, avatar, customFields, twoFactorCode } = this.state;
const { user, dispatch } = this.props;
const params = {} as IProfileParams;
@ -275,9 +285,16 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
}
}
const result = await Services.saveUserProfile(params, customFields);
const twoFactorOptions = params.currentPassword
? {
twoFactorCode: params.currentPassword,
twoFactorMethod: TwoFactorMethods.PASSWORD
}
: null;
if (result.success) {
const result = await Services.saveUserProfileMethod(params, customFields, twoFactorCode || twoFactorOptions);
if (result) {
logEvent(events.PROFILE_SAVE_CHANGES);
if (customFields) {
dispatch(setUser({ customFields, ...params }));
@ -287,10 +304,18 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
EventEmitter.emit(LISTENER, { message: I18n.t('Profile_saved_successfully') });
this.init();
}
this.setState({ saving: false });
} catch (e) {
this.setState({ saving: false, currentPassword: null, twoFactorCode: null });
} catch (e: any) {
if (e?.error === 'totp-invalid' && e?.details.method !== TwoFactorMethods.PASSWORD) {
try {
const code = await twoFactor({ method: e?.details.method, invalid: e?.error === 'totp-invalid' && !!twoFactorCode });
return this.setState({ twoFactorCode: code }, () => this.submit());
} catch {
// cancelled twoFactor modal
}
}
logEvent(events.PROFILE_SAVE_CHANGES_F);
this.setState({ saving: false, currentPassword: null });
this.setState({ saving: false, currentPassword: null, twoFactorCode: null });
this.handleError(e, 'saveUserProfile', 'saving_profile');
}
};