2022-02-07 14:44:48 +05:00
|
|
|
import React, { useEffect, useRef, useState } from 'react';
|
|
|
|
|
import { Modal, View } from 'react-native';
|
2022-02-28 23:25:18 +05:00
|
|
|
import { useThemeStore } from '../../stores/theme';
|
|
|
|
|
import { useUserStore } from '../../stores/stores';
|
|
|
|
|
import BiometricService from '../../services/biometrics';
|
2022-02-07 14:44:48 +05:00
|
|
|
import {
|
|
|
|
|
eSendEvent,
|
|
|
|
|
eSubscribeEvent,
|
|
|
|
|
eUnSubscribeEvent,
|
|
|
|
|
presentSheet,
|
|
|
|
|
ToastEvent
|
2022-02-28 23:25:18 +05:00
|
|
|
} from '../../services/event-manager';
|
|
|
|
|
import { clearMessage } from '../../services/message';
|
|
|
|
|
import PremiumService from '../../services/premium';
|
|
|
|
|
import Sync from '../../services/sync';
|
2022-02-07 14:44:48 +05:00
|
|
|
import { db } from '../../utils/database';
|
2022-02-28 13:48:59 +05:00
|
|
|
import { MMKV } from '../../utils/database/mmkv';
|
|
|
|
|
import { SIZE } from '../../utils/size';
|
|
|
|
|
import { sleep } from '../../utils/time';
|
|
|
|
|
import { IconButton } from '../ui/icon-button';
|
|
|
|
|
import { Button } from '../ui/button';
|
|
|
|
|
import { Dialog } from '../dialog';
|
|
|
|
|
import { presentDialog } from '../dialog/functions';
|
|
|
|
|
import Input from '../ui/input';
|
|
|
|
|
import { Toast } from '../toast';
|
|
|
|
|
import Heading from '../ui/typography/heading';
|
|
|
|
|
import Paragraph from '../ui/typography/paragraph';
|
2022-03-03 15:09:30 +05:00
|
|
|
import SettingsService from '../../services/settings';
|
2022-03-18 14:40:15 +05:00
|
|
|
import TwoFactorVerification from './two-factor';
|
|
|
|
|
import SheetProvider from '../sheet-provider';
|
2022-02-07 14:44:48 +05:00
|
|
|
|
|
|
|
|
function getEmail(email) {
|
|
|
|
|
if (!email) return null;
|
|
|
|
|
return email.replace(/(.{2})(.*)(?=@)/, function (gp1, gp2, gp3) {
|
|
|
|
|
for (let i = 0; i < gp3.length; i++) {
|
|
|
|
|
gp2 += '*';
|
|
|
|
|
}
|
|
|
|
|
return gp2;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const SessionExpired = () => {
|
2022-02-28 23:25:18 +05:00
|
|
|
const colors = useThemeStore(state => state.colors);
|
2022-02-07 14:44:48 +05:00
|
|
|
const email = useRef();
|
|
|
|
|
const emailInputRef = useRef();
|
|
|
|
|
const passwordInputRef = useRef();
|
|
|
|
|
const password = useRef();
|
|
|
|
|
const [visible, setVisible] = useState(false);
|
|
|
|
|
const [focused, setFocused] = useState(false);
|
|
|
|
|
|
|
|
|
|
const setUser = useUserStore(state => state.setUser);
|
|
|
|
|
|
|
|
|
|
const [error, setError] = useState(false);
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
|
|
|
|
const logout = async () => {
|
|
|
|
|
try {
|
|
|
|
|
await db.user.logout();
|
|
|
|
|
await BiometricService.resetCredentials();
|
2022-03-03 15:09:30 +05:00
|
|
|
await SettingsService.set({
|
|
|
|
|
introCompleted: true
|
|
|
|
|
});
|
2022-02-07 14:44:48 +05:00
|
|
|
setVisible(false);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
ToastEvent.show({
|
|
|
|
|
heading: e.message,
|
|
|
|
|
type: 'error',
|
|
|
|
|
context: 'local'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
eSubscribeEvent('session_expired', open);
|
|
|
|
|
return () => {
|
|
|
|
|
eUnSubscribeEvent('session_expired', open);
|
|
|
|
|
setFocused(false);
|
|
|
|
|
};
|
|
|
|
|
}, [visible]);
|
|
|
|
|
|
|
|
|
|
const open = async () => {
|
|
|
|
|
try {
|
|
|
|
|
console.log('REQUESTING NEW TOKEN');
|
|
|
|
|
let res = await db.user.tokenManager.getToken();
|
|
|
|
|
if (!res) throw new Error('no token found');
|
|
|
|
|
if (db.user.tokenManager._isTokenExpired(res)) throw new Error('token expired');
|
|
|
|
|
if (!(await Sync.run())) throw new Error('e');
|
2022-03-03 18:03:03 +05:00
|
|
|
await SettingsService.set({
|
|
|
|
|
sessionExpired: false
|
|
|
|
|
});
|
2022-02-07 14:44:48 +05:00
|
|
|
setVisible(false);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log(e);
|
|
|
|
|
let user = await db.user.getUser();
|
|
|
|
|
if (!user) return;
|
|
|
|
|
email.current = user.email;
|
|
|
|
|
setVisible(true);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-03-18 14:40:15 +05:00
|
|
|
const login = async (mfa, callback) => {
|
2022-02-07 14:44:48 +05:00
|
|
|
if (error) return;
|
|
|
|
|
setLoading(true);
|
|
|
|
|
let user;
|
|
|
|
|
try {
|
2022-03-18 14:40:15 +05:00
|
|
|
if (mfa) {
|
|
|
|
|
await db.user.mfaLogin(email.current.toLowerCase(), password.current, mfa);
|
|
|
|
|
} else {
|
|
|
|
|
await db.user.login(email.current.toLowerCase(), password.current);
|
|
|
|
|
}
|
|
|
|
|
callback && callback(true);
|
2022-02-07 14:44:48 +05:00
|
|
|
user = await db.user.getUser();
|
|
|
|
|
if (!user) throw new Error('Email or password incorrect!');
|
|
|
|
|
PremiumService.setPremiumStatus();
|
|
|
|
|
setUser(user);
|
|
|
|
|
clearMessage();
|
|
|
|
|
ToastEvent.show({
|
|
|
|
|
heading: 'Login successful',
|
|
|
|
|
message: `Logged in as ${user.email}`,
|
|
|
|
|
type: 'success',
|
|
|
|
|
context: 'global'
|
|
|
|
|
});
|
2022-03-03 18:03:03 +05:00
|
|
|
await SettingsService.set({
|
2022-03-03 22:31:23 +05:00
|
|
|
sessionExpired: false,
|
|
|
|
|
userEmailConfirmed: user.isEmailConfirmed
|
2022-03-03 18:03:03 +05:00
|
|
|
});
|
2022-02-07 14:44:48 +05:00
|
|
|
eSendEvent('userLoggedIn', true);
|
|
|
|
|
await sleep(500);
|
|
|
|
|
presentSheet({
|
|
|
|
|
title: 'Syncing your data',
|
|
|
|
|
paragraph: 'Please wait while we sync all your data.',
|
|
|
|
|
progress: true
|
|
|
|
|
});
|
2022-03-23 17:49:01 +05:00
|
|
|
setLoading(false);
|
2022-02-07 14:44:48 +05:00
|
|
|
} catch (e) {
|
2022-03-23 17:49:01 +05:00
|
|
|
callback && callback(false);
|
|
|
|
|
if (e.message === 'Multifactor authentication required.') {
|
2022-03-18 14:40:15 +05:00
|
|
|
TwoFactorVerification.present(async mfa => {
|
|
|
|
|
if (mfa) {
|
2022-03-23 17:49:01 +05:00
|
|
|
console.log(mfa);
|
2022-03-18 14:40:15 +05:00
|
|
|
await login(mfa);
|
2022-03-23 17:49:01 +05:00
|
|
|
} else {
|
|
|
|
|
setLoading(false);
|
2022-03-18 14:40:15 +05:00
|
|
|
}
|
|
|
|
|
}, e.data);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(e.stack);
|
|
|
|
|
setLoading(false);
|
|
|
|
|
ToastEvent.show({
|
|
|
|
|
heading: user ? 'Failed to sync' : 'Login failed',
|
|
|
|
|
message: e.message,
|
|
|
|
|
type: 'error',
|
|
|
|
|
context: 'local'
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-02-07 14:44:48 +05:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return (
|
|
|
|
|
visible && (
|
|
|
|
|
<Modal
|
|
|
|
|
onShow={async () => {
|
|
|
|
|
await sleep(300);
|
|
|
|
|
passwordInputRef.current?.focus();
|
|
|
|
|
setFocused(true);
|
|
|
|
|
}}
|
|
|
|
|
visible={true}
|
|
|
|
|
>
|
2022-03-18 14:40:15 +05:00
|
|
|
<SheetProvider context="two_factor_verify" />
|
2022-02-07 14:44:48 +05:00
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
width: focused ? '100%' : '99.9%',
|
|
|
|
|
padding: 12,
|
|
|
|
|
justifyContent: 'center',
|
|
|
|
|
flex: 1
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<View
|
|
|
|
|
style={{
|
|
|
|
|
justifyContent: 'center',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
width: '100%',
|
|
|
|
|
marginBottom: 20,
|
|
|
|
|
borderRadius: 10,
|
|
|
|
|
paddingVertical: 20
|
|
|
|
|
}}
|
|
|
|
|
>
|
2022-02-28 13:48:59 +05:00
|
|
|
<IconButton
|
2022-02-07 14:44:48 +05:00
|
|
|
customStyle={{
|
|
|
|
|
width: 60,
|
|
|
|
|
height: 60
|
|
|
|
|
}}
|
|
|
|
|
name="alert"
|
|
|
|
|
color={colors.errorText}
|
|
|
|
|
size={50}
|
|
|
|
|
/>
|
|
|
|
|
<Heading size={SIZE.xxxl} color={colors.heading}>
|
|
|
|
|
Session expired
|
|
|
|
|
</Heading>
|
|
|
|
|
<Paragraph
|
|
|
|
|
style={{
|
|
|
|
|
textAlign: 'center'
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Your session on this device has expired. Please enter password for{' '}
|
|
|
|
|
{getEmail(email.current)} to continue.
|
|
|
|
|
</Paragraph>
|
|
|
|
|
</View>
|
|
|
|
|
|
|
|
|
|
<Input
|
|
|
|
|
fwdRef={passwordInputRef}
|
|
|
|
|
onChangeText={value => {
|
|
|
|
|
password.current = value;
|
|
|
|
|
}}
|
|
|
|
|
returnKeyLabel="Next"
|
|
|
|
|
returnKeyType="next"
|
|
|
|
|
secureTextEntry
|
2022-02-28 13:48:59 +05:00
|
|
|
autoComplete="password"
|
2022-02-07 14:44:48 +05:00
|
|
|
autoCapitalize="none"
|
|
|
|
|
autoCorrect={false}
|
|
|
|
|
placeholder="Password"
|
|
|
|
|
onSubmit={login}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
style={{
|
|
|
|
|
marginTop: 10,
|
|
|
|
|
width: '100%'
|
|
|
|
|
}}
|
|
|
|
|
loading={loading}
|
|
|
|
|
onPress={login}
|
|
|
|
|
type="accent"
|
|
|
|
|
title={loading ? null : 'Login'}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
style={{
|
|
|
|
|
marginTop: 10,
|
|
|
|
|
width: '100%'
|
|
|
|
|
}}
|
|
|
|
|
onPress={() => {
|
|
|
|
|
presentDialog({
|
|
|
|
|
context: 'session_expiry',
|
|
|
|
|
title: 'Logout',
|
|
|
|
|
paragraph:
|
|
|
|
|
'Are you sure you want to logout from this device? Any unsynced changes will be lost.',
|
|
|
|
|
positiveText: 'Logout',
|
|
|
|
|
positiveType: 'errorShade',
|
|
|
|
|
positivePress: logout
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
type="errorShade"
|
|
|
|
|
title={loading ? null : 'Logout from this device'}
|
|
|
|
|
/>
|
|
|
|
|
</View>
|
|
|
|
|
<Toast context="local" />
|
|
|
|
|
<Dialog context="session_expiry" />
|
|
|
|
|
</Modal>
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
};
|