Fixed periodical 'Connecting...' problem.

Also fixed safari arraybufferview warning
Closes #1551
Closes #1538
This commit is contained in:
Igor Zhukov 2017-12-08 23:29:40 +04:00
parent 550f8ae781
commit 237b3990b0
4 changed files with 10499 additions and 102 deletions

View File

@ -60,21 +60,83 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
/** /**
* Server public key, obtained from here: https://core.telegram.org/api/obtaining_api_id * Server public key, obtained from here: https://core.telegram.org/api/obtaining_api_id
*
*
* -----BEGIN RSA PUBLIC KEY-----
* MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
* lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
* an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw
* Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
* 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
* Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
* -----END RSA PUBLIC KEY-----
*
* -----BEGIN PUBLIC KEY-----
* MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAruw2yP/BCcsJliRoW5eB
* VBVle9dtjJw+OYED160Wybum9SXtBBLXriwt4rROd9csv0t0OHCaTmRqBcQ0J8fx
* hN6/cpR1GWgOZRUAiQxoMnlt0R93LCX/j1dnVa/gVbCjdSxpbrfY2g2L4frzjJvd
* l84Kd9ORYjDEAyFnEA7dD556OptgLQQ2e2iVNq8NZLYTzLp5YpOdO1doK+ttrltg
* gTCy5SrKeLoCPPbOgGsdxJxyz5KKcZnSLj16yE5HvJQn0CNpRdENvRUXe6tBP78O
* 39oJ8BTHp9oIjd6XWXAsp2CvK45Ol8wFXGF710w9lwCGNbmNxNYhtIkdqfsEcwR5
* JwIDAQAB
* -----END PUBLIC KEY-----
*
* -----BEGIN PUBLIC KEY-----
* MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvfLHfYH2r9R70w8prHbl
* Wt/nDkh+XkgpflqQVcnAfSuTtO05lNPspQmL8Y2XjVT4t8cT6xAkdgfmmvnvRPOO
* KPi0OfJXoRVylFzAQG/j83u5K3kRLbae7fLccVhKZhY46lvsueI1hQdLgNV9n1cQ
* 3TDS2pQOCtovG4eDl9wacrXOJTG2990VjgnIKNA0UMoP+KF03qzryqIt3oTvZq03
* DyWdGK+AZjgBLaDKSnC6qD2cFY81UryRWOab8zKkWAnhw2kFpcqhI0jdV5QaSCEx
* vnsjVaX0Y1N0870931/5Jb9ICe4nweZ9kSDF/gip3kWLG0o8XQpChDfyvsqB9OLV
* /wIDAQAB
* -----END PUBLIC KEY-----
*
* -----BEGIN PUBLIC KEY-----
* MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/ditzm+mPND6xkhzwFI
* z6J/968CtkcSE/7Z2qAJiXbmZ3UDJPGrzqTDHkO30R8VeRM/Kz2f4nR05GIFiITl
* 4bEjvpy7xqRDspJcCFIOcyXm8abVDhF+th6knSU0yLtNKuQVP6voMrnt9MV1X92L
* GZQLgdHZbPQz0Z5qIpaKhdyA8DEvWWvSUwwc+yi1/gGaybwlzZwqXYoPOhwMebzK
* Uk0xW14htcJrRrq+PXXQbRzTMynseCoPIoke0dtCodbA3qQxQovE16q9zz4Otv2k
* 4j63cz53J+mhkVWAeWxVGI0lltJmWtEYK6er8VqqWot3nqmWMXogrgRLggv/Nbbo
* oQIDAQAB
* -----END PUBLIC KEY-----
*
* -----BEGIN PUBLIC KEY-----
* MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvmpxVY7ld/8DAjz6F6q0
* 5shjg8/4p6047bn6/m8yPy1RBsvIyvuDuGnP/RzPEhzXQ9UJ5Ynmh2XJZgHoE9xb
* nfxL5BXHplJhMtADXKM9bWB11PU1Eioc3+AXBB8QiNFBn2XI5UkO5hPhbb9mJpjA
* 9Uhw8EdfqJP8QetVsI/xrCEbwEXe0xvifRLJbY08/Gp66KpQvy7g8w7VB8wlgePe
* xW3pT13Ap6vuC+mQuJPyiHvSxjEKHgqePji9NP3tJUFQjcECqcm0yV7/2d0t/pbC
* m+ZH1sadZspQCEPPrtbkQBlvHb4OLiIWPGHKSMeRFvp3IWcmdJqXahxLCUS1Eh6M
* AQIDAQAB
* -----END PUBLIC KEY-----
* *
* -----BEGIN RSA PUBLIC KEY----- * Bytes can be got via
* MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6 * $ openssl rsa -pubin -in key.pub -text -noout
* lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
* an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw
* Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
* 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
* Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
* -----END RSA PUBLIC KEY-----
*/ */
var publisKeysHex = [{ var publisKeysHex = [
modulus: 'c150023e2f70db7985ded064759cfecf0af328e69a41daf4d6f01b538135a6f91f8f8b2a0ec9ba9720ce352efcf6c5680ffc424bd634864902de0b4bd6d49f4e580230e3ae97d95c8b19442b3c0a10d8f5633fecedd6926a7f6dab0ddb7d457f9ea81b8465fcd6fffeed114011df91c059caedaf97625f6c96ecc74725556934ef781d866b34f011fce4d835a090196e9a5f0e4449af7eb697ddb9076494ca5f81104a305b6dd27665722c46b60e5df680fb16b210607ef217652e60236c255f6a28315f4083a96791d7214bf64c1df4fd0db1944fb26a2a57031b32eee64ad15a8ba68885cde74a5bfc920f6abf59ba5c75506373e7130f9042da922179251f', {
exponent: '010001' modulus: 'c150023e2f70db7985ded064759cfecf0af328e69a41daf4d6f01b538135a6f91f8f8b2a0ec9ba9720ce352efcf6c5680ffc424bd634864902de0b4bd6d49f4e580230e3ae97d95c8b19442b3c0a10d8f5633fecedd6926a7f6dab0ddb7d457f9ea81b8465fcd6fffeed114011df91c059caedaf97625f6c96ecc74725556934ef781d866b34f011fce4d835a090196e9a5f0e4449af7eb697ddb9076494ca5f81104a305b6dd27665722c46b60e5df680fb16b210607ef217652e60236c255f6a28315f4083a96791d7214bf64c1df4fd0db1944fb26a2a57031b32eee64ad15a8ba68885cde74a5bfc920f6abf59ba5c75506373e7130f9042da922179251f',
}] exponent: '010001'
},
{
modulus: 'aeec36c8ffc109cb099624685b97815415657bd76d8c9c3e398103d7ad16c9bba6f525ed0412d7ae2c2de2b44e77d72cbf4b7438709a4e646a05c43427c7f184debf72947519680e651500890c6832796dd11f772c25ff8f576755afe055b0a3752c696eb7d8da0d8be1faf38c9bdd97ce0a77d3916230c4032167100edd0f9e7a3a9b602d04367b689536af0d64b613ccba7962939d3b57682beb6dae5b608130b2e52aca78ba023cf6ce806b1dc49c72cf928a7199d22e3d7ac84e47bc9427d0236945d10dbd15177bab413fbf0edfda09f014c7a7da088dde9759702ca760af2b8e4e97cc055c617bd74c3d97008635b98dc4d621b4891da9fb0473047927',
exponent: '010001'
},
{
modulus: 'bdf2c77d81f6afd47bd30f29ac76e55adfe70e487e5e48297e5a9055c9c07d2b93b4ed3994d3eca5098bf18d978d54f8b7c713eb10247607e69af9ef44f38e28f8b439f257a11572945cc0406fe3f37bb92b79112db69eedf2dc71584a661638ea5becb9e23585074b80d57d9f5710dd30d2da940e0ada2f1b878397dc1a72b5ce2531b6f7dd158e09c828d03450ca0ff8a174deacebcaa22dde84ef66ad370f259d18af806638012da0ca4a70baa83d9c158f3552bc9158e69bf332a45809e1c36905a5caa12348dd57941a482131be7b2355a5f4635374f3bd3ddf5ff925bf4809ee27c1e67d9120c5fe08a9de458b1b4a3c5d0a428437f2beca81f4e2d5ff',
exponent: '010001'
},
{
modulus: 'b3f762b739be98f343eb1921cf0148cfa27ff7af02b6471213fed9daa0098976e667750324f1abcea4c31e43b7d11f1579133f2b3d9fe27474e462058884e5e1b123be9cbbc6a443b2925c08520e7325e6f1a6d50e117eb61ea49d2534c8bb4d2ae4153fabe832b9edf4c5755fdd8b19940b81d1d96cf433d19e6a22968a85dc80f0312f596bd2530c1cfb28b5fe019ac9bc25cd9c2a5d8a0f3a1c0c79bcca524d315b5e21b5c26b46babe3d75d06d1cd33329ec782a0f22891ed1db42a1d6c0dea431428bc4d7aabdcf3e0eb6fda4e23eb7733e7727e9a1915580796c55188d2596d2665ad1182ba7abf15aaa5a8b779ea996317a20ae044b820bff35b6e8a1',
exponent: '010001'
},
{
modulus: 'be6a71558ee577ff03023cfa17aab4e6c86383cff8a7ad38edb9fafe6f323f2d5106cbc8cafb83b869cffd1ccf121cd743d509e589e68765c96601e813dc5b9dfc4be415c7a6526132d0035ca33d6d6075d4f535122a1cdfe017041f1088d1419f65c8e5490ee613e16dbf662698c0f54870f0475fa893fc41eb55b08ff1ac211bc045ded31be27d12c96d8d3cfc6a7ae8aa50bf2ee0f30ed507cc2581e3dec56de94f5dc0a7abee0be990b893f2887bd2c6310a1e0a9e3e38bd34fded2541508dc102a9c9b4c95effd9dd2dfe96c29be647d6c69d66ca500843cfaed6e440196f1dbe0e2e22163c61ca48c79116fa77216726749a976a1c4b0944b5121e8c01',
exponent: '010001'
}
]
var publicKeysParsed = {} var publicKeysParsed = {}
var prepared = false var prepared = false
@ -180,7 +242,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpTimeManager, CryptoWorker, $http, $q, $timeout) { .factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpTimeManager, CryptoWorker, $http, $q, $timeout) {
var chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/) var chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/)
var chromeVersion = chromeMatches && parseFloat(chromeMatches[1]) || false var chromeVersion = chromeMatches && parseFloat(chromeMatches[1]) || false
var xhrSendBuffer = !('ArrayBufferView' in window) && (!chromeVersion || chromeVersion < 30) var xhrSendBuffer = !('ArrayBufferView' in window) && (chromeVersion > 0 && chromeVersion < 30)
delete $http.defaults.headers.post['Content-Type'] delete $http.defaults.headers.post['Content-Type']
delete $http.defaults.headers.common['Accept'] delete $http.defaults.headers.common['Accept']
@ -411,7 +473,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
function mtpVerifyDhParams(g, dhPrime, gA) { function mtpVerifyDhParams(g, dhPrime, gA) {
console.log(dT(), 'Verifying DH params') console.log(dT(), 'Verifying DH params')
var dhPrimeHex = bytesToHex(dhPrime); var dhPrimeHex = bytesToHex(dhPrime)
if (g != 3 || if (g != 3 ||
dhPrimeHex !== 'c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b') { dhPrimeHex !== 'c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b') {
// The verified value is from https://core.telegram.org/mtproto/security_guidelines // The verified value is from https://core.telegram.org/mtproto/security_guidelines
@ -597,7 +659,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var akStopped = false var akStopped = false
var chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/) var chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/)
var chromeVersion = chromeMatches && parseFloat(chromeMatches[1]) || false var chromeVersion = chromeMatches && parseFloat(chromeMatches[1]) || false
var xhrSendBuffer = !('ArrayBufferView' in window) && (!chromeVersion || chromeVersion < 30) var xhrSendBuffer = !('ArrayBufferView' in window) && (chromeVersion > 0 && chromeVersion < 30)
delete $http.defaults.headers.post['Content-Type'] delete $http.defaults.headers.post['Content-Type']
delete $http.defaults.headers.common['Accept'] delete $http.defaults.headers.common['Accept']
@ -837,8 +899,8 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
}).then(function () { }).then(function () {
delete self.longPollPending delete self.longPollPending
setZeroTimeout(self.checkLongPoll.bind(self)) setZeroTimeout(self.checkLongPoll.bind(self))
}, function () { }, function (error) {
console.log('Long-poll failed') console.log('Long-poll failed', error)
}) })
} }
@ -874,48 +936,44 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
this.sheduleRequest(delay) this.sheduleRequest(delay)
} }
MtpNetworker.prototype.getMsgKeyIv = function (msgKey, isOut) { MtpNetworker.prototype.getMsgKey = function (dataWithPadding, isOut) {
var authKey = this.authKeyUint8 var authKey = this.authKeyUint8
var x = isOut ? 0 : 8 var x = isOut ? 0 : 8
var sha1aText = new Uint8Array(48) var msgKeyLargePlain = bufferConcat(authKey.subarray(88 + x, 88 + x + 32), dataWithPadding)
var sha1bText = new Uint8Array(48) return CryptoWorker.sha256Hash(msgKeyLargePlain).then(function (msgKeyLarge) {
var sha1cText = new Uint8Array(48) var msgKey = new Uint8Array(msgKeyLarge).subarray(8, 24)
var sha1dText = new Uint8Array(48) return msgKey
})
}
MtpNetworker.prototype.getAesKeyIv = function (msgKey, isOut) {
var authKey = this.authKeyUint8
var x = isOut ? 0 : 8
var sha2aText = new Uint8Array(52)
var sha2bText = new Uint8Array(52)
var promises = {} var promises = {}
sha1aText.set(msgKey, 0) sha2aText.set(msgKey, 0)
sha1aText.set(authKey.subarray(x, x + 32), 16) sha2aText.set(authKey.subarray(x, x + 36), 16)
promises.sha1a = CryptoWorker.sha1Hash(sha1aText) promises.sha2a = CryptoWorker.sha256Hash(sha2aText)
sha1bText.set(authKey.subarray(x + 32, x + 48), 0) sha2bText.set(authKey.subarray(40 + x, 40 + x + 36), 0)
sha1bText.set(msgKey, 16) sha2bText.set(msgKey, 36)
sha1bText.set(authKey.subarray(x + 48, x + 64), 32) promises.sha2b = CryptoWorker.sha256Hash(sha2bText)
promises.sha1b = CryptoWorker.sha1Hash(sha1bText)
sha1cText.set(authKey.subarray(x + 64, x + 96), 0)
sha1cText.set(msgKey, 32)
promises.sha1c = CryptoWorker.sha1Hash(sha1cText)
sha1dText.set(msgKey, 0)
sha1dText.set(authKey.subarray(x + 96, x + 128), 16)
promises.sha1d = CryptoWorker.sha1Hash(sha1dText)
return $q.all(promises).then(function (result) { return $q.all(promises).then(function (result) {
var aesKey = new Uint8Array(32) var aesKey = new Uint8Array(32)
var aesIv = new Uint8Array(32) var aesIv = new Uint8Array(32)
sha1a = new Uint8Array(result.sha1a), var sha2a = new Uint8Array(result.sha2a)
sha1b = new Uint8Array(result.sha1b), var sha2b = new Uint8Array(result.sha2b)
sha1c = new Uint8Array(result.sha1c),
sha1d = new Uint8Array(result.sha1d)
aesKey.set(sha1a.subarray(0, 8)) aesKey.set(sha2a.subarray(0, 8))
aesKey.set(sha1b.subarray(8, 20), 8) aesKey.set(sha2b.subarray(8, 24), 8)
aesKey.set(sha1c.subarray(4, 16), 20) aesKey.set(sha2a.subarray(24, 32), 24)
aesIv.set(sha1a.subarray(8, 20)) aesIv.set(sha2b.subarray(0, 8))
aesIv.set(sha1b.subarray(0, 8), 12) aesIv.set(sha2a.subarray(8, 24), 8)
aesIv.set(sha1c.subarray(16, 20), 20) aesIv.set(sha2b.subarray(24, 32), 24)
aesIv.set(sha1d.subarray(0, 8), 24)
return [aesKey, aesIv] return [aesKey, aesIv]
}) })
@ -1145,7 +1203,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
this.checkConnectionPeriod = Math.max(1.1, Math.sqrt(this.checkConnectionPeriod)) this.checkConnectionPeriod = Math.max(1.1, Math.sqrt(this.checkConnectionPeriod))
}) })
}, function (error) { }, function (error) {
console.log('Encrypted request failed', error) console.error('Encrypted request failed', error)
if (message.container) { if (message.container) {
angular.forEach(message.inner, function (msgID) { angular.forEach(message.inner, function (msgID) {
@ -1173,16 +1231,12 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
} }
} }
MtpNetworker.prototype.getEncryptedMessage = function (bytes) { MtpNetworker.prototype.getEncryptedMessage = function (dataWithPadding) {
var self = this var self = this
return self.getMsgKey(dataWithPadding, true).then(function (msgKey) {
// console.log(dT(), 'Start encrypt', bytes.byteLength) return self.getAesKeyIv(msgKey, true).then(function (keyIv) {
return CryptoWorker.sha1Hash(bytes).then(function (bytesHash) {
// console.log(dT(), 'after hash')
var msgKey = new Uint8Array(bytesHash).subarray(4, 20)
return self.getMsgKeyIv(msgKey, true).then(function (keyIv) {
// console.log(dT(), 'after msg key iv') // console.log(dT(), 'after msg key iv')
return CryptoWorker.aesEncrypt(bytes, keyIv[0], keyIv[1]).then(function (encryptedBytes) { return CryptoWorker.aesEncrypt(dataWithPadding, keyIv[0], keyIv[1]).then(function (encryptedBytes) {
// console.log(dT(), 'Finish encrypt') // console.log(dT(), 'Finish encrypt')
return { return {
bytes: encryptedBytes, bytes: encryptedBytes,
@ -1195,7 +1249,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
MtpNetworker.prototype.getDecryptedMessage = function (msgKey, encryptedData) { MtpNetworker.prototype.getDecryptedMessage = function (msgKey, encryptedData) {
// console.log(dT(), 'get decrypted start') // console.log(dT(), 'get decrypted start')
return this.getMsgKeyIv(msgKey, false).then(function (keyIv) { return this.getAesKeyIv(msgKey, false).then(function (keyIv) {
// console.log(dT(), 'after msg key iv') // console.log(dT(), 'after msg key iv')
return CryptoWorker.aesDecrypt(encryptedData, keyIv[0], keyIv[1]) return CryptoWorker.aesDecrypt(encryptedData, keyIv[0], keyIv[1])
}) })
@ -1206,7 +1260,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
options = options || {} options = options || {}
// console.log(dT(), 'Send encrypted'/*, message*/) // console.log(dT(), 'Send encrypted'/*, message*/)
// console.trace() // console.trace()
var data = new TLSerialization({startMaxLength: message.body.length + 64}) var data = new TLSerialization({startMaxLength: message.body.length + 2048})
data.storeIntBytes(this.serverSalt, 64, 'salt') data.storeIntBytes(this.serverSalt, 64, 'salt')
data.storeIntBytes(this.sessionID, 64, 'session_id') data.storeIntBytes(this.sessionID, 64, 'session_id')
@ -1217,7 +1271,17 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
data.storeInt(message.body.length, 'message_data_length') data.storeInt(message.body.length, 'message_data_length')
data.storeRawBytes(message.body, 'message_data') data.storeRawBytes(message.body, 'message_data')
return this.getEncryptedMessage(data.getBuffer()).then(function (encryptedResult) { var dataBuffer = data.getBuffer()
var paddingLength = (16 - (data.offset % 16)) + 16 * (1 + nextRandomInt(5))
var padding = new Array(paddingLength)
MtpSecureRandom.nextBytes(padding)
var dataWithPadding = bufferConcat(dataBuffer, padding)
// console.log(dT(), 'Adding padding', dataBuffer, padding, dataWithPadding)
// console.log(dT(), 'auth_key_id', bytesToHex(self.authKeyID))
return this.getEncryptedMessage(dataWithPadding).then(function (encryptedResult) {
// console.log(dT(), 'Got encrypted out message'/*, encryptedResult*/) // console.log(dT(), 'Got encrypted out message'/*, encryptedResult*/)
var request = new TLSerialization({startMaxLength: encryptedResult.bytes.byteLength + 256}) var request = new TLSerialization({startMaxLength: encryptedResult.bytes.byteLength + 256})
request.storeIntBytes(self.authKeyID, 64, 'auth_key_id') request.storeIntBytes(self.authKeyID, 64, 'auth_key_id')
@ -1259,7 +1323,6 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
MtpNetworker.prototype.parseResponse = function (responseBuffer) { MtpNetworker.prototype.parseResponse = function (responseBuffer) {
// console.log(dT(), 'Start parsing response') // console.log(dT(), 'Start parsing response')
var self = this var self = this
var deserializer = new TLDeserialization(responseBuffer) var deserializer = new TLDeserialization(responseBuffer)
var authKeyID = deserializer.fetchIntBytes(64, false, 'auth_key_id') var authKeyID = deserializer.fetchIntBytes(64, false, 'auth_key_id')
@ -1269,44 +1332,45 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var msgKey = deserializer.fetchIntBytes(128, true, 'msg_key') var msgKey = deserializer.fetchIntBytes(128, true, 'msg_key')
var encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data') var encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data')
return this.getDecryptedMessage(msgKey, encryptedData).then(function (dataWithPadding) { return self.getDecryptedMessage(msgKey, encryptedData).then(function (dataWithPadding) {
// console.log(dT(), 'after decrypt') // console.log(dT(), 'after decrypt')
var deserializer = new TLDeserialization(dataWithPadding, {mtproto: true}) return self.getMsgKey(dataWithPadding, false).then(function (calcMsgKey) {
if (!bytesCmp(msgKey, calcMsgKey)) {
var salt = deserializer.fetchIntBytes(64, false, 'salt') console.warn('[MT] msg_keys', msgKey, bytesFromArrayBuffer(calcMsgKey))
var sessionID = deserializer.fetchIntBytes(64, false, 'session_id')
var messageID = deserializer.fetchLong('message_id')
if (!bytesCmp(sessionID, self.sessionID) &&
(!self.prevSessionID || !bytesCmp(sessionID, self.prevSessionID))) {
console.warn('Sessions', sessionID, self.sessionID, self.prevSessionID)
throw new Error('[MT] Invalid server session_id: ' + bytesToHex(sessionID))
}
var seqNo = deserializer.fetchInt('seq_no')
var offset = deserializer.getOffset()
var totalLength = dataWithPadding.byteLength
var messageBodyLength = deserializer.fetchInt('message_data[length]')
if ((messageBodyLength % 4) ||
messageBodyLength > totalLength - offset) {
throw new Error('[MT] Invalid body length: ' + messageBodyLength)
}
var messageBody = deserializer.fetchRawBytes(messageBodyLength, true, 'message_data')
var offset = deserializer.getOffset()
var paddingLength = totalLength - offset
if (paddingLength < 0 || paddingLength > 15) {
throw new Error('[MT] Invalid padding length: ' + paddingLength)
}
var hashData = convertToUint8Array(dataWithPadding).subarray(0, offset)
return CryptoWorker.sha1Hash(hashData).then(function (dataHash) {
if (!bytesCmp(msgKey, bytesFromArrayBuffer(dataHash).slice(-16))) {
console.warn(msgKey, bytesFromArrayBuffer(dataHash))
throw new Error('[MT] server msgKey mismatch') throw new Error('[MT] server msgKey mismatch')
} }
// console.log(dT(), 'after msgKey check')
var deserializer = new TLDeserialization(dataWithPadding, {mtproto: true})
var salt = deserializer.fetchIntBytes(64, false, 'salt')
var sessionID = deserializer.fetchIntBytes(64, false, 'session_id')
var messageID = deserializer.fetchLong('message_id')
if (!bytesCmp(sessionID, self.sessionID) &&
(!self.prevSessionID || !bytesCmp(sessionID, self.prevSessionID))) {
console.warn('Sessions', sessionID, self.sessionID, self.prevSessionID)
throw new Error('[MT] Invalid server session_id: ' + bytesToHex(sessionID))
}
var seqNo = deserializer.fetchInt('seq_no')
var totalLength = dataWithPadding.byteLength
var messageBodyLength = deserializer.fetchInt('message_data[length]')
var offset = deserializer.getOffset()
if ((messageBodyLength % 4) ||
messageBodyLength > totalLength - offset) {
throw new Error('[MT] Invalid body length: ' + messageBodyLength)
}
var messageBody = deserializer.fetchRawBytes(messageBodyLength, true, 'message_data')
var offset = deserializer.getOffset()
var paddingLength = totalLength - offset
if (paddingLength < 12 || paddingLength > 1024) {
throw new Error('[MT] Invalid padding length: ' + paddingLength)
}
var buffer = bytesToArrayBuffer(messageBody) var buffer = bytesToArrayBuffer(messageBody)
var deserializerOptions = { var deserializerOptions = {

View File

@ -104,19 +104,38 @@ if (!Function.prototype.bind) {
/* setZeroTimeout polyfill, from http://dbaron.org/log/20100309-faster-timeouts */ /* setZeroTimeout polyfill, from http://dbaron.org/log/20100309-faster-timeouts */
(function (global) { (function (global) {
var timeouts = []
var messageName = 'zero-timeout-message' var messageName = 'zero-timeout-message'
var originalSetTimeout = global.setTimeout
var originalClearTimeout = global.clearTimeout
var originalMinId = originalSetTimeout(function () {}, 0)
var zeroTimeouts = []
var zeroMinId = originalMinId + 100000000
function setZeroTimeout (fn) { function setZeroTimeout (fn) {
timeouts.push(fn) var timeoutId = ++zeroMinId
zeroTimeouts.push([timeoutId, fn])
global.postMessage(messageName, '*') global.postMessage(messageName, '*')
return timeoutId
}
function clearZeroTimeout(timeoutId) {
if (timeoutId && timeoutId >= zeroMinId) {
for (var i = 0, len = zeroTimeouts.length; i < len; i++) {
if (zeroTimeouts[i][0] == timeoutId) {
console.warn('spliced timeout', timeoutId, i)
zeroTimeouts.splice(i, 1)
break
}
}
}
} }
function handleMessage (event) { function handleMessage (event) {
if (event.source == global && event.data == messageName) { if (event.source == global && event.data == messageName) {
event.stopPropagation() event.stopPropagation()
if (timeouts.length > 0) { if (zeroTimeouts.length > 0) {
var fn = timeouts.shift() var fn = zeroTimeouts.shift()[1]
fn() fn()
} }
} }
@ -124,7 +143,6 @@ if (!Function.prototype.bind) {
global.addEventListener('message', handleMessage, true) global.addEventListener('message', handleMessage, true)
var originalSetTimeout = global.setTimeout
global.setTimeout = function (callback, delay) { global.setTimeout = function (callback, delay) {
if (!delay || delay <= 5) { if (!delay || delay <= 5) {
return setZeroTimeout(callback) return setZeroTimeout(callback)
@ -132,5 +150,12 @@ if (!Function.prototype.bind) {
return originalSetTimeout(callback, delay) return originalSetTimeout(callback, delay)
} }
global.clearTimeout = function (timeoutId) {
if (timeoutId >= zeroMinId) {
clearZeroTimeout(timeoutId)
}
return originalClearTimeout(timeoutId)
}
global.setZeroTimeout = setZeroTimeout global.setZeroTimeout = setZeroTimeout
})(this) })(this)

10308
app/vendor/jquery/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
CACHE MANIFEST CACHE MANIFEST
# 66 # 67
NETWORK: NETWORK:
* *