<commit_before>//     telegram.link
//     Copyright 2014 <NAME> '<EMAIL>'
//     Released under the MIT License
//     http://telegram.link


// ***

// Dependencies:
var tl = require('telegram-tl-node');
var mt = require('telegram-mt-node');
var auth = mt.auth;
var utility = mt.utility;
var net = mt.net;
var api = require('./api');
var SequenceNumber = mt.SequenceNumber;
var logger = require('get-log')('telegram-link');

// Constants
var NULL_SERVER_SALT = '0x0000000000000000';

// ***

// Print the library version
require('colors');
var printed = false;
module.exports = exports = function (signature) {
    if (!printed) {
        console.log('\n' + (signature || require('./static').signature.cyan));
        var caption = signature ?
            'powered by telegram.link' :
            ('v.' + require('../package.json').version);
        console.log(caption.gray + '\n');
        printed = true;
    }
    return module.exports;
};

// ***

// This module is the entry-point of the **Telegram.link** library and provides the highest-level **interface**
// to communicate with the **Telegram** data-center. When you write your _telegram-like-app_ you
// should deal only with this module.

// You can import the module as follows:

//      var telegramLink = require('telegram.link')();

// ***
// **Function:** telegramLink.**createClient(appId, primaryDC, [options], [connectionListener])**

// Creates the Client and connects to the supplied primary Telegram data center address.

// When the Client connection is established the `connect` event will be emitted.

// Usage example:

//      var client = telegramLink.createClient(
//          {
//              id: 12345,
//              hash: 'q1w2e3r4t5y6u7i8o9p0',
//              version: 'x.y.z',
//              lang: 'xx'
//              [, authKey]
//              [, connectionType: 'TCP']
//          },
//          primaryDC
//          [, function(ex){
//                  if(!ex) { console.log('Connected to Telegram!'); }
//              }]
//      );

// - **app**: are all the application info:
//      - **id** and **hash** _(required)_: you can get it your own APP ID at https://core.telegram.org/myapp
//      - **version** _(required)_: semver of your application, see http://semver.org
//      - **langCode** _(required)_: device/user language, see ISO 639-1
//      - **deviceModel** _(required)_: the device model or the user agent
//      - **systemVersion** _(required)_: the operative system version
//      - **authKey** _(optional)_: the authentication key, already persisted by your app, can be supplied here. The `authKeyCreate`
//       event will be emitted when the connection will be established, after the the `connect` event
//      - **connectionType** _(optional)_: the value could be `HTTP` or `TCP`, HTTP is by default
// - **dataCenter** _(required)_: the data center address, you could use `telegramLink.TEST_PRIMARY_DC` or
// `telegramLink.PROD_PRIMARY_DC`
// - **connectionListener** _(optional)_: a callback function, it will be registered as listener on `connect` event

// The code:
function createClient(app, dataCenter, callback) {
    var client = new Client(app, dataCenter);
    if (callback) {
        client.once('connect', callback);
    }
    connect.apply(client);
    return client;
}


// ***
// **Class:** telegramLink.**Client**

// Represents the connection client to Telegram and implements the Telegram API.

// It must be created by the `createClient()` method above and the following constructor
// cannot be called directly _(private)_.

// The code :
function Client(app, dataCenter) {
    this._app = app;

    if ('TCP' === app.connectionType) {
        this._connection = new net.TcpConnection(dataCenter);
    } else {
        this._connection = new net.HttpConnection(dataCenter);
    }

    if (app.authKey) {
        this._channel = createEncryptedChannel(this._connection, app, app.authKey, NULL_SERVER_SALT);
    }
}
// Extend the `events.EventEmitter` class
require('util').inherits(Client, require('events').EventEmitter);

// ***
// _createEncryptedChannel()_

// Creates the encrypted channel used to call all the Telegram API methods _(private)_

// The code:
function createEncryptedChannel(connection, app, authKey, serverSalt) {
    return new net.EncryptedRpcChannel(
        connection, {
            authKey: authKey,
            serverSalt: serverSalt,
            sessionId: utility.createNonce(8),
            sequenceNumber: new SequenceNumber()
        }, app
    );
}

// ***
// client.**createAuthKey([callback])**

// Exchanges the authorization key with Telegram, see https://core.telegram.org/mtproto/auth_key

// This method is asynchronous and the client must be already connected before calling this function.
// When the authKey is created, the `authKeyCreate` event will be emitted.

// The last parameter callback will be added as a listener for the `authKeyCreate` event, the callback
// could receive the following arguments:
// - **error**: the error if an exception occurs, null otherwise.
// - **authKey**: the authentication key exchanged with Telegram

// The code:
Client.prototype.createAuthKey = function (callback) {
    if (callback) {
        this.once('authKeyCreate', function (auth) {
            this._channel = createEncryptedChannel(this._connection, this._app, auth.key, auth.serverSalt);
            callback(auth);
        });
    }
    if (this._connection && this._connection.isConnected()) {
        auth.createAuthKey(
            createEventEmitterCallback('authKeyCreate').bind(this),
            new net.RpcChannel(this._connection));
    } else {
        var msg = 'Client is not yet connected! Wait until it\'s connected before call this method!';
        logger.error(msg);
        this.emit('error', new Error(msg));
    }
};


// ***
// client.**getDataCenterList([callback])**

// Gets the data center list, the current data center and the nearest one<commit_msg>Add the encrypted import/export of the authKey<commit_after>//     telegram.link
//     Copyright 2014 <NAME> '<EMAIL>'
//     Released under the MIT License
//     http://telegram.link


// ***

// Dependencies:
var tl = require('telegram-tl-node');
var mt = require('telegram-mt-node');
var auth = mt.auth;
var utility = mt.utility;
var net = mt.net;
var api = require('./api');
var SequenceNumber = mt.SequenceNumber;
var logger = require('get-log')('telegram-link');

// Constants
var NULL_SERVER_SALT = '0x0000000000000000';

// ***

// Print the library version
require('colors');
var printed = false;
module.exports = exports = function (signature) {
    if (!printed) {
        console.log('\n' + (signature || require('./static').signature.cyan));
        var caption = signature ?
            'powered by telegram.link' :
            ('v.' + require('../package.json').version);
        console.log(caption.gray + '\n');
        printed = true;
    }
    return module.exports;
};

// ***

// This module is the entry-point of the **Telegram.link** library and provides the highest-level **interface**
// to communicate with the **Telegram** data-center. When you write your _telegram-like-app_ you
// should deal only with this module.

// You can import the module as follows:

//      var telegramLink = require('telegram.link')();

// ***
// **Function:** telegramLink.**createClient(appId, primaryDC, [options], [connectionListener])**

// Creates the Client and connects to the supplied primary Telegram data center address.

// When the Client connection is established the `connect` event will be emitted.

// Usage example:

//      var client = telegramLink.createClient(
//          {
//              id: 12345,
//              hash: 'q1w2e3r4t5y6u7i8o9p0',
//              version: 'x.y.z',
//              lang: 'xx'
//              [, authKey]
//              [, connectionType: 'TCP']
//          },
//          primaryDC
//          [, function(ex){
//                  if(!ex) { console.log('Connected to Telegram!'); }
//              }]
//      );

// - **app**: are all the application info:
//      - **id** and **hash** _(required)_: you can get it your own APP ID at https://core.telegram.org/myapp
//      - **version** _(required)_: semver of your application, see http://semver.org
//      - **langCode** _(required)_: device/user language, see ISO 639-1
//      - **deviceModel** _(required)_: the device model or the user agent
//      - **systemVersion** _(required)_: the operative system version
//      - **authKey** _(optional)_: the authentication key, already persisted by your app, can be supplied here. The `authKeyCreate`
//       event will be emitted when the connection will be established, after the the `connect` event
//      - **authKeyBuffer** && **authKeyPassword** _(optional)_: the authentication key buffer to decrypt with the password
//      - **connectionType** _(optional)_: the value could be `HTTP` or `TCP`, HTTP is by default
// - **dataCenter** _(required)_: the data center address, you could use `telegramLink.TEST_PRIMARY_DC` or
// `telegramLink.PROD_PRIMARY_DC`
// - **connectionListener** _(optional)_: a callback function, it will be registered as listener on `connect` event

// The code:
function createClient(app, dataCenter, callback) {
    var client = new Client(app, dataCenter);
    if (callback) {
        client.once('connect', callback);
    }
    connect.apply(client);
    return client;
}


// ***
// **Class:** telegramLink.**Client**

// Represents the connection client to Telegram and implements the Telegram API.

// It must be created by the `createClient()` method above and the following constructor
// cannot be called directly _(private)_.

// The code :
function Client(app, dataCenter) {
    this._app = app;

    if ('TCP' === app.connectionType) {
        this._connection = new net.TcpConnection(dataCenter);
    } else {
        this._connection = new net.HttpConnection(dataCenter);
    }

    app.authKey = app.authKeyBuffer && app.authKeyPassword ?
        auth.AuthKey.decryptAuthKey(app.authKeyBuffer, app.authKeyPassword) :
        app.authKey;

    if (app.authKey) {
        this._channel = createEncryptedChannel(this._connection, app, app.authKey, NULL_SERVER_SALT);
    }
}
// Extend the `events.EventEmitter` class
require('util').inherits(Client, require('events').EventEmitter);

// ***
// _createEncryptedChannel()_

// Creates the encrypted channel used to call all the Telegram API methods _(private)_

// The code:
function createEncryptedChannel(connection, app, authKey, serverSalt) {
    return new net.EncryptedRpcChannel(
        connection, {
            authKey: authKey,
            serverSalt: serverSalt,
            sessionId: utility.createNonce(8),
            sequenceNumber: new SequenceNumber()
        }, app
    );
}

// ***
// client.**createAuthKey([callback])**

// Exchanges the authorization key with Telegram, see https://core.telegram.org/mtproto/auth_key

// This method is asynchronous and the client must be already connected before calling this function.
// When the authKey is created, the `authKeyCreate` event will be emitted.

// The last parameter callback will be added as a listener for the `authKeyCreate` event, the callback
// could receive the following arguments:
// - **error**: the error if an exception occurs, null otherwise.
// - **authKey**: the authentication key exchanged with Telegram

// The code:
Client.prototype.createAuthKey = function (callback) {
    if (callback) {
        this.once('authKeyCreate', function (auth) {
            this._channel = createEncryptedChannel(this._connection, this._app, auth.key, auth.serverSalt);
            callback(auth);
        });
    }
    if (this._connection && this._connection.isConnected()) {
        auth.createAuthKey(
            createEventEmitterCallback('authKeyCreate').bind(this),
            new net.RpcChannel(this._connection));
    } else {
        var msg = 'Client is not yet connected! Wait until it\'s connected before call this method!';
        logger.error(msg);
        this.emit('error', new Error(msg));
    }
};

// ***
// client.**exportEncryptedAuthKey(password)**

// Exports an encrypted buffer of the internal authKey using the password.

// The code:
Client.prototype.exportEncryptedAuthKey = function (password) {
    return this._channel ? auth.AuthKey.encryptAuthKey(this._channel._context.authKey, password) : null;
}


// ***
// client.**getDataCenterList([callback])**

// Gets the data center list, the current data center and the nearest one
{'fraction_non_alphanumeric': 0.1354813046937152, 'fraction_numerical': 0.0065234685759745425, 'mean_word_length': 2.919862800124727, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1029893', 'n_tokens_mistral': 3577, 'n_tokens_neox': 3459, 'n_words': 1105}