fix(core): use existing auth_key from storage

This commit is contained in:
teidesu 2022-11-08 06:50:49 +03:00 committed by Alina Sireneva
parent a23197df91
commit bd5130c77b
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
4 changed files with 73 additions and 32 deletions

View file

@ -334,6 +334,7 @@ export class BaseTelegramClient extends EventEmitter {
storage: this.storage, storage: this.storage,
testMode: this._testMode, testMode: this._testMode,
transport: opts.transport, transport: opts.transport,
_emitError: this._emitError.bind(this),
...(opts.network ?? {}), ...(opts.network ?? {}),
}, this._config) }, this._config)
@ -881,9 +882,8 @@ export class BaseTelegramClient extends EventEmitter {
} }
} }
await this.storage.updatePeers(parsedPeers)
if (count > 0) { if (count > 0) {
await this.storage.updatePeers(parsedPeers)
this.log.debug('cached %d peers', count) this.log.debug('cached %d peers', count)
} }

View file

@ -10,7 +10,7 @@ import { MtprotoSession } from './mtproto-session'
export class MultiSessionConnection extends EventEmitter { export class MultiSessionConnection extends EventEmitter {
private _log: Logger private _log: Logger
private _sessions: MtprotoSession[] readonly _sessions: MtprotoSession[]
constructor( constructor(
readonly params: SessionConnectionParams, readonly params: SessionConnectionParams,
@ -88,6 +88,7 @@ export class MultiSessionConnection extends EventEmitter {
if (this._connections.length > this._count) { if (this._connections.length > this._count) {
// destroy extra connections // destroy extra connections
for (let i = this._connections.length - 1; i >= this._count; i--) { for (let i = this._connections.length - 1; i >= this._count; i--) {
this._connections[i].removeAllListeners()
this._connections[i].destroy() this._connections[i].destroy()
} }
@ -97,10 +98,17 @@ export class MultiSessionConnection extends EventEmitter {
// create new connections // create new connections
for (let i = this._connections.length; i < this._count; i++) { for (let i = this._connections.length; i < this._count; i++) {
const session = this.params.isMainConnection ? this._sessions[i] : this._sessions[0] const session = this.params.isMainConnection
? this._sessions[i]
: this._sessions[0]
const conn = new SessionConnection(this.params, session) const conn = new SessionConnection(this.params, session)
conn.on('update', (update) => this.emit('update', update)) conn.on('update', (update) => this.emit('update', update))
conn.on('error', (err) => this.emit('error', err, conn))
conn.on('key-change', (key) => this.emit('key-change', i, key))
conn.on('tmp-key-change', (key, expires) =>
this.emit('tmp-key-change', i, key, expires)
)
this._connections.push(conn) this._connections.push(conn)
} }
@ -128,7 +136,9 @@ export class MultiSessionConnection extends EventEmitter {
let minIdx = 0 let minIdx = 0
for (let i = 0; i < this._connections.length; i++) { for (let i = 0; i < this._connections.length; i++) {
const conn = this._connections[i] const conn = this._connections[i]
const total = conn._session.queuedRpc.length + conn._session.pendingMessages.size() const total =
conn._session.queuedRpc.length +
conn._session.pendingMessages.size()
if (total < min) { if (total < min) {
min = total min = total
@ -157,4 +167,10 @@ export class MultiSessionConnection extends EventEmitter {
conn.connect() conn.connect()
} }
} }
async setAuthKey(authKey: Buffer | null, temp = false, idx = 0): Promise<void> {
const session = this._sessions[idx]
const key = temp ? session._authKeyTemp : session._authKey
await key.setup(authKey)
}
} }

View file

@ -10,16 +10,10 @@ import {
import { PersistentConnectionParams } from './persistent-connection' import { PersistentConnectionParams } from './persistent-connection'
import { ConfigManager } from './config-manager' import { ConfigManager } from './config-manager'
import { MultiSessionConnection } from './multi-session-connection' import { MultiSessionConnection } from './multi-session-connection'
import { SessionConnectionParams } from './session-connection' import { SessionConnection, SessionConnectionParams } from "./session-connection";
import { ITelegramStorage } from '../storage' import { ITelegramStorage } from '../storage'
export class DcConnectionManager { export class DcConnectionManager {
constructor(
readonly manager: NetworkManager,
readonly dcId: number,
private _dc: tl.RawDcOption
) {}
private __baseConnectionParams = (): SessionConnectionParams => ({ private __baseConnectionParams = (): SessionConnectionParams => ({
crypto: this.manager.params.crypto, crypto: this.manager.params.crypto,
initConnection: this.manager._initConnectionParams, initConnection: this.manager._initConnectionParams,
@ -43,6 +37,38 @@ export class DcConnectionManager {
1, 1,
this.manager._log this.manager._log
) )
constructor(
readonly manager: NetworkManager,
readonly dcId: number,
private _dc: tl.RawDcOption
) {
this._setupStorageHandlers(this.mainConnection)
}
private _setupStorageHandlers(connection: MultiSessionConnection): void {
connection.on('key-change', (idx, key) => {
this.manager._log.debug('key change for dc %d from connection %d', this.dcId, idx)
this.manager._storage.setAuthKeyFor(this.dcId, key)
})
connection.on('tmp-key-change', (idx, key, expires) => {
this.manager._log.debug('temp key change for dc %d from connection %d', this.dcId, idx)
this.manager._storage.setTempAuthKeyFor(this.dcId, idx, key, expires * 1000)
})
}
async loadKeys(): Promise<void> {
const permanent = await this.manager._storage.getAuthKeyFor(this.dcId)
await this.mainConnection.setAuthKey(permanent)
if (this.manager.params.usePfs) {
for (let i = 0; i < this.mainConnection._sessions.length; i++) {
const temp = await this.manager._storage.getAuthKeyFor(this.dcId, i)
await this.mainConnection.setAuthKey(temp, true, i)
}
}
}
} }
/** /**
@ -66,6 +92,7 @@ export interface NetworkManagerParams {
layer: number layer: number
readerMap: TlReaderMap readerMap: TlReaderMap
writerMap: TlWriterMap writerMap: TlWriterMap
_emitError: (err: Error, connection?: SessionConnection) => void
} }
/** /**
@ -82,6 +109,7 @@ export interface NetworkManagerExtraParams {
export class NetworkManager { export class NetworkManager {
readonly _log = this.params.log.create('network') readonly _log = this.params.log.create('network')
readonly _storage = this.params.storage
readonly _initConnectionParams: tl.RawInitConnectionRequest readonly _initConnectionParams: tl.RawInitConnectionRequest
readonly _transportFactory: TransportFactory readonly _transportFactory: TransportFactory
@ -92,6 +120,8 @@ export class NetworkManager {
private _keepAliveInterval?: NodeJS.Timeout private _keepAliveInterval?: NodeJS.Timeout
private _keepAliveAction = this._defaultKeepAliveAction.bind(this) private _keepAliveAction = this._defaultKeepAliveAction.bind(this)
private _lastUpdateTime = 0
private _updateHandler: (upd: tl.TypeUpdates) => void = () => {}
private _defaultKeepAliveAction(): void { private _defaultKeepAliveAction(): void {
if (this._keepAliveInterval) return if (this._keepAliveInterval) return
@ -160,9 +190,7 @@ export class NetworkManager {
this._primaryDc = dc this._primaryDc = dc
// todo add handlers dc.mainConnection.on('usable', () => {
/*
this.primaryConnection.on('usable', () => {
this._lastUpdateTime = Date.now() this._lastUpdateTime = Date.now()
if (this._keepAliveInterval) clearInterval(this._keepAliveInterval) if (this._keepAliveInterval) clearInterval(this._keepAliveInterval)
@ -173,22 +201,19 @@ export class NetworkManager {
} }
}, 60_000) }, 60_000)
}) })
this.primaryConnection.on('update', (update) => { dc.mainConnection.on('update', (update) => {
this._lastUpdateTime = Date.now() this._lastUpdateTime = Date.now()
this._handleUpdate(update) this._updateHandler(update)
}) })
this.primaryConnection.on('wait', () => // dc.mainConnection.on('wait', () =>
this._cleanupPrimaryConnection() // this._cleanupPrimaryConnection()
// )
dc.mainConnection.on('error', (err, conn) =>
this.params._emitError(err, conn)
) )
this.primaryConnection.on('key-change', async (key) => { dc.loadKeys()
this.storage.setAuthKeyFor(this._defaultDc.id, key) .catch((e) => this.params._emitError(e))
await this._saveStorage() .then(() => dc.mainConnection.connect())
})
this.primaryConnection.on('error', (err) =>
this._emitError(err, this.primaryConnection)
)
*/
dc.mainConnection.connect()
} }
/** /**

View file

@ -41,7 +41,7 @@ import {
import { TransportError } from './transports' import { TransportError } from './transports'
import { createAesIgeForMessageOld } from '../utils/crypto/mtproto' import { createAesIgeForMessageOld } from '../utils/crypto/mtproto'
const TEMP_AUTH_KEY_EXPIRY = 300 // 86400 fixme const TEMP_AUTH_KEY_EXPIRY = 86400
export interface SessionConnectionParams extends PersistentConnectionParams { export interface SessionConnectionParams extends PersistentConnectionParams {
initConnection: tl.RawInitConnectionRequest initConnection: tl.RawInitConnectionRequest
@ -57,7 +57,7 @@ export interface SessionConnectionParams extends PersistentConnectionParams {
} }
// destroy_auth_key#d1435160 = DestroyAuthKeyRes; // destroy_auth_key#d1435160 = DestroyAuthKeyRes;
const DESTROY_AUTH_KEY = Buffer.from('605134d1', 'hex') // const DESTROY_AUTH_KEY = Buffer.from('605134d1', 'hex')
function makeNiceStack( function makeNiceStack(
error: tl.errors.RpcError, error: tl.errors.RpcError,
@ -160,7 +160,7 @@ export class SessionConnection extends PersistentConnection {
this._authorize() this._authorize()
// todo: if we use pfs, we can also start temp key exchange here // todo: if we use pfs, we can also start temp key exchange here
} else if (this.params.usePfs && !this._session._authKeyTemp.ready) { } else if (this.params.usePfs && !this._session._authKeyTemp.ready) {
this.log.info('no perm auth key but using pfs, authorizing') this.log.info('no temp auth key but using pfs, authorizing')
this._authorizePfs() this._authorizePfs()
} else { } else {
this.log.info('auth keys are already available') this.log.info('auth keys are already available')
@ -234,7 +234,7 @@ export class SessionConnection extends PersistentConnection {
} }
} }
this.emit('err', error) this.emit('error', error)
} }
protected onConnectionUsable() { protected onConnectionUsable() {