TelegramPWA/src/util/sessions.ts
2025-04-24 14:22:15 +02:00

191 lines
4.7 KiB
TypeScript

import type { ApiSessionData } from '../api/types';
import type { DcId, SharedSessionData } from '../types';
import {
DC_IDS,
DEBUG, IS_SCREEN_LOCKED_CACHE_KEY,
SESSION_ACCOUNT_PREFIX,
SESSION_LEGACY_USER_KEY,
} from '../config';
import { ACCOUNT_SLOT, storeAccountData, writeSlotSession } from './multiaccount';
export function hasStoredSession() {
if (checkSessionLocked()) {
return true;
}
const slotData = loadSlotSession(ACCOUNT_SLOT);
if (slotData) return Boolean(slotData.dcId);
if (!ACCOUNT_SLOT) {
const legacyAuthJson = localStorage.getItem(SESSION_LEGACY_USER_KEY);
if (legacyAuthJson) {
try {
const userAuth = JSON.parse(legacyAuthJson);
return Boolean(userAuth && userAuth.id && userAuth.dcID);
} catch (err) {
// Do nothing.
return false;
}
}
}
return false;
}
export function storeSession(sessionData: ApiSessionData) {
const {
mainDcId, keys, isTest,
} = sessionData;
const currentSlotData = loadSlotSession(ACCOUNT_SLOT);
const newSlotData: SharedSessionData = {
...currentSlotData,
dcId: mainDcId,
isTest,
};
Object.keys(keys).map(Number).forEach((dcId) => {
newSlotData[`dc${dcId as DcId}_auth_key`] = keys[dcId];
});
if (!ACCOUNT_SLOT) {
storeLegacySession(sessionData, currentSlotData?.userId);
}
writeSlotSession(ACCOUNT_SLOT, newSlotData);
}
function storeLegacySession(sessionData: ApiSessionData, currentUserId?: string) {
const {
mainDcId, keys, isTest,
} = sessionData;
localStorage.setItem(SESSION_LEGACY_USER_KEY, JSON.stringify({
dcID: mainDcId,
id: currentUserId,
test: isTest,
}));
localStorage.setItem('dc', String(mainDcId));
Object.keys(keys).map(Number).forEach((dcId) => {
localStorage.setItem(`dc${dcId}_auth_key`, JSON.stringify(keys[dcId]));
});
}
export function clearStoredSession(slot?: number) {
if (!slot) {
clearStoredLegacySession();
}
localStorage.removeItem(`${SESSION_ACCOUNT_PREFIX}${slot || 1}`);
}
function clearStoredLegacySession() {
[
SESSION_LEGACY_USER_KEY,
'dc',
...DC_IDS.map((dcId) => `dc${dcId}_auth_key`),
...DC_IDS.map((dcId) => `dc${dcId}_hash`),
...DC_IDS.map((dcId) => `dc${dcId}_server_salt`),
].forEach((key) => {
localStorage.removeItem(key);
});
}
export function loadStoredSession(): ApiSessionData | undefined {
if (!hasStoredSession()) {
return undefined;
}
const slotData = loadSlotSession(ACCOUNT_SLOT);
if (!slotData) {
if (ACCOUNT_SLOT) return undefined;
return loadStoredLegacySession();
}
const sessionData: ApiSessionData = {
mainDcId: slotData.dcId,
keys: DC_IDS.reduce((acc, dcId) => {
const key = slotData[`dc${dcId}_auth_key` as const];
if (key) {
acc[dcId] = key;
}
return acc;
}, {} as Record<number, string>),
isTest: slotData.isTest || undefined,
};
return sessionData;
}
function loadStoredLegacySession(): ApiSessionData | undefined {
if (!hasStoredSession()) {
return undefined;
}
const userAuth = JSON.parse(localStorage.getItem(SESSION_LEGACY_USER_KEY) || 'null');
if (!userAuth) {
return undefined;
}
const mainDcId = Number(userAuth.dcID);
const isTest = userAuth.test;
const keys: Record<number, string> = {};
DC_IDS.forEach((dcId) => {
try {
const key = localStorage.getItem(`dc${dcId}_auth_key`);
if (key) {
keys[dcId] = JSON.parse(key);
}
} catch (err) {
if (DEBUG) {
// eslint-disable-next-line no-console
console.warn('Failed to load stored session', err);
}
// Do nothing.
}
});
if (!Object.keys(keys).length) return undefined;
return {
mainDcId,
keys,
isTest,
};
}
export function loadSlotSession(slot: number | undefined): SharedSessionData | undefined {
try {
const data = JSON.parse(localStorage.getItem(`${SESSION_ACCOUNT_PREFIX}${slot || 1}`) || '{}') as SharedSessionData;
if (!data.dcId) return undefined;
return data;
} catch (e) {
return undefined;
}
}
export function updateSessionUserId(currentUserId: string) {
const slotData = loadSlotSession(ACCOUNT_SLOT);
if (!slotData) return;
storeAccountData(ACCOUNT_SLOT, { userId: currentUserId });
}
export function importTestSession() {
const sessionJson = process.env.TEST_SESSION!;
try {
const sessionData = JSON.parse(sessionJson) as ApiSessionData & { userId: string };
storeLegacySession(sessionData, sessionData.userId);
} catch (err) {
if (DEBUG) {
// eslint-disable-next-line no-console
console.warn('Failed to load test session', err);
}
}
}
export function checkSessionLocked() {
return localStorage.getItem(IS_SCREEN_LOCKED_CACHE_KEY) === 'true';
}