Skip to content

Commit

Permalink
Add the telegram-mt-node dependency
Browse files Browse the repository at this point in the history
- Remove the `lib` folder under node_modules

- Remove all the tests under ./test/lib

- Move telegram.link.js under ./lib

- Do the code refactoring

- Update the project file and review the project
dependencies

- Update the build file

- Update the travis config file

- Update the version to 0.2.0
  • Loading branch information
enricostara committed Nov 28, 2014
1 parent d360a1f commit 5d4fcd9
Show file tree
Hide file tree
Showing 18 changed files with 81 additions and 1,580 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ language: node_js
node_js:
- "0.10"
after_script:
- npm run zuul
- npm run coveralls
env:
global:
Expand Down
38 changes: 10 additions & 28 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,26 @@ var mocha = require('gulp-mocha');
var docco = require('gulp-docco');
var del = require('del');

gulp.task('docs-api', function () {
gulp.task('docs', function () {
del(['./docs/api'], function() {
gulp.src('telegram.link.js')
gulp.src('./lib/**')
.pipe(docco({'layout': 'linear'}))
.pipe(gulp.dest('./docs/api'))
.pipe(gulp.dest('./docs/api'));
});
});

gulp.task('quality-lib', function () {
return gulp.src('node_modules/lib/**/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
});
gulp.task('quality-api', function () {
return gulp.src('telegram.link.js')
gulp.task('quality', function () {
return gulp.src('../lib/**')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(jshint.reporter('default'));
});

gulp.task('test-lib', function () {
return gulp.src('./test/lib/**/*.js')
.pipe(mocha({reporter: 'mocha-better-spec-reporter', timeout: '10s'}));
});
gulp.task('test-api', function () {
gulp.task('test', function () {
return gulp.src('./test/*.js')
.pipe(mocha({reporter: 'mocha-better-spec-reporter', timeout: '10s'}));
.pipe(mocha({reporter: 'mocha-better-spec-reporter', timeout: '20s'}));
});

gulp.task('cov-test-lib', function () {
return gulp.src('./test/lib/**/*.js')
.pipe(mocha({reporter: 'mocha-lcov-reporter', timeout: '120s'}));
});
gulp.task('cov-test-api', function () {
gulp.task('cover', function () {
return gulp.src('./test/*.js')
.pipe(mocha({reporter: 'mocha-lcov-reporter', timeout: '120s'}));
});

gulp.task('default', ['quality', 'test-lib']);
gulp.task('quality', ['quality-lib', 'quality-api']);
gulp.task('test', ['quality', 'test-lib', 'test-api']);
gulp.task('cover', ['cov-test-lib', 'cov-test-api']);
gulp.task('default', ['quality', 'test']);
2 changes: 1 addition & 1 deletion node_modules/lib/static.js → lib/static.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ exports.telegram = {
};

// Register `Telegram Messanger` public keys
var PublicKey = require('./crypto-util/public-key');
var PublicKey = require('telegram-mt-node').security.PublicKey;
PublicKey.addKey({
fingerprint: '0x9a996a1db11c729b',
modulus: 'c6aeda78b02a251db4b6441031f467fa871faed32526c436524b1fb3b5dca28efb8c089dd1b46d92c895993d87108254951c5f001a0f055f3063dcd14d431a300eb9e29517e359a1c9537e5e87ab1b116faecf5d17546ebc21db234d9d336a693efcb2b6fbcca1e7d1a0be414dca408a11609b9c4269a920b09fed1f9a1597be02761430f09e4bc48fcafbe289054c99dba51b6b5eb7d9c3a2ab4e490545b4676bd620e93804bcac93bf94f73f92c729ca899477ff17625ef14a934d51dc11d5f8650a3364586b3a52fcff2fedec8a8406cac4e751705a472e55707e3c8cd5594342b119c6c3293532d85dbe9271ed54a2fd18b4dc79c04a30951107d5639397',
Expand Down
114 changes: 52 additions & 62 deletions telegram.link.js → lib/telegram.link.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,33 @@
// with `TELEGRAM MESSANGER`

// Print library version
console.log(require('lib/static').signature);
console.log(('v.%s', require('./package.json').version));
console.log(require('./static').signature);
console.log('v.%s', require('../package.json').version);

// Register the project name on the logging sys
var getLogger = require('get-log');
getLogger.PROJECT_NAME = require('./package.json').name;
getLogger.PROJECT_NAME = require('../package.json').name;

// Export the class
module.exports = exports = TelegramLink;

// Import dependencies
var crypto = require('lib/crypto-util');
var TcpConnection = require('lib/net').TcpConnection;
var HttpConnection = require('lib/net').HttpConnection;
var TypeObject = require('telegram-tl-node').TypeObject;
var mtproto = require('lib/mtproto');
var mtproto = require('telegram-mt-node');
var flow = require('get-flow');
var TcpConnection = mtproto.net.TcpConnection;
var HttpConnection = mtproto.net.HttpConnection;
var utility = mtproto.utility;
var security = mtproto.security;


// The constructor requires a primary telegram DataCenter address as argument
function TelegramLink(primaryDC) {
// this._connection = new TcpConnection(primaryDC);
this._connection = new HttpConnection({
proxyHost: process.env.PROXY_HOST,
proxyPort: process.env.PROXY_PORT,
host: primaryDC.host,
port: primaryDC.port
});
function TelegramLink(primaryDC, connectionType) {
if (connectionType && 'TCP' === connectionType) {
this._connection = new TcpConnection(primaryDC);
} else {
this._connection = new HttpConnection(primaryDC);
}
}

// The method creates a connection to the DataCenter,
Expand Down Expand Up @@ -72,8 +72,8 @@ TelegramLink.prototype.authorization = function (callback) {
// Request a PQ pair number
function requestPQ(callback) {
// Create a nonce for the client
var clientNonce = crypto.createNonce(16);
mtproto.req_pq({
var clientNonce = utility.createNonce(16);
mtproto.service.req_pq({
props: {
nonce: clientNonce
},
Expand All @@ -90,7 +90,7 @@ TelegramLink.prototype.authorization = function (callback) {

// Find the P and Q prime numbers
function findPAndQ(resPQ) {
var pqFinder = new crypto.PQFinder(resPQ.pq);
var pqFinder = new security.PQFinder(resPQ.pq);
if (logger.isDebugEnabled()) logger.debug('Start finding P and Q, with PQ = %s', pqFinder.getPQPairNumber());
var pq = pqFinder.findPQ();
if (logger.isDebugEnabled()) logger.debug('Found P = %s and Q = %s', pq[0], pq[1]);
Expand All @@ -108,7 +108,7 @@ TelegramLink.prototype.authorization = function (callback) {
for (var i = 0; i < fingerprints.length; i++) {
var fingerprint = fingerprints[i];
if (logger.isDebugEnabled()) logger.debug('Searching fingerprint %s in store', fingerprint);
var publicKey = crypto.PublicKey.retrieveKey(fingerprint);
var publicKey = security.PublicKey.retrieveKey(fingerprint);
if (publicKey) {
if (logger.isDebugEnabled()) logger.debug('Fingerprint %s found in keyStore.', fingerprint);
obj.fingerprint = fingerprint;
Expand All @@ -122,8 +122,8 @@ TelegramLink.prototype.authorization = function (callback) {
// Create the pq_inner_data buffer
function createPQInnerData(obj) {
var resPQ = obj.resPQ;
var newNonce = crypto.createNonce(32);
var pqInnerData = new mtproto.P_q_inner_data({props: {
var newNonce = utility.createNonce(32);
var pqInnerData = new mtproto.type.P_q_inner_data({props: {
pq: resPQ.pq,
p: obj.pBuffer,
q: obj.qBuffer,
Expand All @@ -139,21 +139,20 @@ TelegramLink.prototype.authorization = function (callback) {
// Encrypt the pq_inner_data with RSA
function encryptPQInnerDataWithRSA(obj) {
// Create the data with hash to be encrypt
var hash = crypto.createSHA1Hash(obj.pqInnerData);
var hash = utility.createSHA1Hash(obj.pqInnerData);
var dataWithHash = Buffer.concat([hash, obj.pqInnerData]);
if (logger.isDebugEnabled()) {
logger.debug('Data to be encrypted contains: hash(%s), pqInnerData(%s), total length %s',
hash.length, obj.pqInnerData.length, dataWithHash.length);
}
if (logger.isDebugEnabled()) logger.debug('Data to be encrypted contains: ' +
'hash(%s), pqInnerData(%s), total length %s',
hash.length, obj.pqInnerData.length, dataWithHash.length);
// Encrypt data with RSA
obj.encryptedData = crypto.rsaEncrypt({message: dataWithHash, key: obj.publicKey});
obj.encryptedData = security.cipher.rsaEncrypt(dataWithHash, obj.publicKey);
return obj;
}

// Request server DH parameters
function requestDHParams(callback, obj) {
var resPQ = obj.resPQ;
mtproto.req_DH_params({
mtproto.service.req_DH_params({
props: {
nonce: resPQ.nonce,
server_nonce: resPQ.server_nonce,
Expand All @@ -168,11 +167,11 @@ TelegramLink.prototype.authorization = function (callback) {
logger.error(ex);
if (callback) callback(ex);
} else {
if (serverDHParams.typeName == 'mtproto.Server_DH_params_ok') {
if (serverDHParams.typeName == 'mtproto.type.Server_DH_params_ok') {
if (logger.isDebugEnabled()) logger.debug('\'Server_DH_params_ok\' received from Telegram.');
obj.serverDHParams = serverDHParams;
callback(null, obj, duration);
} else if (serverDHParams.typeName == 'mtproto.Server_DH_params_ko') {
} else if (serverDHParams.typeName == 'mtproto.type.Server_DH_params_ko') {
logger.warn('\'Server_DH_params_ko\' received from Telegram!');
callback(createError(JSON.stringify(serverDHParams), 'EDHPARAMKO'));
} else {
Expand All @@ -189,23 +188,17 @@ TelegramLink.prototype.authorization = function (callback) {
function decryptDHParams(obj, duration) {
var newNonce = TypeObject.stringValue2Buffer(obj.newNonce, 32);
var serverNonce = TypeObject.stringValue2Buffer(obj.resPQ.server_nonce, 16);
if (logger.isDebugEnabled()) {
logger.debug('newNonce = %s, serverNonce = %s', newNonce.toString('hex'), serverNonce.toString('hex'));
}
var hashNS = crypto.createSHA1Hash([newNonce, serverNonce]);
var hashSN = crypto.createSHA1Hash([serverNonce, newNonce]);
var hashNN = crypto.createSHA1Hash([newNonce, newNonce]);
if (logger.isDebugEnabled()) {
logger.debug('hashNS = %s, hashSN = %s, hashNN = %s', hashNS.toString('hex'), hashSN.toString('hex'), hashNN.toString('hex'));
}
if (logger.isDebugEnabled()) logger.debug('newNonce = %s, serverNonce = %s', newNonce.toString('hex'), serverNonce.toString('hex'));
var hashNS = utility.createSHA1Hash([newNonce, serverNonce]);
var hashSN = utility.createSHA1Hash([serverNonce, newNonce]);
var hashNN = utility.createSHA1Hash([newNonce, newNonce]);
if (logger.isDebugEnabled()) logger.debug('hashNS = %s, hashSN = %s, hashNN = %s', hashNS.toString('hex'), hashSN.toString('hex'), hashNN.toString('hex'));
// Create the AES key
var aesKey = Buffer.concat([hashNS, hashSN.slice(0, 12)]);
var aesIv = Buffer.concat([Buffer.concat([hashSN.slice(12), hashNN]), newNonce.slice(0, 4)]);
if (logger.isDebugEnabled()) {
logger.debug('aesKey = %s, aesIv = %s', aesKey.toString('hex'), aesIv.toString('hex'));
}
if (logger.isDebugEnabled()) logger.debug('aesKey = %s, aesIv = %s', aesKey.toString('hex'), aesIv.toString('hex'));
// Decrypt the message
var answerWithHash = crypto.aesDecrypt(
var answerWithHash = security.cipher.aesDecrypt(
obj.serverDHParams.encrypted_answer,
aesKey,
aesIv
Expand All @@ -216,7 +209,7 @@ TelegramLink.prototype.authorization = function (callback) {
if (logger.isDebugEnabled()) logger.debug('answerWithHash(%s) = %s', answerWithHash.length, answerWithHash.toString('hex'));
var answer = answerWithHash.slice(20, 564 + 20);
if (logger.isDebugEnabled()) logger.debug('answer(%s) = %s', answer.length, answer.toString('hex'));
var serverDHInnerData = new mtproto.Server_DH_inner_data({
var serverDHInnerData = new mtproto.type.Server_DH_inner_data({
buffer: answer
}).deserialize();
if (logger.isDebugEnabled()) logger.debug('serverDHInnerData = %s obtained in %sms', JSON.stringify(serverDHInnerData), duration);
Expand All @@ -228,7 +221,7 @@ TelegramLink.prototype.authorization = function (callback) {
throw createError('ServerNonce mismatch %s != %s', obj.serverDHParams.server_nonce, serverDHInnerData.server_nonce);
}
// Synch the local time with the server time
crypto.timeSynchronization(serverDHInnerData.server_time * 1000, duration);
mtproto.time.timeSynchronization(serverDHInnerData.server_time * 1000, duration);
obj.serverDHInnerData = serverDHInnerData;
return obj;
}
Expand All @@ -240,12 +233,12 @@ TelegramLink.prototype.authorization = function (callback) {
if (logger.isDebugEnabled()) logger.debug('Start calculating g_b');
// Calculate g_b
var g = obj.serverDHInnerData.g;
var b = crypto.createNonce(256);
var b = utility.createNonce(256);
var dhPrime = obj.serverDHInnerData.dh_prime;
var gb = crypto.modPow(g, b, dhPrime);
var gb = utility.modPow(g, b, dhPrime);
if (logger.isDebugEnabled()) logger.debug('g_b(%s) = %s', gb.length, gb.toString('hex'));
// Create client DH inner data
obj.clientDHInnerData = new mtproto.Client_DH_inner_data({props: {
obj.clientDHInnerData = new mtproto.type.Client_DH_inner_data({props: {
nonce: obj.resPQ.nonce,
server_nonce: obj.resPQ.server_nonce,
retry_id: retryCount,
Expand All @@ -256,27 +249,24 @@ TelegramLink.prototype.authorization = function (callback) {

// Encrypt Client DH inner data
function encryptClientDHInnerDataWithAES(obj) {
var hash = crypto.createSHA1Hash(obj.clientDHInnerData);
var hash = utility.createSHA1Hash(obj.clientDHInnerData);
var dataWithHash = Buffer.concat([hash, obj.clientDHInnerData]);
if (logger.isDebugEnabled()) {
logger.debug('Data to be encrypted contains: hash(%s), clientDHInnerData(%s), total length %s',
hash.length, obj.clientDHInnerData.length, dataWithHash.length);
}
obj.encryptClientDHInnerData = crypto.aesEncrypt(
if (logger.isDebugEnabled()) logger.debug('Data to be encrypted contains: ' +
'hash(%s), clientDHInnerData(%s), total length %s',
hash.length, obj.clientDHInnerData.length, dataWithHash.length);
obj.encryptClientDHInnerData = security.cipher.aesEncrypt(
dataWithHash,
obj.aes.key,
obj.aes.iv
);
if (logger.isDebugEnabled()) {
logger.debug('encryptClientDHInnerData(%s) = %s',
obj.encryptClientDHInnerData.length, obj.encryptClientDHInnerData.toString('hex'));
}
if (logger.isDebugEnabled()) logger.debug('encryptClientDHInnerData(%s) = %s',
obj.encryptClientDHInnerData.length, obj.encryptClientDHInnerData.toString('hex'));
return obj;
}

// Set client DH parameters
function setClientDHParams(callback, obj) {
mtproto.set_client_DH_params({
mtproto.service.set_client_DH_params({
props: {
nonce: obj.resPQ.nonce,
server_nonce: obj.resPQ.server_nonce,
Expand All @@ -288,14 +278,14 @@ TelegramLink.prototype.authorization = function (callback) {
logger.error(ex);
if (callback) callback(ex);
} else {
if (setClientDHParamsAnswer.typeName == 'mtproto.Dh_gen_ok') {
if (setClientDHParamsAnswer.typeName == 'mtproto.type.Dh_gen_ok') {
if (logger.isDebugEnabled()) logger.debug('\'Dh_gen_ok\' received from Telegram.');
obj.setClientDHParamsAnswer = setClientDHParamsAnswer;
callback(null, obj, duration);
} else if (setClientDHParamsAnswer.typeName == 'mtproto.Dh_gen_retry') {
} else if (setClientDHParamsAnswer.typeName == 'mtproto.type.Dh_gen_retry') {
logger.warn('\'Dh_gen_retry\' received from Telegram!');
callback(createError(JSON.stringify(serverDHParams), 'EDHPARAMRETRY'));
} else if (setClientDHParamsAnswer.typeName == 'mtproto.Dh_gen_fail') {
} else if (setClientDHParamsAnswer.typeName == 'mtproto.type.Dh_gen_fail') {
logger.warn('\'Dh_gen_fail\' received from Telegram!');
callback(createError(JSON.stringify(serverDHParams), 'EDHPARAMFAIL'));
} else {
Expand Down
Loading

0 comments on commit 5d4fcd9

Please sign in to comment.