Support exporting legacy session

This commit is contained in:
Alexander Zinchuk 2021-06-12 04:24:40 +03:00
parent 19ef014068
commit f5086002bb
7 changed files with 80 additions and 38 deletions

View File

@ -105,10 +105,11 @@ export function onAuthError(err: Error) {
}); });
} }
export function onAuthReady(sessionId: string) { export function onAuthReady(sessionId: string, sessionJson: string) {
onUpdate({ onUpdate({
...buildAuthStateUpdate('authorizationStateReady'), ...buildAuthStateUpdate('authorizationStateReady'),
sessionId, sessionId,
sessionJson,
}); });
} }

View File

@ -68,6 +68,7 @@ export async function init(sessionInfo: string, _onUpdate: OnApiUpdate) {
}); });
const newSessionId = await session.save(); const newSessionId = await session.save();
const sessionJson = JSON.stringify(session.getSessionData(true));
if (DEBUG) { if (DEBUG) {
// eslint-disable-next-line no-console // 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); console.log('[GramJs/client] CONNECTED as ', newSessionId);
} }
onAuthReady(newSessionId); onAuthReady(newSessionId, sessionJson);
onUpdate({ '@type': 'updateApiReady' }); onUpdate({ '@type': 'updateApiReady' });
void fetchCurrentUser(); void fetchCurrentUser();

View File

@ -36,6 +36,7 @@ export type ApiUpdateAuthorizationState = {
'@type': 'updateAuthorizationState'; '@type': 'updateAuthorizationState';
authorizationState: ApiUpdateAuthorizationStateType; authorizationState: ApiUpdateAuthorizationStateType;
sessionId?: string; sessionId?: string;
sessionJson?: string;
isCodeViaApp?: boolean; isCodeViaApp?: boolean;
hint?: string; hint?: string;
qrCode?: { token: string; expires: number }; qrCode?: { token: string; expires: number };

View File

@ -15,7 +15,7 @@ export const DEBUG_ALERT_MSG = 'Shoot!\nSomething went wrong, please see the err
export const DEBUG_GRAMJS = false; export const DEBUG_GRAMJS = false;
export const GRAMJS_SESSION_ID_KEY = 'GramJs:sessionId'; 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_DISABLED = false;
export const GLOBAL_STATE_CACHE_KEY = 'tt-global-state'; export const GLOBAL_STATE_CACHE_KEY = 'tt-global-state';

View File

@ -12,7 +12,7 @@ class StorageSession extends MemorySession {
this._authKeys = {}; this._authKeys = {};
if (sessionInfo && sessionInfo.startsWith(SESSION_DATA_PREFIX)) { if (sessionInfo && sessionInfo.startsWith(SESSION_DATA_PREFIX)) {
this._sessionData = sessionInfo; this._sessionString = sessionInfo;
} else if (sessionInfo) { } else if (sessionInfo) {
this._storageKey = sessionInfo; this._storageKey = sessionInfo;
} }
@ -27,8 +27,8 @@ class StorageSession extends MemorySession {
} }
async load() { async load() {
if (this._sessionData) { if (this._sessionString) {
await this._loadFromSessionData(); await this._loadFromSessionString();
return; return;
} }
@ -99,8 +99,26 @@ class StorageSession extends MemorySession {
void this._updateStorage(); void this._updateStorage();
} }
async _loadFromSessionData() { getSessionData(asHex) {
const [, mainDcIdStr, mainDcKey] = this._sessionData.split(':'); 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 mainDcId = Number(mainDcIdStr);
const { const {
ipAddress, ipAddress,
@ -117,22 +135,8 @@ class StorageSession extends MemorySession {
return; 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 { try {
await this._saveToCache(JSON.stringify(sessionData)); await this._saveToCache(JSON.stringify(this.getSessionData()));
} catch (err) { } catch (err) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.warn('Failed to update session in storage'); console.warn('Failed to update session in storage');

View File

@ -22,12 +22,12 @@ addReducer('initApi', (global: GlobalState, actions) => {
let sessionInfo = localStorage.getItem(GRAMJS_SESSION_ID_KEY) || undefined; let sessionInfo = localStorage.getItem(GRAMJS_SESSION_ID_KEY) || undefined;
if (!sessionInfo) { if (!sessionInfo) {
const legacySessionMainDcRaw = localStorage.getItem(LEGACY_SESSION_KEY); const legacySessionJson = localStorage.getItem(LEGACY_SESSION_KEY);
if (legacySessionMainDcRaw) { if (legacySessionJson) {
const legacySessionMainDc = legacySessionMainDcRaw.replace(/"/g, ''); const { dcID: legacySessionMainDc } = JSON.parse(legacySessionJson);
const legacySessionMainDcKeyRaw = localStorage.getItem(`dc${legacySessionMainDc}_auth_key`); const legacySessionMainKeyRaw = localStorage.getItem(`dc${legacySessionMainDc}_auth_key`);
if (legacySessionMainDcKeyRaw) { if (legacySessionMainKeyRaw) {
const legacySessionMainDcKey = legacySessionMainDcKeyRaw.replace(/"/g, ''); const legacySessionMainDcKey = legacySessionMainKeyRaw.replace(/"/g, '');
sessionInfo = `session:${legacySessionMainDc}:${legacySessionMainDcKey}`; sessionInfo = `session:${legacySessionMainDc}:${legacySessionMainDcKey}`;
} }
} }
@ -110,8 +110,10 @@ addReducer('gotToAuthQrCode', (global) => {
}); });
addReducer('saveSession', (global, actions, payload) => { addReducer('saveSession', (global, actions, payload) => {
const { sessionId } = payload!; const { sessionId, sessionJson } = payload!;
localStorage.setItem(GRAMJS_SESSION_ID_KEY, sessionId); localStorage.setItem(GRAMJS_SESSION_ID_KEY, sessionId);
exportLegacySession(sessionJson, global.currentUserId!);
}); });
addReducer('signOut', () => { addReducer('signOut', () => {
@ -125,8 +127,7 @@ addReducer('signOut', () => {
addReducer('reset', () => { addReducer('reset', () => {
localStorage.removeItem(GRAMJS_SESSION_ID_KEY); localStorage.removeItem(GRAMJS_SESSION_ID_KEY);
localStorage.removeItem(LEGACY_SESSION_KEY); clearLegacySession();
updateAppBadge(0);
cacheApi.clear(MEDIA_CACHE_NAME); cacheApi.clear(MEDIA_CACHE_NAME);
cacheApi.clear(MEDIA_CACHE_NAME_AVATARS); cacheApi.clear(MEDIA_CACHE_NAME_AVATARS);
@ -140,6 +141,8 @@ addReducer('reset', () => {
cacheApi.clear(`${langChachePrefix}${i === 0 ? '' : i}`); cacheApi.clear(`${langChachePrefix}${i === 0 ? '' : i}`);
} }
updateAppBadge(0);
getDispatch().init(); getDispatch().init();
}); });
@ -180,3 +183,23 @@ addReducer('deleteDeviceToken', (global) => {
delete newGlobal.push; delete newGlobal.push;
setGlobal(newGlobal); 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);
}

View File

@ -11,7 +11,7 @@ import {
ApiUpdateConnectionState, ApiUpdateConnectionState,
ApiUpdateCurrentUser, ApiUpdateCurrentUser,
} from '../../../api/types'; } from '../../../api/types';
import { DEBUG } from '../../../config'; import { DEBUG, LEGACY_SESSION_KEY } from '../../../config';
import { subscribe } from '../../../util/notifications'; import { subscribe } from '../../../util/notifications';
import { updateUser } from '../../reducers'; import { updateUser } from '../../reducers';
import { setLanguage } from '../../../util/langProvider'; import { setLanguage } from '../../../util/langProvider';
@ -102,6 +102,11 @@ function onUpdateAuthorizationState(update: ApiUpdateAuthorizationState) {
}); });
break; break;
case 'authorizationStateReady': { case 'authorizationStateReady': {
const { sessionId, sessionJson } = update;
if (sessionId && global.authRememberMe) {
getDispatch().saveSession({ sessionId, sessionJson });
}
if (wasAuthReady) { if (wasAuthReady) {
break; break;
} }
@ -112,11 +117,6 @@ function onUpdateAuthorizationState(update: ApiUpdateAuthorizationState) {
lastSyncTime: Date.now(), lastSyncTime: Date.now(),
}); });
const { sessionId } = update;
if (sessionId && global.authRememberMe) {
getDispatch().saveSession({ sessionId });
}
break; break;
} }
} }
@ -152,4 +152,16 @@ function onUpdateCurrentUser(update: ApiUpdateCurrentUser) {
...updateUser(getGlobal(), currentUser.id, currentUser), ...updateUser(getGlobal(), currentUser.id, currentUser),
currentUserId: currentUser.id, 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));
} }