Browse Source

Fixed periodical 'Connecting...' problem.

Also fixed safari arraybufferview warning
Closes #1551
Closes #1538
master
Igor Zhukov 7 years ago
parent
commit
237b3990b0
  1. 186
      app/js/lib/mtproto.js
  2. 35
      app/js/lib/polyfill.js
  3. 10308
      app/vendor/jquery/jquery.js
  4. 2
      app/webogram.appcache

186
app/js/lib/mtproto.js

@ -61,6 +61,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -61,6 +61,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
/**
* Server public key, obtained from here: https://core.telegram.org/api/obtaining_api_id
*
*
* -----BEGIN RSA PUBLIC KEY-----
* MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
* lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
@ -69,12 +70,73 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -69,12 +70,73 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
* 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-----
*
* Bytes can be got via
* $ openssl rsa -pubin -in key.pub -text -noout
*/
var publisKeysHex = [{
var publisKeysHex = [
{
modulus: 'c150023e2f70db7985ded064759cfecf0af328e69a41daf4d6f01b538135a6f91f8f8b2a0ec9ba9720ce352efcf6c5680ffc424bd634864902de0b4bd6d49f4e580230e3ae97d95c8b19442b3c0a10d8f5633fecedd6926a7f6dab0ddb7d457f9ea81b8465fcd6fffeed114011df91c059caedaf97625f6c96ecc74725556934ef781d866b34f011fce4d835a090196e9a5f0e4449af7eb697ddb9076494ca5f81104a305b6dd27665722c46b60e5df680fb16b210607ef217652e60236c255f6a28315f4083a96791d7214bf64c1df4fd0db1944fb26a2a57031b32eee64ad15a8ba68885cde74a5bfc920f6abf59ba5c75506373e7130f9042da922179251f',
exponent: '010001'
}]
},
{
modulus: 'aeec36c8ffc109cb099624685b97815415657bd76d8c9c3e398103d7ad16c9bba6f525ed0412d7ae2c2de2b44e77d72cbf4b7438709a4e646a05c43427c7f184debf72947519680e651500890c6832796dd11f772c25ff8f576755afe055b0a3752c696eb7d8da0d8be1faf38c9bdd97ce0a77d3916230c4032167100edd0f9e7a3a9b602d04367b689536af0d64b613ccba7962939d3b57682beb6dae5b608130b2e52aca78ba023cf6ce806b1dc49c72cf928a7199d22e3d7ac84e47bc9427d0236945d10dbd15177bab413fbf0edfda09f014c7a7da088dde9759702ca760af2b8e4e97cc055c617bd74c3d97008635b98dc4d621b4891da9fb0473047927',
exponent: '010001'
},
{
modulus: 'bdf2c77d81f6afd47bd30f29ac76e55adfe70e487e5e48297e5a9055c9c07d2b93b4ed3994d3eca5098bf18d978d54f8b7c713eb10247607e69af9ef44f38e28f8b439f257a11572945cc0406fe3f37bb92b79112db69eedf2dc71584a661638ea5becb9e23585074b80d57d9f5710dd30d2da940e0ada2f1b878397dc1a72b5ce2531b6f7dd158e09c828d03450ca0ff8a174deacebcaa22dde84ef66ad370f259d18af806638012da0ca4a70baa83d9c158f3552bc9158e69bf332a45809e1c36905a5caa12348dd57941a482131be7b2355a5f4635374f3bd3ddf5ff925bf4809ee27c1e67d9120c5fe08a9de458b1b4a3c5d0a428437f2beca81f4e2d5ff',
exponent: '010001'
},
{
modulus: 'b3f762b739be98f343eb1921cf0148cfa27ff7af02b6471213fed9daa0098976e667750324f1abcea4c31e43b7d11f1579133f2b3d9fe27474e462058884e5e1b123be9cbbc6a443b2925c08520e7325e6f1a6d50e117eb61ea49d2534c8bb4d2ae4153fabe832b9edf4c5755fdd8b19940b81d1d96cf433d19e6a22968a85dc80f0312f596bd2530c1cfb28b5fe019ac9bc25cd9c2a5d8a0f3a1c0c79bcca524d315b5e21b5c26b46babe3d75d06d1cd33329ec782a0f22891ed1db42a1d6c0dea431428bc4d7aabdcf3e0eb6fda4e23eb7733e7727e9a1915580796c55188d2596d2665ad1182ba7abf15aaa5a8b779ea996317a20ae044b820bff35b6e8a1',
exponent: '010001'
},
{
modulus: 'be6a71558ee577ff03023cfa17aab4e6c86383cff8a7ad38edb9fafe6f323f2d5106cbc8cafb83b869cffd1ccf121cd743d509e589e68765c96601e813dc5b9dfc4be415c7a6526132d0035ca33d6d6075d4f535122a1cdfe017041f1088d1419f65c8e5490ee613e16dbf662698c0f54870f0475fa893fc41eb55b08ff1ac211bc045ded31be27d12c96d8d3cfc6a7ae8aa50bf2ee0f30ed507cc2581e3dec56de94f5dc0a7abee0be990b893f2887bd2c6310a1e0a9e3e38bd34fded2541508dc102a9c9b4c95effd9dd2dfe96c29be647d6c69d66ca500843cfaed6e440196f1dbe0e2e22163c61ca48c79116fa77216726749a976a1c4b0944b5121e8c01',
exponent: '010001'
}
]
var publicKeysParsed = {}
var prepared = false
@ -180,7 +242,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -180,7 +242,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpTimeManager, CryptoWorker, $http, $q, $timeout) {
var chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/)
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.common['Accept']
@ -411,7 +473,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -411,7 +473,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
function mtpVerifyDhParams(g, dhPrime, gA) {
console.log(dT(), 'Verifying DH params')
var dhPrimeHex = bytesToHex(dhPrime);
var dhPrimeHex = bytesToHex(dhPrime)
if (g != 3 ||
dhPrimeHex !== 'c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b') {
// The verified value is from https://core.telegram.org/mtproto/security_guidelines
@ -597,7 +659,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -597,7 +659,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var akStopped = false
var chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/)
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.common['Accept']
@ -837,8 +899,8 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -837,8 +899,8 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
}).then(function () {
delete self.longPollPending
setZeroTimeout(self.checkLongPoll.bind(self))
}, function () {
console.log('Long-poll failed')
}, function (error) {
console.log('Long-poll failed', error)
})
}
@ -874,48 +936,44 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -874,48 +936,44 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
this.sheduleRequest(delay)
}
MtpNetworker.prototype.getMsgKeyIv = function (msgKey, isOut) {
MtpNetworker.prototype.getMsgKey = function (dataWithPadding, isOut) {
var authKey = this.authKeyUint8
var x = isOut ? 0 : 8
var sha1aText = new Uint8Array(48)
var sha1bText = new Uint8Array(48)
var sha1cText = new Uint8Array(48)
var sha1dText = new Uint8Array(48)
var promises = {}
sha1aText.set(msgKey, 0)
sha1aText.set(authKey.subarray(x, x + 32), 16)
promises.sha1a = CryptoWorker.sha1Hash(sha1aText)
var msgKeyLargePlain = bufferConcat(authKey.subarray(88 + x, 88 + x + 32), dataWithPadding)
return CryptoWorker.sha256Hash(msgKeyLargePlain).then(function (msgKeyLarge) {
var msgKey = new Uint8Array(msgKeyLarge).subarray(8, 24)
return msgKey
})
}
sha1bText.set(authKey.subarray(x + 32, x + 48), 0)
sha1bText.set(msgKey, 16)
sha1bText.set(authKey.subarray(x + 48, x + 64), 32)
promises.sha1b = CryptoWorker.sha1Hash(sha1bText)
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 = {}
sha1cText.set(authKey.subarray(x + 64, x + 96), 0)
sha1cText.set(msgKey, 32)
promises.sha1c = CryptoWorker.sha1Hash(sha1cText)
sha2aText.set(msgKey, 0)
sha2aText.set(authKey.subarray(x, x + 36), 16)
promises.sha2a = CryptoWorker.sha256Hash(sha2aText)
sha1dText.set(msgKey, 0)
sha1dText.set(authKey.subarray(x + 96, x + 128), 16)
promises.sha1d = CryptoWorker.sha1Hash(sha1dText)
sha2bText.set(authKey.subarray(40 + x, 40 + x + 36), 0)
sha2bText.set(msgKey, 36)
promises.sha2b = CryptoWorker.sha256Hash(sha2bText)
return $q.all(promises).then(function (result) {
var aesKey = new Uint8Array(32)
var aesIv = new Uint8Array(32)
sha1a = new Uint8Array(result.sha1a),
sha1b = new Uint8Array(result.sha1b),
sha1c = new Uint8Array(result.sha1c),
sha1d = new Uint8Array(result.sha1d)
var sha2a = new Uint8Array(result.sha2a)
var sha2b = new Uint8Array(result.sha2b)
aesKey.set(sha1a.subarray(0, 8))
aesKey.set(sha1b.subarray(8, 20), 8)
aesKey.set(sha1c.subarray(4, 16), 20)
aesKey.set(sha2a.subarray(0, 8))
aesKey.set(sha2b.subarray(8, 24), 8)
aesKey.set(sha2a.subarray(24, 32), 24)
aesIv.set(sha1a.subarray(8, 20))
aesIv.set(sha1b.subarray(0, 8), 12)
aesIv.set(sha1c.subarray(16, 20), 20)
aesIv.set(sha1d.subarray(0, 8), 24)
aesIv.set(sha2b.subarray(0, 8))
aesIv.set(sha2a.subarray(8, 24), 8)
aesIv.set(sha2b.subarray(24, 32), 24)
return [aesKey, aesIv]
})
@ -1145,7 +1203,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1145,7 +1203,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
this.checkConnectionPeriod = Math.max(1.1, Math.sqrt(this.checkConnectionPeriod))
})
}, function (error) {
console.log('Encrypted request failed', error)
console.error('Encrypted request failed', error)
if (message.container) {
angular.forEach(message.inner, function (msgID) {
@ -1173,16 +1231,12 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1173,16 +1231,12 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
}
}
MtpNetworker.prototype.getEncryptedMessage = function (bytes) {
MtpNetworker.prototype.getEncryptedMessage = function (dataWithPadding) {
var self = this
// console.log(dT(), 'Start encrypt', bytes.byteLength)
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) {
return self.getMsgKey(dataWithPadding, true).then(function (msgKey) {
return self.getAesKeyIv(msgKey, true).then(function (keyIv) {
// 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')
return {
bytes: encryptedBytes,
@ -1195,7 +1249,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1195,7 +1249,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
MtpNetworker.prototype.getDecryptedMessage = function (msgKey, encryptedData) {
// 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')
return CryptoWorker.aesDecrypt(encryptedData, keyIv[0], keyIv[1])
})
@ -1206,7 +1260,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1206,7 +1260,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
options = options || {}
// console.log(dT(), 'Send encrypted'/*, message*/)
// 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.sessionID, 64, 'session_id')
@ -1217,7 +1271,17 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1217,7 +1271,17 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
data.storeInt(message.body.length, 'message_data_length')
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*/)
var request = new TLSerialization({startMaxLength: encryptedResult.bytes.byteLength + 256})
request.storeIntBytes(self.authKeyID, 64, 'auth_key_id')
@ -1259,7 +1323,6 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1259,7 +1323,6 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
MtpNetworker.prototype.parseResponse = function (responseBuffer) {
// console.log(dT(), 'Start parsing response')
var self = this
var deserializer = new TLDeserialization(responseBuffer)
var authKeyID = deserializer.fetchIntBytes(64, false, 'auth_key_id')
@ -1269,8 +1332,15 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1269,8 +1332,15 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var msgKey = deserializer.fetchIntBytes(128, true, 'msg_key')
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')
return self.getMsgKey(dataWithPadding, false).then(function (calcMsgKey) {
if (!bytesCmp(msgKey, calcMsgKey)) {
console.warn('[MT] msg_keys', msgKey, bytesFromArrayBuffer(calcMsgKey))
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')
@ -1285,10 +1355,11 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1285,10 +1355,11 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var seqNo = deserializer.fetchInt('seq_no')
var offset = deserializer.getOffset()
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)
@ -1297,16 +1368,9 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1297,16 +1368,9 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var offset = deserializer.getOffset()
var paddingLength = totalLength - offset
if (paddingLength < 0 || paddingLength > 15) {
if (paddingLength < 12 || paddingLength > 1024) {
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')
}
var buffer = bytesToArrayBuffer(messageBody)
var deserializerOptions = {

35
app/js/lib/polyfill.js

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

10308
app/vendor/jquery/jquery.js vendored

File diff suppressed because it is too large Load Diff

2
app/webogram.appcache

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

Loading…
Cancel
Save