From f5086002bbfaa79b1ab6e56e0abd7fc64bd481a5 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Sat, 12 Jun 2021 04:24:40 +0300 Subject: [PATCH] Support exporting legacy session --- src/api/gramjs/methods/auth.ts | 3 +- src/api/gramjs/methods/client.ts | 3 +- src/api/types/updates.ts | 1 + src/config.ts | 2 +- src/lib/gramjs/sessions/StorageSession.js | 44 ++++++++++++---------- src/modules/actions/api/initial.ts | 41 +++++++++++++++----- src/modules/actions/apiUpdaters/initial.ts | 24 +++++++++--- 7 files changed, 80 insertions(+), 38 deletions(-) diff --git a/src/api/gramjs/methods/auth.ts b/src/api/gramjs/methods/auth.ts index a3f791001..68c0a7423 100644 --- a/src/api/gramjs/methods/auth.ts +++ b/src/api/gramjs/methods/auth.ts @@ -105,10 +105,11 @@ export function onAuthError(err: Error) { }); } -export function onAuthReady(sessionId: string) { +export function onAuthReady(sessionId: string, sessionJson: string) { onUpdate({ ...buildAuthStateUpdate('authorizationStateReady'), sessionId, + sessionJson, }); } diff --git a/src/api/gramjs/methods/client.ts b/src/api/gramjs/methods/client.ts index b426c5b3b..28c5eec4c 100644 --- a/src/api/gramjs/methods/client.ts +++ b/src/api/gramjs/methods/client.ts @@ -68,6 +68,7 @@ export async function init(sessionInfo: string, _onUpdate: OnApiUpdate) { }); const newSessionId = await session.save(); + const sessionJson = JSON.stringify(session.getSessionData(true)); if (DEBUG) { // eslint-disable-next-line no-console @@ -76,7 +77,7 @@ export async function init(sessionInfo: string, _onUpdate: OnApiUpdate) { console.log('[GramJs/client] CONNECTED as ', newSessionId); } - onAuthReady(newSessionId); + onAuthReady(newSessionId, sessionJson); onUpdate({ '@type': 'updateApiReady' }); void fetchCurrentUser(); diff --git a/src/api/types/updates.ts b/src/api/types/updates.ts index b1b60432e..3c150b81d 100644 --- a/src/api/types/updates.ts +++ b/src/api/types/updates.ts @@ -36,6 +36,7 @@ export type ApiUpdateAuthorizationState = { '@type': 'updateAuthorizationState'; authorizationState: ApiUpdateAuthorizationStateType; sessionId?: string; + sessionJson?: string; isCodeViaApp?: boolean; hint?: string; qrCode?: { token: string; expires: number }; diff --git a/src/config.ts b/src/config.ts index b83426110..b019a716e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -15,7 +15,7 @@ export const DEBUG_ALERT_MSG = 'Shoot!\nSomething went wrong, please see the err export const DEBUG_GRAMJS = false; export const GRAMJS_SESSION_ID_KEY = 'GramJs:sessionId'; -export const LEGACY_SESSION_KEY = 'dc'; +export const LEGACY_SESSION_KEY = 'user_auth'; export const GLOBAL_STATE_CACHE_DISABLED = false; export const GLOBAL_STATE_CACHE_KEY = 'tt-global-state'; diff --git a/src/lib/gramjs/sessions/StorageSession.js b/src/lib/gramjs/sessions/StorageSession.js index bd87622a3..306a3eb83 100644 --- a/src/lib/gramjs/sessions/StorageSession.js +++ b/src/lib/gramjs/sessions/StorageSession.js @@ -12,7 +12,7 @@ class StorageSession extends MemorySession { this._authKeys = {}; if (sessionInfo && sessionInfo.startsWith(SESSION_DATA_PREFIX)) { - this._sessionData = sessionInfo; + this._sessionString = sessionInfo; } else if (sessionInfo) { this._storageKey = sessionInfo; } @@ -27,8 +27,8 @@ class StorageSession extends MemorySession { } async load() { - if (this._sessionData) { - await this._loadFromSessionData(); + if (this._sessionString) { + await this._loadFromSessionString(); return; } @@ -99,8 +99,26 @@ class StorageSession extends MemorySession { void this._updateStorage(); } - async _loadFromSessionData() { - const [, mainDcIdStr, mainDcKey] = this._sessionData.split(':'); + getSessionData(asHex) { + const sessionData = { + mainDcId: this._dcId, + keys: {}, + hashes: {}, + }; + + Object + .keys(this._authKeys) + .forEach((dcId) => { + const authKey = this._authKeys[dcId]; + sessionData.keys[dcId] = asHex ? authKey._key.toString('hex') : authKey._key; + sessionData.hashes[dcId] = asHex ? authKey._hash.toString('hex') : authKey._hash; + }); + + return sessionData; + } + + async _loadFromSessionString() { + const [, mainDcIdStr, mainDcKey] = this._sessionString.split(':'); const mainDcId = Number(mainDcIdStr); const { ipAddress, @@ -117,22 +135,8 @@ class StorageSession extends MemorySession { return; } - const sessionData = { - mainDcId: this._dcId, - keys: {}, - hashes: {}, - }; - - Object.keys(this._authKeys) - .map((dcId) => { - const authKey = this._authKeys[dcId]; - sessionData.keys[dcId] = authKey._key; - sessionData.hashes[dcId] = authKey._hash; - return undefined; - }); - try { - await this._saveToCache(JSON.stringify(sessionData)); + await this._saveToCache(JSON.stringify(this.getSessionData())); } catch (err) { // eslint-disable-next-line no-console console.warn('Failed to update session in storage'); diff --git a/src/modules/actions/api/initial.ts b/src/modules/actions/api/initial.ts index c9abc7284..4420fe070 100644 --- a/src/modules/actions/api/initial.ts +++ b/src/modules/actions/api/initial.ts @@ -22,12 +22,12 @@ addReducer('initApi', (global: GlobalState, actions) => { let sessionInfo = localStorage.getItem(GRAMJS_SESSION_ID_KEY) || undefined; if (!sessionInfo) { - const legacySessionMainDcRaw = localStorage.getItem(LEGACY_SESSION_KEY); - if (legacySessionMainDcRaw) { - const legacySessionMainDc = legacySessionMainDcRaw.replace(/"/g, ''); - const legacySessionMainDcKeyRaw = localStorage.getItem(`dc${legacySessionMainDc}_auth_key`); - if (legacySessionMainDcKeyRaw) { - const legacySessionMainDcKey = legacySessionMainDcKeyRaw.replace(/"/g, ''); + const legacySessionJson = localStorage.getItem(LEGACY_SESSION_KEY); + if (legacySessionJson) { + const { dcID: legacySessionMainDc } = JSON.parse(legacySessionJson); + const legacySessionMainKeyRaw = localStorage.getItem(`dc${legacySessionMainDc}_auth_key`); + if (legacySessionMainKeyRaw) { + const legacySessionMainDcKey = legacySessionMainKeyRaw.replace(/"/g, ''); sessionInfo = `session:${legacySessionMainDc}:${legacySessionMainDcKey}`; } } @@ -110,8 +110,10 @@ addReducer('gotToAuthQrCode', (global) => { }); addReducer('saveSession', (global, actions, payload) => { - const { sessionId } = payload!; + const { sessionId, sessionJson } = payload!; localStorage.setItem(GRAMJS_SESSION_ID_KEY, sessionId); + + exportLegacySession(sessionJson, global.currentUserId!); }); addReducer('signOut', () => { @@ -125,8 +127,7 @@ addReducer('signOut', () => { addReducer('reset', () => { localStorage.removeItem(GRAMJS_SESSION_ID_KEY); - localStorage.removeItem(LEGACY_SESSION_KEY); - updateAppBadge(0); + clearLegacySession(); cacheApi.clear(MEDIA_CACHE_NAME); cacheApi.clear(MEDIA_CACHE_NAME_AVATARS); @@ -140,6 +141,8 @@ addReducer('reset', () => { cacheApi.clear(`${langChachePrefix}${i === 0 ? '' : i}`); } + updateAppBadge(0); + getDispatch().init(); }); @@ -180,3 +183,23 @@ addReducer('deleteDeviceToken', (global) => { delete newGlobal.push; setGlobal(newGlobal); }); + +function exportLegacySession(sessionJson: string, currentUserId: number) { + const { mainDcId, keys } = JSON.parse(sessionJson); + const legacySession = { dcID: mainDcId, id: currentUserId }; + localStorage.setItem(LEGACY_SESSION_KEY, JSON.stringify(legacySession)); + localStorage.setItem('dc', mainDcId); + Object.keys(keys).forEach((dcId) => { + localStorage.setItem(`dc${dcId}_auth_key`, `"${keys[dcId]}"`); + }); +} + +function clearLegacySession() { + localStorage.removeItem('dc5_auth_key'); + localStorage.removeItem('dc4_auth_key'); + localStorage.removeItem('dc3_auth_key'); + localStorage.removeItem('dc2_auth_key'); + localStorage.removeItem('dc1_auth_key'); + localStorage.removeItem('dc'); + localStorage.removeItem(LEGACY_SESSION_KEY); +} diff --git a/src/modules/actions/apiUpdaters/initial.ts b/src/modules/actions/apiUpdaters/initial.ts index 113f1adaf..476c24ac5 100644 --- a/src/modules/actions/apiUpdaters/initial.ts +++ b/src/modules/actions/apiUpdaters/initial.ts @@ -11,7 +11,7 @@ import { ApiUpdateConnectionState, ApiUpdateCurrentUser, } from '../../../api/types'; -import { DEBUG } from '../../../config'; +import { DEBUG, LEGACY_SESSION_KEY } from '../../../config'; import { subscribe } from '../../../util/notifications'; import { updateUser } from '../../reducers'; import { setLanguage } from '../../../util/langProvider'; @@ -102,6 +102,11 @@ function onUpdateAuthorizationState(update: ApiUpdateAuthorizationState) { }); break; case 'authorizationStateReady': { + const { sessionId, sessionJson } = update; + if (sessionId && global.authRememberMe) { + getDispatch().saveSession({ sessionId, sessionJson }); + } + if (wasAuthReady) { break; } @@ -112,11 +117,6 @@ function onUpdateAuthorizationState(update: ApiUpdateAuthorizationState) { lastSyncTime: Date.now(), }); - const { sessionId } = update; - if (sessionId && global.authRememberMe) { - getDispatch().saveSession({ sessionId }); - } - break; } } @@ -152,4 +152,16 @@ function onUpdateCurrentUser(update: ApiUpdateCurrentUser) { ...updateUser(getGlobal(), currentUser.id, currentUser), currentUserId: currentUser.id, }); + + updateLegacySessionUserId(currentUser.id); +} + +function updateLegacySessionUserId(currentUserId: number) { + const legacySessionJson = localStorage.getItem(LEGACY_SESSION_KEY); + if (!legacySessionJson) return; + + const legacySession = JSON.parse(legacySessionJson); + legacySession.id = currentUserId; + + localStorage.setItem(LEGACY_SESSION_KEY, JSON.stringify(legacySession)); }