Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / components / hooks / useSessionRecovery.ts
blobfc1299016a93f29ef5a5b2153accafcb3514c512
1 import { useEffect, useState } from 'react';
3 import { differenceInMilliseconds } from 'date-fns';
5 import { useAddresses } from '@proton/account/addresses/hooks';
6 import { useUser } from '@proton/account/user/hooks';
7 import { useUserSettings } from '@proton/account/userSettings/hooks';
8 import { useSessionRecoveryLocalStorage } from '@proton/components/containers/account/sessionRecovery/SessionRecoveryLocalStorageManager';
9 import { useInterval } from '@proton/hooks';
10 import { APPS, DAY, HOUR, MINUTE, SECOND } from '@proton/shared/lib/constants';
11 import { MNEMONIC_STATUS, SessionRecoveryState } from '@proton/shared/lib/interfaces';
12 import { getHasMigratedAddressKeys } from '@proton/shared/lib/keys';
13 import isTruthy from '@proton/utils/isTruthy';
15 import useAuthentication from './useAuthentication';
16 import useConfig from './useConfig';
18 export const useIsSessionRecoveryInitiatedByCurrentSession = () => {
19     const [user] = useUser();
20     const authentication = useAuthentication();
22     if (!user?.AccountRecovery) {
23         return null;
24     }
26     return user.AccountRecovery.UID === authentication.getUID();
29 export const useSessionRecoveryState = () => {
30     const [user] = useUser();
32     if (!user?.AccountRecovery) {
33         return SessionRecoveryState.NONE;
34     }
36     return user.AccountRecovery.State;
39 export const useIsSessionRecoveryEnabled = () => {
40     const [userSettings] = useUserSettings();
42     return !!userSettings?.SessionAccountRecovery;
45 export const useAvailableRecoveryMethods = () => {
46     const [user] = useUser();
47     const [userSettings, loadingUserSettings] = useUserSettings();
49     const recoveryPhrase = user.MnemonicStatus === MNEMONIC_STATUS.SET;
50     const recoveryEmail = !!userSettings?.Email.Reset && !!userSettings?.Email.Value;
51     const recoveryPhone = !!userSettings?.Phone.Reset && !!userSettings?.Phone.Value;
53     const availableRecoveryMethods = [
54         recoveryEmail && ('email' as const),
55         recoveryPhone && ('sms' as const),
56         recoveryPhrase && ('mnemonic' as const),
57     ].filter(isTruthy);
59     return [availableRecoveryMethods, loadingUserSettings] as const;
62 export const useIsSessionRecoveryAvailable = () => {
63     const [user] = useUser();
64     const [addresses = [], loadingAddresses] = useAddresses();
65     const { APP_NAME } = useConfig();
67     const hasMigratedKeys = getHasMigratedAddressKeys(addresses);
68     const isPrivateUser = user?.isPrivate;
70     return [
71         APP_NAME !== APPS.PROTONVPN_SETTINGS && !loadingAddresses && hasMigratedKeys && isPrivateUser,
72         loadingAddresses,
73     ];
76 export const useIsSessionRecoveryInitiationAvailable = () => {
77     const [isSessionRecoveryAvailable] = useIsSessionRecoveryAvailable();
78     const isSessionRecoveryEnabled = useIsSessionRecoveryEnabled();
79     const sessionRecoveryState = useSessionRecoveryState();
81     const sessionRecoveryInitiated =
82         sessionRecoveryState === SessionRecoveryState.GRACE_PERIOD ||
83         sessionRecoveryState === SessionRecoveryState.INSECURE;
85     return isSessionRecoveryAvailable && isSessionRecoveryEnabled && !sessionRecoveryInitiated;
88 /**
89  * Determines whether applications should display session recovery in progress "notifications".
90  * Notifications here means banners or modals and not the browser notifications.
91  */
92 export const useShouldNotifySessionRecoveryInProgress = () => {
93     const [isSessionRecoveryAvailable] = useIsSessionRecoveryAvailable();
94     const sessionRecoveryState = useSessionRecoveryState();
95     const isSessionRecoveryInitiatedByCurrentSession = useIsSessionRecoveryInitiatedByCurrentSession();
96     const { hasConfirmedSessionRecoveryInProgress } = useSessionRecoveryLocalStorage();
98     return (
99         isSessionRecoveryAvailable &&
100         sessionRecoveryState === SessionRecoveryState.GRACE_PERIOD &&
101         !hasConfirmedSessionRecoveryInProgress &&
102         !isSessionRecoveryInitiatedByCurrentSession
103     );
107  * Determines whether applications should display password reset available "notifications".
108  * Notifications here means banners or modals and not the browser notifications.
109  */
110 export const useShouldNotifyPasswordResetAvailable = () => {
111     const [isSessionRecoveryAvailable] = useIsSessionRecoveryAvailable();
112     const sessionRecoveryState = useSessionRecoveryState();
114     return isSessionRecoveryAvailable && sessionRecoveryState === SessionRecoveryState.INSECURE;
117 export const useSessionRecoveryGracePeriodHoursRemaining = () => {
118     const [user] = useUser();
120     if (!user.AccountRecovery || user.AccountRecovery.State !== SessionRecoveryState.GRACE_PERIOD) {
121         return null;
122     }
124     const msRemaining = user.AccountRecovery.EndTime * 1000 - Date.now();
126     return Math.ceil(msRemaining / HOUR);
129 export const useSessionRecoveryInsecureTimeRemaining = () => {
130     const [user] = useUser();
132     const [now, setNow] = useState(() => new Date());
133     const [interval, setInterval] = useState(HOUR);
135     const [timeRemaining, setTimeRemaining] = useState<{
136         inHours: number;
137         inDays: number;
138         inMinutes: number;
139         inSeconds: number;
140     }>();
142     const diff = user?.AccountRecovery?.EndTime
143         ? differenceInMilliseconds(user.AccountRecovery.EndTime * 1000, now)
144         : 0;
146     useInterval(
147         () => {
148             setNow(new Date());
149         },
150         diff < 0 ? null : interval
151     );
153     useEffect(() => {
154         const inDays = Math.floor(diff / DAY);
155         const inHours = Math.floor(diff / HOUR);
156         const inMinutes = Math.floor(diff / MINUTE);
157         const inSeconds = Math.floor(diff / SECOND);
159         if (inMinutes <= 1) {
160             setInterval(SECOND);
161         } else if (inHours <= 1) {
162             setInterval(MINUTE);
163         } else {
164             setInterval(HOUR);
165         }
167         setTimeRemaining({
168             inHours,
169             inDays,
170             inMinutes,
171             inSeconds,
172         });
173     }, [diff]);
175     if (!user.AccountRecovery || user.AccountRecovery.State !== SessionRecoveryState.INSECURE) {
176         return null;
177     }
179     if (diff <= 0 || !timeRemaining) {
180         return null;
181     }
183     return timeRemaining;
186 export const useShouldNotifySessionRecoveryCancelled = () => {
187     const [isSessionRecoveryAvailable] = useIsSessionRecoveryAvailable();
188     const sessionRecoveryState = useSessionRecoveryState();
189     const { hasDismissedSessionRecoveryCancelled } = useSessionRecoveryLocalStorage();
191     return (
192         isSessionRecoveryAvailable &&
193         sessionRecoveryState === SessionRecoveryState.CANCELLED &&
194         !hasDismissedSessionRecoveryCancelled
195     );