179 lines
4.6 KiB
JavaScript
179 lines
4.6 KiB
JavaScript
const MemorySession = require('./Memory');
|
|
const AuthKey = require('../crypto/AuthKey');
|
|
const utils = require('../Utils');
|
|
|
|
const STORAGE_KEY_BASE = 'GramJs-session-';
|
|
const SESSION_DATA_PREFIX = 'session:';
|
|
|
|
class StorageSession extends MemorySession {
|
|
constructor(sessionInfo) {
|
|
super();
|
|
|
|
this._authKeys = {};
|
|
|
|
if (sessionInfo && sessionInfo.startsWith(SESSION_DATA_PREFIX)) {
|
|
this._sessionData = sessionInfo;
|
|
} else if (sessionInfo) {
|
|
this._storageKey = sessionInfo;
|
|
}
|
|
}
|
|
|
|
get authKey() {
|
|
throw new Error('Not supported');
|
|
}
|
|
|
|
set authKey(value) {
|
|
throw new Error('Not supported');
|
|
}
|
|
|
|
async load() {
|
|
if (this._sessionData) {
|
|
await this._loadFromSessionData();
|
|
return;
|
|
}
|
|
|
|
if (!this._storageKey) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const json = await this._fetchFromCache();
|
|
const {
|
|
mainDcId,
|
|
keys,
|
|
hashes,
|
|
} = JSON.parse(json);
|
|
const {
|
|
ipAddress,
|
|
port,
|
|
} = utils.getDC(mainDcId);
|
|
|
|
this.setDC(mainDcId, ipAddress, port, true);
|
|
|
|
Object.keys(keys)
|
|
.forEach((dcId) => {
|
|
if (keys[dcId] && hashes[dcId]) {
|
|
this._authKeys[dcId] = new AuthKey(
|
|
Buffer.from(keys[dcId].data),
|
|
Buffer.from(hashes[dcId].data),
|
|
);
|
|
}
|
|
});
|
|
} catch (err) {
|
|
// eslint-disable-next-line no-console
|
|
console.warn('Failed to retrieve or parse session from storage');
|
|
// eslint-disable-next-line no-console
|
|
console.warn(err);
|
|
}
|
|
}
|
|
|
|
setDC(dcId, serverAddress, port, skipUpdateStorage = false) {
|
|
this._dcId = dcId;
|
|
this._serverAddress = serverAddress;
|
|
this._port = port;
|
|
|
|
delete this._authKeys[dcId];
|
|
|
|
if (!skipUpdateStorage) {
|
|
void this._updateStorage();
|
|
}
|
|
}
|
|
|
|
async save() {
|
|
if (!this._storageKey) {
|
|
this._storageKey = generateStorageKey();
|
|
}
|
|
|
|
await this._updateStorage();
|
|
|
|
return this._storageKey;
|
|
}
|
|
|
|
getAuthKey(dcId = this._dcId) {
|
|
return this._authKeys[dcId];
|
|
}
|
|
|
|
setAuthKey(authKey, dcId = this._dcId) {
|
|
this._authKeys[dcId] = authKey;
|
|
|
|
void this._updateStorage();
|
|
}
|
|
|
|
async _loadFromSessionData() {
|
|
const [, mainDcIdStr, mainDcKey] = this._sessionData.split(':');
|
|
const mainDcId = Number(mainDcIdStr);
|
|
const {
|
|
ipAddress,
|
|
port,
|
|
} = utils.getDC(mainDcId);
|
|
this.setDC(mainDcId, ipAddress, port);
|
|
const authKey = new AuthKey();
|
|
await authKey.setKey(Buffer.from(mainDcKey, 'hex'), true);
|
|
this.setAuthKey(authKey, mainDcId);
|
|
}
|
|
|
|
async _updateStorage() {
|
|
if (!this._storageKey) {
|
|
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));
|
|
} catch (err) {
|
|
// eslint-disable-next-line no-console
|
|
console.warn('Failed to update session in storage');
|
|
// eslint-disable-next-line no-console
|
|
console.warn(err);
|
|
}
|
|
}
|
|
|
|
async delete() {
|
|
try {
|
|
return await this._delete();
|
|
} catch (err) {
|
|
// eslint-disable-next-line no-console
|
|
console.warn('Failed to delete session from storage');
|
|
// eslint-disable-next-line no-console
|
|
console.warn(err);
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
// @abstract
|
|
_delete() {
|
|
throw new Error('Not Implemented');
|
|
}
|
|
|
|
// @abstract
|
|
_fetchFromCache() {
|
|
throw new Error('Not Implemented');
|
|
}
|
|
|
|
// @abstract
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
_saveToCache(data) {
|
|
throw new Error('Not Implemented');
|
|
}
|
|
}
|
|
|
|
function generateStorageKey() {
|
|
// Creating two sessions at the same moment is not expected nor supported.
|
|
return `${STORAGE_KEY_BASE}${Date.now()}`;
|
|
}
|
|
|
|
module.exports = StorageSession;
|