Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/containers/TwoFactor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const TwoFactor = React.memo(() => {

const sendEmail = async () => {
try {
console.log('params', params);
if (params?.user) {
clearErrors();
const response = await sendEmailCode(params?.user);
Expand Down
13 changes: 13 additions & 0 deletions app/definitions/IUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,16 @@ export type IUserDataEvent = {
);

export type TUserModel = IUser & Model;

export interface IUserTwoFactorDisable {
success: boolean;
error: string;
errorType: 'totp-required' | 'totp-invalid';
details: {
method: string;
emailOrUsername: string;
codeGenerated: boolean;
codeExpires: string;
availableMethods: string[];
};
}
4 changes: 3 additions & 1 deletion app/definitions/rest/v1/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { PushEndpoints } from './push';
import { DirectoryEndpoint } from './directory';
import { AutoTranslateEndpoints } from './autotranslate';
import { ModerationEndpoints } from './moderation';
import { MeEndpoints } from './me';

export type Endpoints = ChannelsEndpoints &
ChatEndpoints &
Expand All @@ -44,4 +45,5 @@ export type Endpoints = ChannelsEndpoints &
PushEndpoints &
DirectoryEndpoint &
AutoTranslateEndpoints &
ModerationEndpoints;
ModerationEndpoints &
MeEndpoints;
7 changes: 7 additions & 0 deletions app/definitions/rest/v1/me.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { IUser } from '../../IUser';

export type MeEndpoints = {
me: {
GET: () => IUser;
};
};
5 changes: 4 additions & 1 deletion app/definitions/rest/v1/users.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IProfileParams } from '../../IProfile';
import type { ITeam } from '../../ITeam';
import type { IUser } from '../../IUser';
import { INotificationPreferences, IUserPreferences, IUserRegistered } from '../../IUser';
import { INotificationPreferences, IUserPreferences, IUserRegistered, IUserTwoFactorDisable } from '../../IUser';

export type UsersEndpoints = {
'users.2fa.sendEmailCode': {
Expand Down Expand Up @@ -64,4 +64,7 @@ export type UsersEndpoints = {
'users.deleteOwnAccount': {
POST: (params: { password: string; confirmRelinquish: boolean }) => { success: boolean };
};
'users.2fa.disableEmail': {
POST: (params: { emailOrUsername: string }) => IUserTwoFactorDisable;
};
};
11 changes: 11 additions & 0 deletions app/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
"Chat_started": "Chat started",
"Chats": "Chats",
"Check_again": "Check again",
"Check_auth_app_for_code": "Check your authenticator app and type in the 6-digit code",
"Check_canned_responses": "Check on canned responses.",
"Checked": "Checked",
"Choose": "Choose",
Expand Down Expand Up @@ -240,6 +241,8 @@
"Disable": "Disable",
"Disable_encryption_description": "Disabling E2EE compromises privacy. You can re-enable it later if needed. Proceed with caution.",
"Disable_encryption_title": "Disable encryption",
"Disable_totp_authenticator_app": "Disable TOTP Authenticator App",
"Disable_two_factor_auth_via_email": "Disable email TOTP authentication",
"Disable_writing_in_room": "Disable writing in room",
"Disabled": "Disabled",
"Disabled_E2E_Encryption_for_this_room": "disabled E2E encryption for this room",
Expand Down Expand Up @@ -297,6 +300,8 @@
"Enable_encryption_description": "Ensure conversations are kept private",
"Enable_encryption_title": "Enable encryption",
"Enable_Message_Parser": "Enable message parser",
"Enable_totp_authenticator_app": "Enable TOTP Authenticator App",
"Enable_two_factor_auth_via_email": "Enable email TOTP authentication",
"Enable_writing_in_room": "Enable writing in room",
"Enabled": "Enabled",
"Enabled_E2E_Encryption_for_this_room": "enabled E2E encryption for this room",
Expand All @@ -312,6 +317,7 @@
"Encryption_keys_reset": "Encryption keys reset",
"Encryption_keys_reset_failed": "Encryption keys reset failed",
"End_to_end_encrypted_room": "End to end encrypted room",
"Enter_6_digit_code": "Enter 6 digit code",
"Enter_E2EE_Password": "Enter E2EE password",
"Enter_E2EE_Password_description": "To access your encrypted channels and direct messages, enter your encryption password. This is not stored on the server, so you’ll need to use it on every device.",
"Enter_the_code": "Enter the code we just emailed you.",
Expand Down Expand Up @@ -744,6 +750,7 @@
"saving_preferences": "saving preferences",
"saving_profile": "saving profile",
"saving_settings": "saving settings",
"Scan_TOTP_QR_code": "Scan this QR code in Authy, Google Authenticator, or any TOTP app.",
"Screen_lock": "Screen lock",
"Search": "Search",
"Search_by": "Search by",
Expand Down Expand Up @@ -863,6 +870,10 @@
"Token_expired": "Your session has expired. Please log in again.",
"Topic": "Topic",
"topic": "topic",
"TOTP_email_not_verified": "You need to verify your emails before setting up 2FA",
"TOTP_enter_Code": "Enter code",
"TOTP_Open_Authentication_App": "Open authentication app",
"TOTP_Setup_Title": "Two-factor authentication",
"totp-invalid": "Code or password invalid",
"Translate": "Translate",
"Travel_and_places": "Travel and places",
Expand Down
11 changes: 11 additions & 0 deletions app/lib/services/restApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1105,3 +1105,14 @@ export const getUsersRoles = async (): Promise<boolean | IRoleUser[]> => {

export const getSupportedVersionsCloud = (uniqueId?: string, domain?: string) =>
fetch(`https://releases.rocket.chat/v2/server/supportedVersions?uniqueId=${uniqueId}&domain=${domain}&source=mobile`);

export const getMe = () => sdk.get('me');

export const requestUserTotp = (userid: string) =>
sdk.methodCall('2fa:enable', { msg: 'method', id: userid, method: '2fa:enable', params: [] });

export const verifyUserTotp = (code: string) => sdk.methodCall('2fa:validateTempToken', [code]);

export const enableEmail2fa = () => sdk.post('users.2fa.enableEmail');

export const disableEmail2fa = () => sdk.post('users.2fa.disableEmail');
1 change: 1 addition & 0 deletions app/lib/services/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class Sdk {
}
return resolve(result);
} catch (e: any) {
console.log('e', e);
const errorType = isMethodCall ? e?.error : e?.data?.errorType;
const totpInvalid = 'totp-invalid';
const totpRequired = 'totp-required';
Expand Down
4 changes: 4 additions & 0 deletions app/stacks/InsideStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ import {
import { isIOS } from '../lib/methods/helpers';
import { TNavigation } from './stackType';
import AccessibilityAndAppearanceView from '../views/AccessibilityAndAppearanceView';
import TotpView from '../views/TwoFactorAuthenticationView';
import TotpVerifyView from '../views/TwoFactorAuthenticationView/VerifyView';

// ChatsStackNavigator
const ChatsStack = createNativeStackNavigator<ChatsStackParamList & TNavigation>();
Expand Down Expand Up @@ -196,6 +198,8 @@ const SettingsStackNavigator = () => {
component={ScreenLockConfigView}
options={ScreenLockConfigView.navigationOptions}
/>
<SettingsStack.Screen name='TotpView' component={TotpView} />
<SettingsStack.Screen name='TotpVerifyView' component={TotpVerifyView} />
</SettingsStack.Navigator>
);
};
Expand Down
2 changes: 2 additions & 0 deletions app/stacks/MasterDetailStack/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ export type ModalStackParamList = {
name: string;
};
AccessibilityAndAppearanceView: undefined;
TotpView: undefined;
TotpVerifyView: undefined;
};

export type MasterDetailInsideStackParamList = {
Expand Down
2 changes: 2 additions & 0 deletions app/stacks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ export type SettingsStackParamList = {
PushTroubleshootView: undefined;
GetHelpView: undefined;
AccessibilityAndAppearanceView: undefined;
TotpView: undefined;
TotpVerifyView: undefined;
};

export type AdminPanelStackParamList = {
Expand Down
69 changes: 68 additions & 1 deletion app/views/SecurityPrivacyView.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import React, { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';

import * as List from '../containers/List';
import SafeAreaView from '../containers/SafeAreaView';
Expand All @@ -19,6 +20,10 @@
toggleCrashErrorsReport
} from '../lib/methods/helpers/log';
import Switch from '../containers/Switch';
import { getUserSelector } from '../selectors/login';
import { disableEmail2fa, enableEmail2fa, getMe } from '../lib/services/restApi';
import { showToast } from '../lib/methods/helpers/showToast';
import { setUser } from '../actions/login';

interface ISecurityPrivacyViewProps {
navigation: NativeStackNavigationProp<SettingsStackParamList, 'SecurityPrivacyView'>;
Expand All @@ -28,8 +33,10 @@
const [crashReportState, setCrashReportState] = useState(getReportCrashErrorsValue());
const [analyticsEventsState, setAnalyticsEventsState] = useState(getReportAnalyticsEventsValue());
const [server] = useServer();
const dispatch = useDispatch();

const e2eEnabled = useAppSelector(state => state.settings.E2E_Enable);
const user = useAppSelector(state => getUserSelector(state));

useEffect(() => {
navigation.setOptions({
Expand All @@ -51,7 +58,35 @@
toggleAnalyticsEventsReport(value);
};

const navigateToScreen = (screen: 'E2EEncryptionSecurityView' | 'ScreenLockConfigView') => {
const toggleEmail2fa = async (value: boolean) => {
if (!value) {
try {
const res = await disableEmail2fa();
if (res.success) {
showToast('Email 2FA disabled successfully');

const updatedMe = await getMe();
dispatch(setUser(updatedMe));
}
} catch (error) {
console.log('error', error);
}
} else {
try {
const res = await enableEmail2fa();
if (res.success) {
showToast('Email 2FA enabled successfully');

const updatedMe = await getMe();
dispatch(setUser(updatedMe));
}
} catch (error) {
console.log('error', error);
}
}
};

const navigateToScreen = (screen: 'E2EEncryptionSecurityView' | 'ScreenLockConfigView' | 'TotpView') => {
// @ts-ignore
logEvent(events[`SP_GO_${screen.replace('View', '').toUpperCase()}`]);
navigation.navigate(screen);
Expand All @@ -64,6 +99,10 @@
navigateToScreen('ScreenLockConfigView');
};

const navigateToTotpView = async () => {

Check failure on line 102 in app/views/SecurityPrivacyView.tsx

View workflow job for this annotation

GitHub Actions / ESLint and Test / run-eslint-and-test

Async arrow function has no 'await' expression
navigateToScreen('TotpView');
};

return (
<SafeAreaView testID='security-privacy-view'>
<List.Container testID='security-privacy-view-list'>
Expand All @@ -89,6 +128,34 @@
<List.Separator />
</List.Section>

<List.Section>
<List.Separator />
<List.Item
title={user.services?.totp?.enabled ? 'Disable_totp_authenticator_app' : 'Enable_totp_authenticator_app'}
showActionIndicator
onPress={navigateToTotpView}
testID='security-privacy-view-screen-lock'
/>
<List.Separator />
{user.services?.totp?.enabled ? (
<>
<List.Item
title={'view_backup_codes'}
showActionIndicator
onPress={navigateToScreenLockConfigView}
testID='security-privacy-view-screen-lock'
/>
<List.Separator />
</>
) : null}
<List.Item
title={user.services?.email2fa?.enabled ? 'Disable_two_factor_auth_via_email' : 'Enable_two_factor_auth_via_email'}
testID='security-privacy-view-analytics-events'
right={() => <Switch value={user?.services?.email2fa?.enabled || false} onValueChange={toggleEmail2fa} />}
/>
<List.Separator />
</List.Section>

<List.Section>
<List.Separator />
<List.Item
Expand Down
Loading
Loading