import { addActionHandler, getGlobal, setGlobal, } from '../../index'; import { initApi, callApi, callApiLocal, setShouldEnableDebugLog, } from '../../../api/gramjs'; import { LANG_CACHE_NAME, CUSTOM_BG_CACHE_NAME, MEDIA_CACHE_NAME, MEDIA_CACHE_NAME_AVATARS, MEDIA_PROGRESSIVE_CACHE_NAME, IS_TEST, LOCK_SCREEN_ANIMATION_DURATION_MS, } from '../../../config'; import { IS_MOV_SUPPORTED, IS_WEBM_SUPPORTED, MAX_BUFFER_SIZE, PLATFORM_ENV, } from '../../../util/windowEnvironment'; import { unsubscribe } from '../../../util/notifications'; import * as cacheApi from '../../../util/cacheApi'; import { updateAppBadge } from '../../../util/appBadge'; import { storeSession, loadStoredSession, clearStoredSession, importLegacySession, clearLegacySessions, } from '../../../util/sessions'; import { forceWebsync } from '../../../util/websync'; import { addUsers, clearGlobalForLockScreen, updatePasscodeSettings } from '../../reducers'; import { clearEncryptedSession, encryptSession, forgetPasscode } from '../../../util/passcode'; import { serializeGlobal } from '../../cache'; import { parseInitialLocationHash, resetInitialLocationHash } from '../../../util/routing'; import type { ActionReturnType } from '../../types'; import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { buildCollectionByKey } from '../../../util/iteratees'; addActionHandler('initApi', async (global, actions): Promise => { if (!IS_TEST) { await importLegacySession(); void clearLegacySessions(); } const initialLocationHash = parseInitialLocationHash(); void initApi(actions.apiUpdate, { userAgent: navigator.userAgent, platform: PLATFORM_ENV, sessionData: loadStoredSession(), isTest: window.location.search.includes('test') || initialLocationHash?.tgWebAuthTest === '1', isMovSupported: IS_MOV_SUPPORTED, isWebmSupported: IS_WEBM_SUPPORTED, maxBufferSize: MAX_BUFFER_SIZE, webAuthToken: initialLocationHash?.tgWebAuthToken, dcId: initialLocationHash?.tgWebAuthDcId ? Number(initialLocationHash?.tgWebAuthDcId) : undefined, mockScenario: initialLocationHash?.mockScenario, shouldAllowHttpTransport: global.settings.byKey.shouldAllowHttpTransport, shouldForceHttpTransport: global.settings.byKey.shouldForceHttpTransport, shouldDebugExportedSenders: global.settings.byKey.shouldDebugExportedSenders, }); void setShouldEnableDebugLog(Boolean(global.settings.byKey.shouldCollectDebugLogs)); }); addActionHandler('setAuthPhoneNumber', (global, actions, payload): ActionReturnType => { const { phoneNumber } = payload!; void callApi('provideAuthPhoneNumber', phoneNumber.replace(/[^\d]/g, '')); return { ...global, authIsLoading: true, authError: undefined, }; }); addActionHandler('setAuthCode', (global, actions, payload): ActionReturnType => { const { code } = payload!; void callApi('provideAuthCode', code); return { ...global, authIsLoading: true, authError: undefined, }; }); addActionHandler('setAuthPassword', (global, actions, payload): ActionReturnType => { const { password } = payload!; void callApi('provideAuthPassword', password); return { ...global, authIsLoading: true, authError: undefined, }; }); addActionHandler('uploadProfilePhoto', async (global, actions, payload): Promise => { const { file, isFallback, isVideo, videoTs, } = payload!; const result = await callApi('uploadProfilePhoto', file, isFallback, isVideo, videoTs); if (!result) return; global = getGlobal(); global = addUsers(global, buildCollectionByKey(result.users, 'id')); setGlobal(global); actions.loadFullUser({ userId: global.currentUserId! }); }); addActionHandler('signUp', (global, actions, payload): ActionReturnType => { const { firstName, lastName } = payload!; void callApi('provideAuthRegistration', { firstName, lastName }); return { ...global, authIsLoading: true, authError: undefined, }; }); addActionHandler('returnToAuthPhoneNumber', (global): ActionReturnType => { void callApi('restartAuth'); return { ...global, authError: undefined, }; }); addActionHandler('goToAuthQrCode', (global): ActionReturnType => { void callApi('restartAuthWithQr'); return { ...global, authIsLoadingQrCode: true, authError: undefined, }; }); addActionHandler('saveSession', (global, actions, payload): ActionReturnType => { if (global.passcode.isScreenLocked) { return; } const { sessionData } = payload; if (sessionData) { storeSession(sessionData, global.currentUserId); } else { clearStoredSession(); } }); addActionHandler('signOut', async (global, actions, payload): Promise => { if ('hangUp' in actions) actions.hangUp({ tabId: getCurrentTabId() }); if ('leaveGroupCall' in actions) actions.leaveGroupCall({ tabId: getCurrentTabId() }); try { resetInitialLocationHash(); await unsubscribe(); await callApi('destroy'); await forceWebsync(false); } catch (err) { // Do nothing } actions.reset(); if (payload?.forceInitApi) { actions.initApi(); } }); addActionHandler('requestChannelDifference', (global, actions, payload): ActionReturnType => { const { chatId } = payload; void callApi('requestChannelDifference', chatId); }); addActionHandler('reset', (global, actions): ActionReturnType => { clearStoredSession(); clearEncryptedSession(); void cacheApi.clear(MEDIA_CACHE_NAME); void cacheApi.clear(MEDIA_CACHE_NAME_AVATARS); void cacheApi.clear(MEDIA_PROGRESSIVE_CACHE_NAME); void cacheApi.clear(CUSTOM_BG_CACHE_NAME); const langCachePrefix = LANG_CACHE_NAME.replace(/\d+$/, ''); const langCacheVersion = Number((LANG_CACHE_NAME.match(/\d+$/) || ['0'])[0]); for (let i = 0; i < langCacheVersion; i++) { void cacheApi.clear(`${langCachePrefix}${i === 0 ? '' : i}`); } void clearLegacySessions(); updateAppBadge(0); actions.initShared({ force: true }); Object.values(global.byTabId).forEach(({ id: otherTabId, isMasterTab }) => { actions.init({ tabId: otherTabId, isMasterTab }); }); }); addActionHandler('disconnect', (): ActionReturnType => { void callApiLocal('disconnect'); }); addActionHandler('destroyConnection', (): ActionReturnType => { void callApiLocal('destroy', true, true); }); addActionHandler('loadNearestCountry', async (global): Promise => { if (global.connectionState !== 'connectionStateReady') { return; } const authNearestCountry = await callApi('fetchNearestCountry'); global = getGlobal(); global = { ...global, authNearestCountry, }; setGlobal(global); }); addActionHandler('setDeviceToken', (global, actions, deviceToken): ActionReturnType => { return { ...global, push: { deviceToken, subscribedAt: Date.now(), }, }; }); addActionHandler('deleteDeviceToken', (global): ActionReturnType => { return { ...global, push: undefined, }; }); addActionHandler('lockScreen', async (global): Promise => { const sessionJson = JSON.stringify({ ...loadStoredSession(), userId: global.currentUserId }); const globalJson = await serializeGlobal(global); await encryptSession(sessionJson, globalJson); forgetPasscode(); clearStoredSession(); updateAppBadge(0); global = getGlobal(); global = updatePasscodeSettings( global, { isScreenLocked: true, invalidAttemptsCount: 0, timeoutUntil: undefined, }, ); setGlobal(global); setTimeout(() => { global = getGlobal(); global = clearGlobalForLockScreen(global); setGlobal(global); }, LOCK_SCREEN_ANIMATION_DURATION_MS); try { await unsubscribe(); await callApi('destroy', true); } catch (err) { // Do nothing } });