2025-06-04 20:36:48 +02:00

139 lines
4.2 KiB
TypeScript

import type { ActionReturnType } from '../../types';
import { SettingsScreens } from '../../../types';
import { IS_SCREEN_LOCKED_CACHE_KEY } from '../../../config';
import { getCurrentTabId, signalPasscodeHash } from '../../../util/establishMultitabRole';
import { cloneDeep } from '../../../util/iteratees';
import {
clearEncryptedSession, encryptSession, forgetPasscode, setupPasscode,
} from '../../../util/passcode';
import { onBeforeUnload } from '../../../util/schedulers';
import { clearStoredSession, loadStoredSession, storeSession } from '../../../util/sessions';
import { forceUpdateCache, migrateCache, serializeGlobal } from '../../cache';
import { addActionHandler, getGlobal, setGlobal } from '../../index';
import { INITIAL_GLOBAL_STATE } from '../../initialState';
import { clearPasscodeSettings, updatePasscodeSettings } from '../../reducers';
let noLockOnUnload = false;
onBeforeUnload(() => {
const global = getGlobal();
if (!global.isInited) return;
if (global.passcode.hasPasscode && !noLockOnUnload && Object.keys(global.byTabId).length === 1) {
clearStoredSession();
}
});
addActionHandler('setPasscode', async (global, actions, payload): Promise<void> => {
const { passcode, tabId = getCurrentTabId() } = payload;
global = updatePasscodeSettings(global, {
isLoading: true,
});
setGlobal(global);
await setupPasscode(passcode);
const sessionJson = JSON.stringify({ ...loadStoredSession(), userId: global.currentUserId });
global = getGlobal();
const globalJson = serializeGlobal(updatePasscodeSettings(global, {
hasPasscode: true,
error: undefined,
isLoading: false,
}));
try {
await encryptSession(sessionJson, globalJson);
signalPasscodeHash();
global = getGlobal();
global = updatePasscodeSettings(global, {
hasPasscode: true,
error: undefined,
isLoading: false,
});
setGlobal(global);
forceUpdateCache(true);
} catch (err: any) {
forgetPasscode();
global = getGlobal();
global = updatePasscodeSettings(global, {
isLoading: false,
});
setGlobal(global);
actions.showNotification({
message: 'Failed to set passcode',
tabId,
});
actions.openSettingsScreen({ screen: SettingsScreens.PasscodeDisabled, tabId });
}
});
addActionHandler('clearPasscode', (global): ActionReturnType => {
void clearEncryptedSession();
localStorage.removeItem(IS_SCREEN_LOCKED_CACHE_KEY);
return clearPasscodeSettings(global);
});
addActionHandler('unlockScreen', (global, actions, payload): ActionReturnType => {
const beforeTabStates = Object.values(global.byTabId);
const { sessionJson, globalJson } = payload;
const session = JSON.parse(sessionJson);
storeSession(session);
const previousGlobal = global;
global = JSON.parse(globalJson);
global.byTabId = previousGlobal.byTabId;
migrateCache(global, cloneDeep(INITIAL_GLOBAL_STATE));
global = updatePasscodeSettings(
global,
{
isScreenLocked: false,
error: undefined,
invalidAttemptsCount: 0,
},
);
setGlobal(global);
signalPasscodeHash();
beforeTabStates.forEach(({ id: tabId, isMasterTab }) => actions.init({ tabId, isMasterTab }));
actions.initApi();
});
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,
timeoutUntil: (invalidAttemptsCount >= MAX_INVALID_ATTEMPTS
? Date.now() + TIMEOUT_RESET_INVALID_ATTEMPTS_MS : undefined),
});
});
addActionHandler('resetInvalidUnlockAttempts', (global): ActionReturnType => {
return updatePasscodeSettings(global, {
invalidAttemptsCount: 0,
timeoutUntil: undefined,
});
});
addActionHandler('setPasscodeError', (global, actions, payload): ActionReturnType => {
const { error } = payload;
return updatePasscodeSettings(global, { error });
});
addActionHandler('clearPasscodeError', (global): ActionReturnType => {
return updatePasscodeSettings(global, { error: undefined });
});
addActionHandler('skipLockOnUnload', (): ActionReturnType => {
noLockOnUnload = true;
});