Passcode: Save last passcode timeout (#2876)
This commit is contained in:
parent
7845ed4e1e
commit
e3dd98882b
@ -30,8 +30,6 @@ type StateProps = {
|
||||
passcodeSettings: GlobalState['passcode'];
|
||||
};
|
||||
|
||||
const MAX_INVALID_ATTEMPTS = 5;
|
||||
const TIMEOUT_RESET_INVALID_ATTEMPTS_MS = 180000; // 3 minutes
|
||||
const ICON_SIZE = 160;
|
||||
|
||||
const LockScreen: FC<OwnProps & StateProps> = ({
|
||||
@ -47,6 +45,7 @@ const LockScreen: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const {
|
||||
invalidAttemptsCount,
|
||||
timeoutUntil,
|
||||
isLoading,
|
||||
} = passcodeSettings;
|
||||
|
||||
@ -56,19 +55,14 @@ const LockScreen: FC<OwnProps & StateProps> = ({
|
||||
const [isSignOutDialogOpen, openSignOutConfirmation, closeSignOutConfirmation] = useFlag(false);
|
||||
const { shouldRender } = useShowTransition(isLocked);
|
||||
|
||||
useTimeout(
|
||||
resetInvalidUnlockAttempts,
|
||||
invalidAttemptsCount && invalidAttemptsCount >= MAX_INVALID_ATTEMPTS
|
||||
? TIMEOUT_RESET_INVALID_ATTEMPTS_MS
|
||||
: undefined,
|
||||
);
|
||||
useTimeout(resetInvalidUnlockAttempts, timeoutUntil ? timeoutUntil - Date.now() : undefined);
|
||||
|
||||
const handleClearError = useCallback(() => {
|
||||
setValidationError('');
|
||||
}, []);
|
||||
|
||||
const handleSubmit = useCallback((passcode: string) => {
|
||||
if (invalidAttemptsCount && invalidAttemptsCount >= MAX_INVALID_ATTEMPTS) {
|
||||
if (timeoutUntil !== undefined) {
|
||||
setValidationError(lang('FloodWait'));
|
||||
return;
|
||||
}
|
||||
@ -78,15 +72,15 @@ const LockScreen: FC<OwnProps & StateProps> = ({
|
||||
logInvalidUnlockAttempt();
|
||||
setValidationError(lang('lng_passcode_wrong'));
|
||||
});
|
||||
}, [invalidAttemptsCount, lang, logInvalidUnlockAttempt, unlockScreen]);
|
||||
}, [lang, timeoutUntil]);
|
||||
|
||||
useEffect(() => {
|
||||
if (invalidAttemptsCount && invalidAttemptsCount >= MAX_INVALID_ATTEMPTS) {
|
||||
if (timeoutUntil !== undefined) {
|
||||
setValidationError(lang('FloodWait'));
|
||||
} else if (invalidAttemptsCount === 0) {
|
||||
setValidationError('');
|
||||
}
|
||||
}, [invalidAttemptsCount, lang]);
|
||||
}, [timeoutUntil, lang, invalidAttemptsCount]);
|
||||
|
||||
const handleSignOutMessage = useCallback(() => {
|
||||
closeSignOutConfirmation();
|
||||
|
||||
@ -252,6 +252,7 @@ addActionHandler('lockScreen', async (global): Promise<void> => {
|
||||
{
|
||||
isScreenLocked: true,
|
||||
invalidAttemptsCount: 0,
|
||||
timeoutUntil: undefined,
|
||||
},
|
||||
);
|
||||
setGlobal(global);
|
||||
|
||||
@ -90,15 +90,23 @@ addActionHandler('decryptSession', (global, actions, payload): ActionReturnType
|
||||
});
|
||||
});
|
||||
|
||||
const MAX_INVALID_ATTEMPTS = 5;
|
||||
const TIMEOUT_RESET_INVALID_ATTEMPTS_MS = 1000 * 15;// 180000; // 3 minutes
|
||||
|
||||
addActionHandler('logInvalidUnlockAttempt', (global): ActionReturnType => {
|
||||
const invalidAttemptsCount = (global.passcode?.invalidAttemptsCount ?? 0) + 1;
|
||||
|
||||
return updatePasscodeSettings(global, {
|
||||
invalidAttemptsCount: (global.passcode?.invalidAttemptsCount ?? 0) + 1,
|
||||
invalidAttemptsCount,
|
||||
timeoutUntil: (invalidAttemptsCount >= MAX_INVALID_ATTEMPTS
|
||||
? Date.now() + TIMEOUT_RESET_INVALID_ATTEMPTS_MS : undefined),
|
||||
});
|
||||
});
|
||||
|
||||
addActionHandler('resetInvalidUnlockAttempts', (global): ActionReturnType => {
|
||||
return updatePasscodeSettings(global, {
|
||||
invalidAttemptsCount: 0,
|
||||
timeoutUntil: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -357,6 +357,7 @@ export function serializeGlobal<T extends GlobalState>(global: T) {
|
||||
'isScreenLocked',
|
||||
'hasPasscode',
|
||||
'invalidAttemptsCount',
|
||||
'timeoutUntil',
|
||||
]),
|
||||
};
|
||||
|
||||
|
||||
@ -592,6 +592,7 @@ export type GlobalState = {
|
||||
isScreenLocked?: boolean;
|
||||
hasPasscode?: boolean;
|
||||
error?: string;
|
||||
timeoutUntil?: number;
|
||||
invalidAttemptsCount?: number;
|
||||
invalidAttemptError?: string;
|
||||
isLoading?: boolean;
|
||||
|
||||
@ -20,6 +20,8 @@ export async function setupPasscode(passcode: string) {
|
||||
|
||||
export async function encryptSession(sessionJson?: string, globalJson?: string) {
|
||||
if (!currentPasscodeHash) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('[api/passcode] Missing current passcode');
|
||||
throw new Error('[api/passcode] Missing current passcode');
|
||||
}
|
||||
|
||||
@ -41,6 +43,8 @@ export async function encryptSession(sessionJson?: string, globalJson?: string)
|
||||
|
||||
export async function decryptSessionByCurrentHash() {
|
||||
if (!currentPasscodeHash) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('[api/passcode] Missing current passcode');
|
||||
throw new Error('[api/passcode] Missing current passcode');
|
||||
}
|
||||
|
||||
@ -50,6 +54,8 @@ export async function decryptSessionByCurrentHash() {
|
||||
]);
|
||||
|
||||
if (!sessionEncrypted || !globalEncrypted) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('[api/passcode] Missing required stored fields');
|
||||
throw new Error('[api/passcode] Missing required stored fields');
|
||||
}
|
||||
|
||||
@ -70,6 +76,8 @@ export async function decryptSession(passcode: string) {
|
||||
]);
|
||||
|
||||
if (!sessionEncrypted || !globalEncrypted) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('[api/passcode] Missing required stored fields');
|
||||
throw new Error('[api/passcode] Missing required stored fields');
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user