Passcode: Display error if passcode wasn't created (#3149)

This commit is contained in:
Alexander Zinchuk 2023-05-03 20:21:25 +04:00
parent c8d64dc929
commit cc0e00ad2d
8 changed files with 70 additions and 27 deletions

View File

@ -31,6 +31,7 @@ import { formatDateToString } from '../../../util/dateFormat';
import { setPermanentWebVersion } from '../../../util/permanentWebVersion';
import { clearWebsync } from '../../../util/websync';
import {
selectCanSetPasscode,
selectCurrentMessageList, selectIsCurrentUserPremium, selectTabState, selectTheme,
} from '../../../global/selectors';
import useLang from '../../../hooks/useLang';
@ -82,7 +83,7 @@ type StateProps =
isConnectionStatusMinimized: ISettings['isConnectionStatusMinimized'];
areChatsLoaded?: boolean;
hasPasscode?: boolean;
isAuthRememberMe?: boolean;
canSetPasscode?: boolean;
}
& Pick<GlobalState, 'connectionState' | 'isSyncing' | 'archiveSettings'>
& Pick<TabState, 'canInstall'>;
@ -114,7 +115,7 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
isConnectionStatusMinimized,
areChatsLoaded,
hasPasscode,
isAuthRememberMe,
canSetPasscode,
canInstall,
archiveSettings,
}) => {
@ -158,7 +159,7 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
}
}, [hasPasscode]);
useHotkeys(isAuthRememberMe ? {
useHotkeys(canSetPasscode ? {
'Ctrl+Shift+L': handleLockScreenHotkey,
'Alt+Shift+L': handleLockScreenHotkey,
'Meta+Shift+L': handleLockScreenHotkey,
@ -481,7 +482,7 @@ export default memo(withGlobal<OwnProps>(
hasPasscode: Boolean(global.passcode.hasPasscode),
canInstall: Boolean(tabState.canInstall),
archiveSettings,
isAuthRememberMe: global.authRememberMe,
canSetPasscode: selectCanSetPasscode(global),
};
},
)(LeftMainHeader));

View File

@ -5,7 +5,7 @@ import { getActions, withGlobal } from '../../../global';
import type { ApiPrivacySettings } from '../../../types';
import { SettingsScreens } from '../../../types';
import { selectIsCurrentUserPremium } from '../../../global/selectors';
import { selectCanSetPasscode, selectIsCurrentUserPremium } from '../../../global/selectors';
import useLang from '../../../hooks/useLang';
import useHistoryBack from '../../../hooks/useHistoryBack';
@ -23,7 +23,7 @@ type StateProps = {
isCurrentUserPremium?: boolean;
hasPassword?: boolean;
hasPasscode?: boolean;
isAuthRememberMe?: boolean;
canSetPasscode?: boolean;
blockedCount: number;
webAuthCount: number;
isSensitiveEnabled?: boolean;
@ -63,7 +63,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
privacyPhoneP2P,
onScreenSelect,
onReset,
isAuthRememberMe,
canSetPasscode,
}) => {
const {
loadPrivacySettings,
@ -160,7 +160,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
{lang('BlockedUsers')}
<span className="settings-item__current-value">{blockedCount || ''}</span>
</ListItem>
{isAuthRememberMe && (
{canSetPasscode && (
<ListItem
icon="key"
narrow
@ -394,7 +394,7 @@ export default memo(withGlobal<OwnProps>(
privacyPhoneCall: privacy.phoneCall,
privacyPhoneP2P: privacy.phoneP2P,
canDisplayChatInTitle,
isAuthRememberMe: global.authRememberMe,
canSetPasscode: selectCanSetPasscode(global),
};
},
)(SettingsPrivacy));

View File

@ -3,14 +3,15 @@ import { addActionHandler, setGlobal, getGlobal } from '../../index';
import { clearPasscodeSettings, updatePasscodeSettings } from '../../reducers';
import { clearStoredSession, loadStoredSession, storeSession } from '../../../util/sessions';
import {
clearEncryptedSession, decryptSession, encryptSession, setupPasscode,
clearEncryptedSession, decryptSession, encryptSession, forgetPasscode, setupPasscode,
} from '../../../util/passcode';
import { forceUpdateCache, migrateCache, serializeGlobal } from '../../cache';
import { onBeforeUnload } from '../../../util/schedulers';
import { cloneDeep } from '../../../util/iteratees';
import { INITIAL_GLOBAL_STATE } from '../../initialState';
import type { ActionReturnType } from '../../types';
import { signalPasscodeHash } from '../../../util/establishMultitabRole';
import { getCurrentTabId, signalPasscodeHash } from '../../../util/establishMultitabRole';
import { SettingsScreens } from '../../../types';
let noLockOnUnload = false;
onBeforeUnload(() => {
@ -21,7 +22,7 @@ onBeforeUnload(() => {
});
addActionHandler('setPasscode', async (global, actions, payload): Promise<void> => {
const { passcode } = payload;
const { passcode, tabId = getCurrentTabId() } = payload;
global = updatePasscodeSettings(global, {
isLoading: true,
});
@ -36,18 +37,34 @@ addActionHandler('setPasscode', async (global, actions, payload): Promise<void>
isLoading: false,
}));
await encryptSession(sessionJson, globalJson);
try {
await encryptSession(sessionJson, globalJson);
signalPasscodeHash();
global = getGlobal();
global = updatePasscodeSettings(global, {
hasPasscode: true,
error: undefined,
isLoading: false,
});
setGlobal(global);
signalPasscodeHash();
global = getGlobal();
global = updatePasscodeSettings(global, {
hasPasscode: true,
error: undefined,
isLoading: false,
});
setGlobal(global);
forceUpdateCache(true);
forceUpdateCache(true);
} catch (err: any) {
forgetPasscode();
global = getGlobal();
global = updatePasscodeSettings(global, {
isLoading: false,
});
setGlobal(global);
actions.showNotification({
message: 'Failed to set passcode',
tabId,
});
actions.requestNextSettingsScreen({ screen: SettingsScreens.PasscodeDisabled, tabId });
}
});
addActionHandler('clearPasscode', (global): ActionReturnType => {

View File

@ -16,6 +16,7 @@ import { getCurrentTabId, reestablishMasterToSelf } from '../util/establishMulti
import { updateTabState } from './reducers/tabs';
import type { ActionReturnType, GlobalState } from './types';
import { isLocalMessageId } from './helpers';
import { isCacheApiSupported } from '../util/cacheApi';
initCache();
@ -129,6 +130,12 @@ addActionHandler('init', (global, actions, payload): ActionReturnType => {
actions.initApi();
}
isCacheApiSupported().then((isSupported) => {
global = getGlobal();
global.isCacheApiSupported = isSupported;
setGlobal(global);
});
return updateTabState(global, {
messageLists: parsedMessageList ? [parsedMessageList] : initialTabState.messageLists,
}, tabId);

View File

@ -11,3 +11,7 @@ export function selectNotifyExceptions<T extends GlobalState>(global: T) {
export function selectLanguageCode<T extends GlobalState>(global: T) {
return global.settings.byKey.language.replace('-raw', '');
}
export function selectCanSetPasscode<T extends GlobalState>(global: T) {
return global.authRememberMe && global.isCacheApiSupported;
}

View File

@ -579,6 +579,7 @@ export type GlobalState = {
appConfig?: ApiAppConfig;
hasWebAuthTokenFailed?: boolean;
hasWebAuthTokenPasswordRequired?: true;
isCacheApiSupported?: boolean;
connectionState?: ApiUpdateConnectionStateType;
currentUserId?: string;
isSyncing?: boolean;
@ -2334,7 +2335,7 @@ export interface ActionPayloads {
connectToActivePhoneCall: undefined;
// Passcode
setPasscode: { passcode: string };
setPasscode: { passcode: string } & WithTabId;
clearPasscode: undefined;
lockScreen: undefined;
decryptSession: { passcode: string };

View File

@ -1,6 +1,13 @@
// eslint-disable-next-line no-restricted-globals
const cacheApi = self.caches;
let isSupported: boolean | undefined;
export async function isCacheApiSupported() {
isSupported = isSupported ?? await cacheApi.has('test').then(() => true).catch(() => false);
return isSupported;
}
export enum Type {
Text,
Blob,
@ -67,7 +74,7 @@ export async function fetch(
export async function save(cacheName: string, key: string, data: AnyLiteral | Blob | ArrayBuffer | string) {
if (!cacheApi) {
return undefined;
return false;
}
try {
@ -78,11 +85,12 @@ export async function save(cacheName: string, key: string, data: AnyLiteral | Bl
const request = new Request(key.replace(/:/g, '_'));
const response = new Response(cacheData);
const cache = await cacheApi.open(cacheName);
return await cache.put(request, response);
await cache.put(request, response);
return true;
} catch (err) {
// eslint-disable-next-line no-console
console.warn(err);
return undefined;
return false;
}
}

View File

@ -117,7 +117,12 @@ function sha256(plaintext: string) {
}
async function store(key: string, value: ArrayBuffer) {
await cacheApi.save(PASSCODE_CACHE_NAME, key, value);
const isSuccessful = await cacheApi.save(PASSCODE_CACHE_NAME, key, value);
if (isSuccessful) {
return;
}
throw new Error('Failed to save to cache');
}
function load(key: string) {