Merge branch 'master' into development

This catches the development branch up with v1.0.39 in master.
This commit is contained in:
Scott Nonnenberg 2017-11-21 18:25:59 -08:00
commit 0e328f3911
No known key found for this signature in database
GPG Key ID: A4931C09644C654B
18 changed files with 9700 additions and 254 deletions

View File

@ -97,6 +97,7 @@ module.exports = function(grunt) {
files: [
'Gruntfile.js',
'js/**/*.js',
'!js/jquery.js',
'!js/libtextsecure.js',
'!js/WebAudioRecorderMp3.js',
'!js/Mp3LameEncoder.min.js',
@ -132,6 +133,9 @@ module.exports = function(grunt) {
}, {
src: 'components/webaudiorecorder/lib/WebAudioRecorderMp3.js',
dest: 'js/WebAudioRecorderMp3.js'
}, {
src: 'components/jquery/dist/jquery.js',
dest: 'js/jquery.js'
}],
},
res: {

View File

@ -82,7 +82,7 @@
"description": "Button shown if the user runs into an error during import, allowing them to start over"
},
"importInstructions": {
"message": "The first step is to tell us where you previously exported your Signal data. It will be a directory whose name starts with 'Signal Export.'",
"message": "The first step is to tell us where you previously <a href='https://support.signal.org/hc/en-us/articles/115002502511'>exported your Signal data</a>. It will be a directory whose name starts with 'Signal Export.'<br><br><b>NOTE</b>: You must only import a set of exported data <b>once</b>. Import makes a copy of the exported client, and duplicate clients interfere with each other.",
"description": "Description of the export process"
},
"importing": {
@ -906,7 +906,7 @@
},
"leftTheGroup": {
"message": "$name$ left the group.",
"description": "Shown in the conversation history when someone leaves the group",
"description": "Shown in the conversation history when a single person leaves the group",
"placeholders": {
"name": {
"content": "$1",
@ -929,8 +929,18 @@
}
},
"joinedTheGroup": {
"message": "$name$ joined the group.",
"description": "Shown in the conversation history when a single person joins the group",
"placeholders": {
"name": {
"content": "$1",
"example": "Alice"
}
}
},
"multipleJoinedTheGroup": {
"message": "$names$ joined the group.",
"description": "Shown in the conversation history when people join the group",
"description": "Shown in the conversation history when more than one person joins the group",
"placeholders": {
"names": {
"content": "$1",

View File

@ -48,6 +48,16 @@ a {
<a href="https://signal.org">signal.org</a>
</div>
<script type='text/javascript' src='js/jquery.js'></script>
<script>
$(document).on('keyup', function(e) {
if (e.keyCode === 27) {
window.closeAbout();
}
});
</script>
</body>
</html>

View File

@ -19,7 +19,7 @@ function checkForUpdates() {
}
var showingDialog = false;
function showUpdateDialog(messages) {
function showUpdateDialog(mainWindow, messages) {
if (showingDialog) {
return;
}
@ -38,7 +38,7 @@ function showUpdateDialog(messages) {
cancelId: LATER_BUTTON
}
dialog.showMessageBox(options, function(response) {
dialog.showMessageBox(mainWindow, options, function(response) {
if (response == RESTART_BUTTON) {
windowState.markShouldQuit();
autoUpdater.quitAndInstall();
@ -52,7 +52,7 @@ function onError(error) {
console.log("Got an error while updating: ", error.stack);
}
function initialize(messages) {
function initialize(getMainWindow, messages) {
if (!messages) {
throw new Error('auto-update initialize needs localized messages');
}
@ -62,7 +62,7 @@ function initialize(messages) {
}
autoUpdater.addListener('update-downloaded', function() {
showUpdateDialog(messages);
showUpdateDialog(getMainWindow(), messages);
});
autoUpdater.addListener('error', onError);

View File

@ -101,7 +101,8 @@
_.each(storeNames, function(storeName) {
var transaction = idb_db.transaction(storeNames, 'readwrite');
transaction.onerror = function(error) {
transaction.onerror = function(e) {
var error = e.target.error;
console.log(
'exportToJsonFile: transaction error',
error && error.stack ? error.stack : error
@ -116,8 +117,13 @@
var request = store.openCursor();
var count = 0;
request.onerror = function(e) {
console.log('Error attempting to export store', storeName);
reject(e);
var error = e.target.error;
console.log(
'Error attempting to export store',
storeName,
error && error.stack ? error.stack : error
);
reject(error);
};
request.onsuccess = function(event) {
if (count === 0) {
@ -188,7 +194,14 @@
};
var transaction = idb_db.transaction(storeNames, 'readwrite');
transaction.onerror = reject;
transaction.onerror = function(e) {
var error = e.target.error;
console.log(
'importFromJsonString error:',
error && error.stack ? error.stack : error
);
reject(error || new Error('importFromJsonString: transaction.onerror'));
};
transaction.oncomplete = finish.bind(null, 'transaction complete');
_.each(storeNames, function(storeName) {
@ -216,14 +229,16 @@
}
}
};
request.onerror = function(error) {
request.onerror = function(e) {
var error = e.target.error;
console.log(
'Error adding object to store',
storeName,
':',
toAdd
toAdd,
error && error.stack ? error.stack : error
);
reject(error);
reject(error || new Error('importFromJsonString: request.onerror'));
};
});
});
@ -384,13 +399,14 @@
return new Promise(function(resolve, reject) {
var transaction = idb_db.transaction('messages', 'readwrite');
transaction.onerror = function(e) {
var error = e.target.error;
console.log(
'exportConversation transaction error for conversation',
name,
':',
e && e.stack ? e.stack : e
error && error.stack ? error.stack : error
);
return reject(e);
return reject(error || new Error('exportConversation: transaction.onerror'));
};
transaction.oncomplete = function() {
// this doesn't really mean anything - we may have attachment processing to do
@ -408,13 +424,14 @@
stream.write('{"messages":[');
request.onerror = function(e) {
var error = e.target.error;
console.log(
'exportConversation: error pulling messages for conversation',
name,
':',
e && e.stack ? e.stack : e
error && error.stack ? error.stack : error
);
return reject(e);
return reject(error || new Error('exportConversation: request.onerror'));
};
request.onsuccess = function(event) {
var cursor = event.target.result;
@ -498,11 +515,12 @@
return new Promise(function(resolve, reject) {
var transaction = idb_db.transaction('conversations', 'readwrite');
transaction.onerror = function(e) {
var error = e.target.error;
console.log(
'exportConversations: transaction error:',
e && e.stack ? e.stack : e
error && error.stack ? error.stack : error
);
return reject(e);
return reject(error || new Error('exportConversations: transaction.onerror'));
};
transaction.oncomplete = function() {
// not really very useful - fires at unexpected times
@ -512,11 +530,12 @@
var store = transaction.objectStore('conversations');
var request = store.openCursor();
request.onerror = function(e) {
var error = e.target.error;
console.log(
'exportConversations: error pulling conversations:',
e && e.stack ? e.stack : e
error && error.stack ? error.stack : error
);
return reject(e);
return reject(error || new Error('exportConversations: request.onerror'));
};
request.onsuccess = function(event) {
var cursor = event.target.result;
@ -602,11 +621,12 @@
var transaction = idb_db.transaction('messages', 'readwrite');
transaction.onerror = function(e) {
var error = e.target.error;
console.log(
'saveAllMessages transaction error:',
e && e.stack ? e.stack : e
error && error.stack ? error.stack : error
);
return reject(e);
return reject(error || new Error('saveAllMessages: transaction.onerror'));
};
transaction.oncomplete = finish.bind(null, 'transaction complete');
@ -620,7 +640,7 @@
count += 1;
if (count === messages.length) {
console.log(
'Done importing',
'Saved',
messages.length,
'messages for conversation',
// Don't know if group or private conversation, so we blindly redact
@ -629,35 +649,63 @@
finish('puts scheduled');
}
};
request.onerror = function(event) {
console.log('Error adding object to store:', event);
reject(new Error('saveAllMessage: onerror fired'));
request.onerror = function(e) {
var error = e.target.error;
console.log(
'Error adding object to store:',
error && error.stack ? error.stack : error
);
reject(error || new Error('saveAllMessages: request.onerror'));
};
});
});
}
// To reduce the memory impact of attachments, we make individual saves to the
// database for every message with an attachment. We load the attachment for a
// message, save it, and only then do we move on to the next message. Thus, every
// message with attachments needs to be removed from our overall message save with the
// filter() call.
function importConversation(idb_db, dir) {
return readFileAsText(dir, 'messages.json').then(function(contents) {
var promiseChain = Promise.resolve();
var json = JSON.parse(contents);
var messages = json.messages;
_.forEach(messages, function(message) {
var conversationId;
if (json.messages && json.messages.length) {
conversationId = json.messages[0].conversationId;
}
var messages = _.filter(json.messages, function(message) {
message = unstringify(message);
if (message.attachments && message.attachments.length) {
var process = function() {
return loadAttachments(dir, message);
return loadAttachments(dir, message).then(function() {
return saveAllMessages(idb_db, [message]);
});
};
promiseChain = promiseChain.then(process);
return null;
}
return message;
});
return promiseChain.then(function() {
return saveAllMessages(idb_db, messages);
});
return saveAllMessages(idb_db, messages)
.then(function() {
return promiseChain;
})
.then(function() {
console.log(
'Finished importing conversation',
// Don't know if group or private conversation, so we blindly redact
conversationId ? '[REDACTED]' + conversationId.slice(-3) : 'with no messages'
);
});
}, function() {
console.log('Warning: could not access messages.json in directory: ' + dir);
});
@ -689,10 +737,18 @@
var storeNames = idb_db.objectStoreNames;
var transaction = idb_db.transaction(storeNames, 'readwrite');
transaction.oncomplete = function() {
// unused
var finished = false;
var finish = function(via) {
console.log('clearing all stores done via', via);
if (finished) {
resolve();
}
finished = true;
};
transaction.onerror = function(error) {
transaction.oncomplete = finish.bind(null, 'transaction complete');
transaction.onerror = function(e) {
var error = e.target.error;
console.log(
'saveAllMessages transaction error:',
error && error.stack ? error.stack : error
@ -711,16 +767,17 @@
if (count >= storeNames.length) {
console.log('Done clearing all indexeddb stores');
return resolve();
return finish('clears complete');
}
};
request.onerror = function(error) {
request.onerror = function(e) {
var error = e.target.error;
console.log(
'clearAllStores transaction error:',
error && error.stack ? error.stack : error
);
return reject(error);
return reject(error || new Error('clearAllStores: request.onerror'));
};
});
});

9205
js/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -25538,21 +25538,18 @@ Curve25519Worker.prototype = {
/**
* The low 32 bits as a signed value.
* @type {number}
* @expose
*/
this.low = low | 0;
/**
* The high 32 bits as a signed value.
* @type {number}
* @expose
*/
this.high = high | 0;
/**
* Whether unsigned or not.
* @type {boolean}
* @expose
*/
this.unsigned = !!unsigned;
}
@ -25578,10 +25575,9 @@ Curve25519Worker.prototype = {
* An indicator used to reliably determine if an object is a Long or not.
* @type {boolean}
* @const
* @expose
* @private
*/
Long.__isLong__;
Long.prototype.__isLong__;
Object.defineProperty(Long.prototype, "__isLong__", {
value: true,
@ -25604,7 +25600,6 @@ Curve25519Worker.prototype = {
* @function
* @param {*} obj Object
* @returns {boolean}
* @expose
*/
Long.isLong = isLong;
@ -25661,7 +25656,6 @@ Curve25519Worker.prototype = {
* @param {number} value The 32 bit integer in question
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
* @returns {!Long} The corresponding Long value
* @expose
*/
Long.fromInt = fromInt;
@ -25696,7 +25690,6 @@ Curve25519Worker.prototype = {
* @param {number} value The number in question
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
* @returns {!Long} The corresponding Long value
* @expose
*/
Long.fromNumber = fromNumber;
@ -25719,7 +25712,6 @@ Curve25519Worker.prototype = {
* @param {number} highBits The high 32 bits
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
* @returns {!Long} The corresponding Long value
* @expose
*/
Long.fromBits = fromBits;
@ -25789,7 +25781,6 @@ Curve25519Worker.prototype = {
* @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed
* @param {number=} radix The radix in which the text is written (2-36), defaults to 10
* @returns {!Long} The corresponding Long value
* @expose
*/
Long.fromString = fromString;
@ -25815,7 +25806,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value
* @returns {!Long}
* @expose
*/
Long.fromValue = fromValue;
@ -25873,7 +25863,6 @@ Curve25519Worker.prototype = {
/**
* Signed zero.
* @type {!Long}
* @expose
*/
Long.ZERO = ZERO;
@ -25886,7 +25875,6 @@ Curve25519Worker.prototype = {
/**
* Unsigned zero.
* @type {!Long}
* @expose
*/
Long.UZERO = UZERO;
@ -25899,7 +25887,6 @@ Curve25519Worker.prototype = {
/**
* Signed one.
* @type {!Long}
* @expose
*/
Long.ONE = ONE;
@ -25912,7 +25899,6 @@ Curve25519Worker.prototype = {
/**
* Unsigned one.
* @type {!Long}
* @expose
*/
Long.UONE = UONE;
@ -25925,7 +25911,6 @@ Curve25519Worker.prototype = {
/**
* Signed negative one.
* @type {!Long}
* @expose
*/
Long.NEG_ONE = NEG_ONE;
@ -25938,7 +25923,6 @@ Curve25519Worker.prototype = {
/**
* Maximum signed value.
* @type {!Long}
* @expose
*/
Long.MAX_VALUE = MAX_VALUE;
@ -25951,7 +25935,6 @@ Curve25519Worker.prototype = {
/**
* Maximum unsigned value.
* @type {!Long}
* @expose
*/
Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE;
@ -25964,7 +25947,6 @@ Curve25519Worker.prototype = {
/**
* Minimum signed value.
* @type {!Long}
* @expose
*/
Long.MIN_VALUE = MIN_VALUE;
@ -25977,7 +25959,6 @@ Curve25519Worker.prototype = {
/**
* Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
* @returns {number}
* @expose
*/
LongPrototype.toInt = function toInt() {
return this.unsigned ? this.low >>> 0 : this.low;
@ -25986,7 +25967,6 @@ Curve25519Worker.prototype = {
/**
* Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
* @returns {number}
* @expose
*/
LongPrototype.toNumber = function toNumber() {
if (this.unsigned)
@ -26000,7 +25980,6 @@ Curve25519Worker.prototype = {
* @returns {string}
* @override
* @throws {RangeError} If `radix` is out of range
* @expose
*/
LongPrototype.toString = function toString(radix) {
radix = radix || 10;
@ -26043,7 +26022,6 @@ Curve25519Worker.prototype = {
/**
* Gets the high 32 bits as a signed integer.
* @returns {number} Signed high bits
* @expose
*/
LongPrototype.getHighBits = function getHighBits() {
return this.high;
@ -26052,7 +26030,6 @@ Curve25519Worker.prototype = {
/**
* Gets the high 32 bits as an unsigned integer.
* @returns {number} Unsigned high bits
* @expose
*/
LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() {
return this.high >>> 0;
@ -26061,7 +26038,6 @@ Curve25519Worker.prototype = {
/**
* Gets the low 32 bits as a signed integer.
* @returns {number} Signed low bits
* @expose
*/
LongPrototype.getLowBits = function getLowBits() {
return this.low;
@ -26070,7 +26046,6 @@ Curve25519Worker.prototype = {
/**
* Gets the low 32 bits as an unsigned integer.
* @returns {number} Unsigned low bits
* @expose
*/
LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() {
return this.low >>> 0;
@ -26079,7 +26054,6 @@ Curve25519Worker.prototype = {
/**
* Gets the number of bits needed to represent the absolute value of this Long.
* @returns {number}
* @expose
*/
LongPrototype.getNumBitsAbs = function getNumBitsAbs() {
if (this.isNegative()) // Unsigned Longs are never negative
@ -26094,7 +26068,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value equals zero.
* @returns {boolean}
* @expose
*/
LongPrototype.isZero = function isZero() {
return this.high === 0 && this.low === 0;
@ -26103,7 +26076,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value is negative.
* @returns {boolean}
* @expose
*/
LongPrototype.isNegative = function isNegative() {
return !this.unsigned && this.high < 0;
@ -26112,7 +26084,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value is positive.
* @returns {boolean}
* @expose
*/
LongPrototype.isPositive = function isPositive() {
return this.unsigned || this.high >= 0;
@ -26121,7 +26092,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value is odd.
* @returns {boolean}
* @expose
*/
LongPrototype.isOdd = function isOdd() {
return (this.low & 1) === 1;
@ -26130,7 +26100,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value is even.
* @returns {boolean}
* @expose
*/
LongPrototype.isEven = function isEven() {
return (this.low & 1) === 0;
@ -26140,7 +26109,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value equals the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.equals = function equals(other) {
if (!isLong(other))
@ -26155,7 +26123,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.eq = LongPrototype.equals;
@ -26163,7 +26130,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value differs from the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.notEquals = function notEquals(other) {
return !this.eq(/* validates */ other);
@ -26174,7 +26140,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.neq = LongPrototype.notEquals;
@ -26182,7 +26147,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value is less than the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.lessThan = function lessThan(other) {
return this.comp(/* validates */ other) < 0;
@ -26193,7 +26157,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.lt = LongPrototype.lessThan;
@ -26201,7 +26164,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value is less than or equal the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) {
return this.comp(/* validates */ other) <= 0;
@ -26212,7 +26174,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.lte = LongPrototype.lessThanOrEqual;
@ -26220,7 +26181,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value is greater than the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.greaterThan = function greaterThan(other) {
return this.comp(/* validates */ other) > 0;
@ -26231,7 +26191,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.gt = LongPrototype.greaterThan;
@ -26239,7 +26198,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value is greater than or equal the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) {
return this.comp(/* validates */ other) >= 0;
@ -26250,7 +26208,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.gte = LongPrototype.greaterThanOrEqual;
@ -26259,7 +26216,6 @@ Curve25519Worker.prototype = {
* @param {!Long|number|string} other Other value
* @returns {number} 0 if they are the same, 1 if the this is greater and -1
* if the given one is greater
* @expose
*/
LongPrototype.compare = function compare(other) {
if (!isLong(other))
@ -26285,14 +26241,12 @@ Curve25519Worker.prototype = {
* @param {!Long|number|string} other Other value
* @returns {number} 0 if they are the same, 1 if the this is greater and -1
* if the given one is greater
* @expose
*/
LongPrototype.comp = LongPrototype.compare;
/**
* Negates this Long's value.
* @returns {!Long} Negated Long
* @expose
*/
LongPrototype.negate = function negate() {
if (!this.unsigned && this.eq(MIN_VALUE))
@ -26304,7 +26258,6 @@ Curve25519Worker.prototype = {
* Negates this Long's value. This is an alias of {@link Long#negate}.
* @function
* @returns {!Long} Negated Long
* @expose
*/
LongPrototype.neg = LongPrototype.negate;
@ -26312,7 +26265,6 @@ Curve25519Worker.prototype = {
* Returns the sum of this and the specified Long.
* @param {!Long|number|string} addend Addend
* @returns {!Long} Sum
* @expose
*/
LongPrototype.add = function add(addend) {
if (!isLong(addend))
@ -26349,7 +26301,6 @@ Curve25519Worker.prototype = {
* Returns the difference of this and the specified Long.
* @param {!Long|number|string} subtrahend Subtrahend
* @returns {!Long} Difference
* @expose
*/
LongPrototype.subtract = function subtract(subtrahend) {
if (!isLong(subtrahend))
@ -26362,7 +26313,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} subtrahend Subtrahend
* @returns {!Long} Difference
* @expose
*/
LongPrototype.sub = LongPrototype.subtract;
@ -26370,7 +26320,6 @@ Curve25519Worker.prototype = {
* Returns the product of this and the specified Long.
* @param {!Long|number|string} multiplier Multiplier
* @returns {!Long} Product
* @expose
*/
LongPrototype.multiply = function multiply(multiplier) {
if (this.isZero())
@ -26438,7 +26387,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} multiplier Multiplier
* @returns {!Long} Product
* @expose
*/
LongPrototype.mul = LongPrototype.multiply;
@ -26447,7 +26395,6 @@ Curve25519Worker.prototype = {
* unsigned if this Long is unsigned.
* @param {!Long|number|string} divisor Divisor
* @returns {!Long} Quotient
* @expose
*/
LongPrototype.divide = function divide(divisor) {
if (!isLong(divisor))
@ -26458,6 +26405,8 @@ Curve25519Worker.prototype = {
return this.unsigned ? UZERO : ZERO;
var approx, rem, res;
if (!this.unsigned) {
// This section is only relevant for signed longs and is derived from the
// closure library as a whole.
if (this.eq(MIN_VALUE)) {
if (divisor.eq(ONE) || divisor.eq(NEG_ONE))
return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
@ -26483,19 +26432,18 @@ Curve25519Worker.prototype = {
return this.neg().div(divisor).neg();
} else if (divisor.isNegative())
return this.div(divisor.neg()).neg();
} else if (!divisor.unsigned)
divisor = divisor.toUnsigned();
// The algorithm below has not been made for unsigned longs. It's therefore
// required to take special care of the MSB prior to running it.
if (this.unsigned) {
res = ZERO;
} else {
// The algorithm below has not been made for unsigned longs. It's therefore
// required to take special care of the MSB prior to running it.
if (!divisor.unsigned)
divisor = divisor.toUnsigned();
if (divisor.gt(this))
return UZERO;
if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true
return UONE;
res = UZERO;
} else
res = ZERO;
}
// Repeat the following until the remainder is less than other: find a
// floating-point that approximates remainder / other *from below*, add this
@ -26539,7 +26487,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} divisor Divisor
* @returns {!Long} Quotient
* @expose
*/
LongPrototype.div = LongPrototype.divide;
@ -26547,7 +26494,6 @@ Curve25519Worker.prototype = {
* Returns this Long modulo the specified.
* @param {!Long|number|string} divisor Divisor
* @returns {!Long} Remainder
* @expose
*/
LongPrototype.modulo = function modulo(divisor) {
if (!isLong(divisor))
@ -26560,14 +26506,12 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} divisor Divisor
* @returns {!Long} Remainder
* @expose
*/
LongPrototype.mod = LongPrototype.modulo;
/**
* Returns the bitwise NOT of this Long.
* @returns {!Long}
* @expose
*/
LongPrototype.not = function not() {
return fromBits(~this.low, ~this.high, this.unsigned);
@ -26577,7 +26521,6 @@ Curve25519Worker.prototype = {
* Returns the bitwise AND of this Long and the specified.
* @param {!Long|number|string} other Other Long
* @returns {!Long}
* @expose
*/
LongPrototype.and = function and(other) {
if (!isLong(other))
@ -26589,7 +26532,6 @@ Curve25519Worker.prototype = {
* Returns the bitwise OR of this Long and the specified.
* @param {!Long|number|string} other Other Long
* @returns {!Long}
* @expose
*/
LongPrototype.or = function or(other) {
if (!isLong(other))
@ -26601,7 +26543,6 @@ Curve25519Worker.prototype = {
* Returns the bitwise XOR of this Long and the given one.
* @param {!Long|number|string} other Other Long
* @returns {!Long}
* @expose
*/
LongPrototype.xor = function xor(other) {
if (!isLong(other))
@ -26613,7 +26554,6 @@ Curve25519Worker.prototype = {
* Returns this Long with bits shifted to the left by the given amount.
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shiftLeft = function shiftLeft(numBits) {
if (isLong(numBits))
@ -26631,7 +26571,6 @@ Curve25519Worker.prototype = {
* @function
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shl = LongPrototype.shiftLeft;
@ -26639,7 +26578,6 @@ Curve25519Worker.prototype = {
* Returns this Long with bits arithmetically shifted to the right by the given amount.
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shiftRight = function shiftRight(numBits) {
if (isLong(numBits))
@ -26657,7 +26595,6 @@ Curve25519Worker.prototype = {
* @function
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shr = LongPrototype.shiftRight;
@ -26665,7 +26602,6 @@ Curve25519Worker.prototype = {
* Returns this Long with bits logically shifted to the right by the given amount.
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) {
if (isLong(numBits))
@ -26690,14 +26626,12 @@ Curve25519Worker.prototype = {
* @function
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shru = LongPrototype.shiftRightUnsigned;
/**
* Converts this Long to signed.
* @returns {!Long} Signed long
* @expose
*/
LongPrototype.toSigned = function toSigned() {
if (!this.unsigned)
@ -26708,7 +26642,6 @@ Curve25519Worker.prototype = {
/**
* Converts this Long to unsigned.
* @returns {!Long} Unsigned long
* @expose
*/
LongPrototype.toUnsigned = function toUnsigned() {
if (this.unsigned)
@ -26716,6 +26649,53 @@ Curve25519Worker.prototype = {
return fromBits(this.low, this.high, true);
};
/**
* Converts this Long to its byte representation.
* @param {boolean=} le Whether little or big endian, defaults to big endian
* @returns {!Array.<number>} Byte representation
*/
LongPrototype.toBytes = function(le) {
return le ? this.toBytesLE() : this.toBytesBE();
}
/**
* Converts this Long to its little endian byte representation.
* @returns {!Array.<number>} Little endian byte representation
*/
LongPrototype.toBytesLE = function() {
var hi = this.high,
lo = this.low;
return [
lo & 0xff,
(lo >>> 8) & 0xff,
(lo >>> 16) & 0xff,
(lo >>> 24) & 0xff,
hi & 0xff,
(hi >>> 8) & 0xff,
(hi >>> 16) & 0xff,
(hi >>> 24) & 0xff
];
}
/**
* Converts this Long to its big endian byte representation.
* @returns {!Array.<number>} Big endian byte representation
*/
LongPrototype.toBytesBE = function() {
var hi = this.high,
lo = this.low;
return [
(hi >>> 24) & 0xff,
(hi >>> 16) & 0xff,
(hi >>> 8) & 0xff,
hi & 0xff,
(lo >>> 24) & 0xff,
(lo >>> 16) & 0xff,
(lo >>> 8) & 0xff,
lo & 0xff
];
}
return Long;
});
@ -35901,6 +35881,10 @@ Internal.SessionRecord = function() {
delete sessions[util.toString(oldestBaseKey)];
}
},
deleteAllSessions: function() {
// Used primarily in session reset scenarios, where we really delete sessions
this.sessions = {};
}
};
return SessionRecord;
@ -36396,7 +36380,7 @@ SessionCipher.prototype = {
}.bind(this));
},
doDecryptWhisperMessage: function(messageBytes, session) {
if (!messageBytes instanceof ArrayBuffer) {
if (!(messageBytes instanceof ArrayBuffer)) {
throw new Error("Expected messageBytes to be an ArrayBuffer");
}
var version = (new Uint8Array(messageBytes))[0];
@ -36571,6 +36555,20 @@ SessionCipher.prototype = {
return this.storage.storeSession(address, record.serialize());
}.bind(this));
}.bind(this));
},
deleteAllSessionsForDevice: function() {
// Used in session reset scenarios, where we really need to delete
var address = this.remoteAddress.toString();
return Internal.SessionLock.queueJobForNumber(address, function() {
return this.getRecord(address).then(function(record) {
if (record === undefined) {
return;
}
record.deleteAllSessions();
return this.storage.storeSession(address, record.serialize());
}.bind(this));
}.bind(this));
}
};
@ -36590,6 +36588,7 @@ libsignal.SessionCipher = function(storage, remoteAddress, options) {
this.getRemoteRegistrationId = cipher.getRemoteRegistrationId.bind(cipher);
this.hasOpenSession = cipher.hasOpenSession.bind(cipher);
this.closeOpenSessionForDevice = cipher.closeOpenSessionForDevice.bind(cipher);
this.deleteAllSessionsForDevice = cipher.deleteAllSessionsForDevice.bind(cipher);
};
/*
@ -37501,9 +37500,30 @@ var TextSecureServer = (function() {
}
window.nodeFetch(url, fetchOptions).then(function(response) {
var resultPromise;
<<<<<<< HEAD
if (options.responseType === 'json'
&& response.headers.get('Content-Type') === 'application/json') {
resultPromise = response.json();
||||||| merged common ancestors
if (options.responseType === 'json') {
resultPromise = response.json();
} else if (!options.responseType || options.responseType === 'text') {
resultPromise = response.text();
=======
if (options.responseType === 'json') {
resultPromise = response.json().catch(function(error) {
// If the response was otherwise successful, a JSON.parse() failure really
// is a problem. But the Signal server does return HTML in error cases
// when we requested JSON, sadly.
if (0 <= response.status && response.status < 400) {
throw error;
}
return null;
})
} else if (!options.responseType || options.responseType === 'text') {
resultPromise = response.text();
>>>>>>> master
} else if (options.responseType === 'arraybuffer') {
resultPromise = response.buffer();
} else {
@ -39258,8 +39278,8 @@ MessageReceiver.prototype.extend({
var address = new libsignal.SignalProtocolAddress(number, deviceId);
var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address);
console.log('closing session for', address.toString());
return sessionCipher.closeOpenSessionForDevice();
console.log('deleting sessions for', address.toString());
return sessionCipher.deleteAllSessionsForDevice();
}));
});
},
@ -39896,12 +39916,14 @@ MessageSender.prototype = {
sendIndividualProto: function(number, proto, timestamp, silent) {
return new Promise(function(resolve, reject) {
this.sendMessageProto(timestamp, [number], proto, function(res) {
if (res.errors.length > 0)
var callback = function(res) {
if (res.errors.length > 0) {
reject(res);
else
} else {
resolve(res);
}, silent);
}
};
this.sendMessageProto(timestamp, [number], proto, callback, silent);
}.bind(this));
},
@ -40076,10 +40098,11 @@ MessageSender.prototype = {
return new Promise(function(resolve, reject) {
this.sendMessageProto(timestamp, numbers, proto, function(res) {
res.dataMessage = proto.toArrayBuffer();
if (res.errors.length > 0)
if (res.errors.length > 0) {
reject(res);
else
} else {
resolve(res);
}
}.bind(this));
}.bind(this));
},
@ -40096,25 +40119,56 @@ MessageSender.prototype = {
});
},
closeSession: function(number, timestamp) {
console.log('sending end session');
resetSession: function(number, timestamp) {
console.log('resetting secure session');
var proto = new textsecure.protobuf.DataMessage();
proto.body = "TERMINATE";
proto.flags = textsecure.protobuf.DataMessage.Flags.END_SESSION;
return this.sendIndividualProto(number, proto, timestamp).then(function(res) {
return this.sendSyncMessage(proto.toArrayBuffer(), timestamp, number).then(function() {
return textsecure.storage.protocol.getDeviceIds(number).then(function(deviceIds) {
var logError = function(prefix) {
return function(error) {
console.log(
prefix,
error && error.stack ? error.stack : error
);
throw error;
};
};
var deleteAllSessions = function(number) {
return textsecure.storage.protocol.getDeviceIds(number)
.then(function(deviceIds) {
return Promise.all(deviceIds.map(function(deviceId) {
var address = new libsignal.SignalProtocolAddress(number, deviceId);
console.log('closing session for', address.toString());
var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address);
return sessionCipher.closeOpenSessionForDevice();
})).then(function() {
return res;
});
console.log('deleting sessions for', address.toString());
var sessionCipher = new libsignal.SessionCipher(
textsecure.storage.protocol,
address
);
return sessionCipher.deleteAllSessionsForDevice();
}));
});
};
var sendToContact = deleteAllSessions(number)
.catch(logError('resetSession/deleteAllSessions1 error:'))
.then(function() {
console.log('finished closing local sessions, now sending to contact');
return this.sendIndividualProto(number, proto, timestamp)
.catch(logError('resetSession/sendToContact error:'))
}.bind(this))
.then(function() {
return deleteAllSessions(number)
.catch(logError('resetSession/deleteAllSessions2 error:'));
});
}.bind(this));
var buffer = proto.toArrayBuffer();
var sendSync = this.sendSyncMessage(buffer, timestamp, number)
.catch(logError('resetSession/sendSync error:'));
return Promise.all([
sendToContact,
sendSync
]);
},
sendMessageToGroup: function(groupId, messageText, attachments, timestamp, expireTimer, profileKey) {
@ -40303,7 +40357,7 @@ textsecure.MessageSender = function(url, username, password, cdn_url) {
this.sendRequestContactSyncMessage = sender.sendRequestContactSyncMessage .bind(sender);
this.sendRequestConfigurationSyncMessage = sender.sendRequestConfigurationSyncMessage.bind(sender);
this.sendMessageToNumber = sender.sendMessageToNumber .bind(sender);
this.closeSession = sender.closeSession .bind(sender);
this.resetSession = sender.resetSession .bind(sender);
this.sendMessageToGroup = sender.sendMessageToGroup .bind(sender);
this.createGroup = sender.createGroup .bind(sender);
this.updateGroup = sender.updateGroup .bind(sender);

View File

@ -718,7 +718,7 @@
recipients : this.getRecipients(),
flags : textsecure.protobuf.DataMessage.Flags.END_SESSION
});
message.send(textsecure.messaging.closeSession(this.id, now));
message.send(textsecure.messaging.resetSession(this.id, now));
}
},
@ -984,8 +984,14 @@
}).then(function() {
var models = this.messageCollection.models;
this.messageCollection.reset([]);
_.each(models, function(message) { message.destroy(); });
this.save({lastMessage: null, timestamp: null}); // archive
_.each(models, function(message) {
message.destroy();
});
this.save({
lastMessage: null,
timestamp: null,
active_at: null,
});
}.bind(this));
},
@ -1011,6 +1017,24 @@
}
},
getDisplayName: function() {
if (!this.isPrivate()) {
return this.getTitle();
}
var name = this.get('name');
if (name) {
return name;
}
var profileName = this.get('profileName');
if (profileName) {
return this.getNumber() + ' ~' + profileName;
}
return this.getNumber();
},
getNumber: function() {
if (!this.isPrivate()) {
return '';

View File

@ -72,19 +72,33 @@
return this.sync('read', this, options);
},
// jscs:enable
getNameForNumber: function(number) {
var conversation = ConversationController.get(number);
if (!conversation) {
return number;
}
return conversation.getDisplayName();
},
getDescription: function() {
if (this.isGroupUpdate()) {
var group_update = this.get('group_update');
if (group_update.left) {
return i18n('leftTheGroup', group_update.left);
if (group_update.left === 'You') {
return i18n('youLeftTheGroup');
} else if (group_update.left) {
return i18n('leftTheGroup', this.getNameForNumber(group_update.left));
}
var messages = [i18n('updatedTheGroup')];
if (group_update.name) {
messages.push(i18n('titleIsNow', group_update.name));
}
if (group_update.joined) {
messages.push(i18n('joinedTheGroup', group_update.joined.join(', ')));
if (group_update.joined && group_update.joined.length) {
var names = _.map(group_update.joined, this.getNameForNumber.bind(this));
if (names.length > 1) {
messages.push(i18n('multipleJoinedTheGroup', names.join(', ')));
} else {
messages.push(i18n('joinedTheGroup', names[0]));
}
}
return messages.join(' ');

View File

@ -267,10 +267,13 @@
},
removeSignedPreKey: function(keyId) {
var prekey = new SignedPreKey({id: keyId});
return new Promise(function(resolve) {
prekey.destroy().then(function() {
resolve();
});
return new Promise(function(resolve, reject) {
var deferred = prekey.destroy();
if (!deferred) {
return resolve();
}
deferred.then(resolve, reject);
});
},

View File

@ -28,6 +28,12 @@
$el.insertBefore(target);
}
}
},
removeItem: function(conversation) {
var $el = this.$('.' + conversation.cid);
if ($el && $el.length > 0) {
$el.remove();
}
}
});
})();

View File

@ -649,6 +649,9 @@
this.model.messageCollection.add(message, {merge: true});
message.setToExpire();
if (message.isOutgoing()) {
this.removeLastSeenIndicator();
}
if (this.lastSeenIndicator) {
this.lastSeenIndicator.increment(1);
}

View File

@ -108,9 +108,16 @@
collection : inboxCollection
}).render();
this.inboxListView.listenTo(inboxCollection,
'add change:timestamp change:name change:number',
this.inboxListView.updateLocation);
this.inboxListView.listenTo(
inboxCollection,
'add change:timestamp change:name change:number',
this.inboxListView.updateLocation
);
this.inboxListView.listenTo(
inboxCollection,
'remove',
this.inboxListView.removeItem
);
this.searchView = new Whisper.ConversationSearchView({
el : this.$('.search-results'),

View File

@ -25399,21 +25399,18 @@ Curve25519Worker.prototype = {
/**
* The low 32 bits as a signed value.
* @type {number}
* @expose
*/
this.low = low | 0;
/**
* The high 32 bits as a signed value.
* @type {number}
* @expose
*/
this.high = high | 0;
/**
* Whether unsigned or not.
* @type {boolean}
* @expose
*/
this.unsigned = !!unsigned;
}
@ -25439,10 +25436,9 @@ Curve25519Worker.prototype = {
* An indicator used to reliably determine if an object is a Long or not.
* @type {boolean}
* @const
* @expose
* @private
*/
Long.__isLong__;
Long.prototype.__isLong__;
Object.defineProperty(Long.prototype, "__isLong__", {
value: true,
@ -25465,7 +25461,6 @@ Curve25519Worker.prototype = {
* @function
* @param {*} obj Object
* @returns {boolean}
* @expose
*/
Long.isLong = isLong;
@ -25522,7 +25517,6 @@ Curve25519Worker.prototype = {
* @param {number} value The 32 bit integer in question
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
* @returns {!Long} The corresponding Long value
* @expose
*/
Long.fromInt = fromInt;
@ -25557,7 +25551,6 @@ Curve25519Worker.prototype = {
* @param {number} value The number in question
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
* @returns {!Long} The corresponding Long value
* @expose
*/
Long.fromNumber = fromNumber;
@ -25580,7 +25573,6 @@ Curve25519Worker.prototype = {
* @param {number} highBits The high 32 bits
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
* @returns {!Long} The corresponding Long value
* @expose
*/
Long.fromBits = fromBits;
@ -25650,7 +25642,6 @@ Curve25519Worker.prototype = {
* @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed
* @param {number=} radix The radix in which the text is written (2-36), defaults to 10
* @returns {!Long} The corresponding Long value
* @expose
*/
Long.fromString = fromString;
@ -25676,7 +25667,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value
* @returns {!Long}
* @expose
*/
Long.fromValue = fromValue;
@ -25734,7 +25724,6 @@ Curve25519Worker.prototype = {
/**
* Signed zero.
* @type {!Long}
* @expose
*/
Long.ZERO = ZERO;
@ -25747,7 +25736,6 @@ Curve25519Worker.prototype = {
/**
* Unsigned zero.
* @type {!Long}
* @expose
*/
Long.UZERO = UZERO;
@ -25760,7 +25748,6 @@ Curve25519Worker.prototype = {
/**
* Signed one.
* @type {!Long}
* @expose
*/
Long.ONE = ONE;
@ -25773,7 +25760,6 @@ Curve25519Worker.prototype = {
/**
* Unsigned one.
* @type {!Long}
* @expose
*/
Long.UONE = UONE;
@ -25786,7 +25772,6 @@ Curve25519Worker.prototype = {
/**
* Signed negative one.
* @type {!Long}
* @expose
*/
Long.NEG_ONE = NEG_ONE;
@ -25799,7 +25784,6 @@ Curve25519Worker.prototype = {
/**
* Maximum signed value.
* @type {!Long}
* @expose
*/
Long.MAX_VALUE = MAX_VALUE;
@ -25812,7 +25796,6 @@ Curve25519Worker.prototype = {
/**
* Maximum unsigned value.
* @type {!Long}
* @expose
*/
Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE;
@ -25825,7 +25808,6 @@ Curve25519Worker.prototype = {
/**
* Minimum signed value.
* @type {!Long}
* @expose
*/
Long.MIN_VALUE = MIN_VALUE;
@ -25838,7 +25820,6 @@ Curve25519Worker.prototype = {
/**
* Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
* @returns {number}
* @expose
*/
LongPrototype.toInt = function toInt() {
return this.unsigned ? this.low >>> 0 : this.low;
@ -25847,7 +25828,6 @@ Curve25519Worker.prototype = {
/**
* Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
* @returns {number}
* @expose
*/
LongPrototype.toNumber = function toNumber() {
if (this.unsigned)
@ -25861,7 +25841,6 @@ Curve25519Worker.prototype = {
* @returns {string}
* @override
* @throws {RangeError} If `radix` is out of range
* @expose
*/
LongPrototype.toString = function toString(radix) {
radix = radix || 10;
@ -25904,7 +25883,6 @@ Curve25519Worker.prototype = {
/**
* Gets the high 32 bits as a signed integer.
* @returns {number} Signed high bits
* @expose
*/
LongPrototype.getHighBits = function getHighBits() {
return this.high;
@ -25913,7 +25891,6 @@ Curve25519Worker.prototype = {
/**
* Gets the high 32 bits as an unsigned integer.
* @returns {number} Unsigned high bits
* @expose
*/
LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() {
return this.high >>> 0;
@ -25922,7 +25899,6 @@ Curve25519Worker.prototype = {
/**
* Gets the low 32 bits as a signed integer.
* @returns {number} Signed low bits
* @expose
*/
LongPrototype.getLowBits = function getLowBits() {
return this.low;
@ -25931,7 +25907,6 @@ Curve25519Worker.prototype = {
/**
* Gets the low 32 bits as an unsigned integer.
* @returns {number} Unsigned low bits
* @expose
*/
LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() {
return this.low >>> 0;
@ -25940,7 +25915,6 @@ Curve25519Worker.prototype = {
/**
* Gets the number of bits needed to represent the absolute value of this Long.
* @returns {number}
* @expose
*/
LongPrototype.getNumBitsAbs = function getNumBitsAbs() {
if (this.isNegative()) // Unsigned Longs are never negative
@ -25955,7 +25929,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value equals zero.
* @returns {boolean}
* @expose
*/
LongPrototype.isZero = function isZero() {
return this.high === 0 && this.low === 0;
@ -25964,7 +25937,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value is negative.
* @returns {boolean}
* @expose
*/
LongPrototype.isNegative = function isNegative() {
return !this.unsigned && this.high < 0;
@ -25973,7 +25945,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value is positive.
* @returns {boolean}
* @expose
*/
LongPrototype.isPositive = function isPositive() {
return this.unsigned || this.high >= 0;
@ -25982,7 +25953,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value is odd.
* @returns {boolean}
* @expose
*/
LongPrototype.isOdd = function isOdd() {
return (this.low & 1) === 1;
@ -25991,7 +25961,6 @@ Curve25519Worker.prototype = {
/**
* Tests if this Long's value is even.
* @returns {boolean}
* @expose
*/
LongPrototype.isEven = function isEven() {
return (this.low & 1) === 0;
@ -26001,7 +25970,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value equals the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.equals = function equals(other) {
if (!isLong(other))
@ -26016,7 +25984,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.eq = LongPrototype.equals;
@ -26024,7 +25991,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value differs from the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.notEquals = function notEquals(other) {
return !this.eq(/* validates */ other);
@ -26035,7 +26001,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.neq = LongPrototype.notEquals;
@ -26043,7 +26008,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value is less than the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.lessThan = function lessThan(other) {
return this.comp(/* validates */ other) < 0;
@ -26054,7 +26018,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.lt = LongPrototype.lessThan;
@ -26062,7 +26025,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value is less than or equal the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) {
return this.comp(/* validates */ other) <= 0;
@ -26073,7 +26035,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.lte = LongPrototype.lessThanOrEqual;
@ -26081,7 +26042,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value is greater than the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.greaterThan = function greaterThan(other) {
return this.comp(/* validates */ other) > 0;
@ -26092,7 +26052,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.gt = LongPrototype.greaterThan;
@ -26100,7 +26059,6 @@ Curve25519Worker.prototype = {
* Tests if this Long's value is greater than or equal the specified's.
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) {
return this.comp(/* validates */ other) >= 0;
@ -26111,7 +26069,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} other Other value
* @returns {boolean}
* @expose
*/
LongPrototype.gte = LongPrototype.greaterThanOrEqual;
@ -26120,7 +26077,6 @@ Curve25519Worker.prototype = {
* @param {!Long|number|string} other Other value
* @returns {number} 0 if they are the same, 1 if the this is greater and -1
* if the given one is greater
* @expose
*/
LongPrototype.compare = function compare(other) {
if (!isLong(other))
@ -26146,14 +26102,12 @@ Curve25519Worker.prototype = {
* @param {!Long|number|string} other Other value
* @returns {number} 0 if they are the same, 1 if the this is greater and -1
* if the given one is greater
* @expose
*/
LongPrototype.comp = LongPrototype.compare;
/**
* Negates this Long's value.
* @returns {!Long} Negated Long
* @expose
*/
LongPrototype.negate = function negate() {
if (!this.unsigned && this.eq(MIN_VALUE))
@ -26165,7 +26119,6 @@ Curve25519Worker.prototype = {
* Negates this Long's value. This is an alias of {@link Long#negate}.
* @function
* @returns {!Long} Negated Long
* @expose
*/
LongPrototype.neg = LongPrototype.negate;
@ -26173,7 +26126,6 @@ Curve25519Worker.prototype = {
* Returns the sum of this and the specified Long.
* @param {!Long|number|string} addend Addend
* @returns {!Long} Sum
* @expose
*/
LongPrototype.add = function add(addend) {
if (!isLong(addend))
@ -26210,7 +26162,6 @@ Curve25519Worker.prototype = {
* Returns the difference of this and the specified Long.
* @param {!Long|number|string} subtrahend Subtrahend
* @returns {!Long} Difference
* @expose
*/
LongPrototype.subtract = function subtract(subtrahend) {
if (!isLong(subtrahend))
@ -26223,7 +26174,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} subtrahend Subtrahend
* @returns {!Long} Difference
* @expose
*/
LongPrototype.sub = LongPrototype.subtract;
@ -26231,7 +26181,6 @@ Curve25519Worker.prototype = {
* Returns the product of this and the specified Long.
* @param {!Long|number|string} multiplier Multiplier
* @returns {!Long} Product
* @expose
*/
LongPrototype.multiply = function multiply(multiplier) {
if (this.isZero())
@ -26299,7 +26248,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} multiplier Multiplier
* @returns {!Long} Product
* @expose
*/
LongPrototype.mul = LongPrototype.multiply;
@ -26308,7 +26256,6 @@ Curve25519Worker.prototype = {
* unsigned if this Long is unsigned.
* @param {!Long|number|string} divisor Divisor
* @returns {!Long} Quotient
* @expose
*/
LongPrototype.divide = function divide(divisor) {
if (!isLong(divisor))
@ -26319,6 +26266,8 @@ Curve25519Worker.prototype = {
return this.unsigned ? UZERO : ZERO;
var approx, rem, res;
if (!this.unsigned) {
// This section is only relevant for signed longs and is derived from the
// closure library as a whole.
if (this.eq(MIN_VALUE)) {
if (divisor.eq(ONE) || divisor.eq(NEG_ONE))
return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
@ -26344,19 +26293,18 @@ Curve25519Worker.prototype = {
return this.neg().div(divisor).neg();
} else if (divisor.isNegative())
return this.div(divisor.neg()).neg();
} else if (!divisor.unsigned)
divisor = divisor.toUnsigned();
// The algorithm below has not been made for unsigned longs. It's therefore
// required to take special care of the MSB prior to running it.
if (this.unsigned) {
res = ZERO;
} else {
// The algorithm below has not been made for unsigned longs. It's therefore
// required to take special care of the MSB prior to running it.
if (!divisor.unsigned)
divisor = divisor.toUnsigned();
if (divisor.gt(this))
return UZERO;
if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true
return UONE;
res = UZERO;
} else
res = ZERO;
}
// Repeat the following until the remainder is less than other: find a
// floating-point that approximates remainder / other *from below*, add this
@ -26400,7 +26348,6 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} divisor Divisor
* @returns {!Long} Quotient
* @expose
*/
LongPrototype.div = LongPrototype.divide;
@ -26408,7 +26355,6 @@ Curve25519Worker.prototype = {
* Returns this Long modulo the specified.
* @param {!Long|number|string} divisor Divisor
* @returns {!Long} Remainder
* @expose
*/
LongPrototype.modulo = function modulo(divisor) {
if (!isLong(divisor))
@ -26421,14 +26367,12 @@ Curve25519Worker.prototype = {
* @function
* @param {!Long|number|string} divisor Divisor
* @returns {!Long} Remainder
* @expose
*/
LongPrototype.mod = LongPrototype.modulo;
/**
* Returns the bitwise NOT of this Long.
* @returns {!Long}
* @expose
*/
LongPrototype.not = function not() {
return fromBits(~this.low, ~this.high, this.unsigned);
@ -26438,7 +26382,6 @@ Curve25519Worker.prototype = {
* Returns the bitwise AND of this Long and the specified.
* @param {!Long|number|string} other Other Long
* @returns {!Long}
* @expose
*/
LongPrototype.and = function and(other) {
if (!isLong(other))
@ -26450,7 +26393,6 @@ Curve25519Worker.prototype = {
* Returns the bitwise OR of this Long and the specified.
* @param {!Long|number|string} other Other Long
* @returns {!Long}
* @expose
*/
LongPrototype.or = function or(other) {
if (!isLong(other))
@ -26462,7 +26404,6 @@ Curve25519Worker.prototype = {
* Returns the bitwise XOR of this Long and the given one.
* @param {!Long|number|string} other Other Long
* @returns {!Long}
* @expose
*/
LongPrototype.xor = function xor(other) {
if (!isLong(other))
@ -26474,7 +26415,6 @@ Curve25519Worker.prototype = {
* Returns this Long with bits shifted to the left by the given amount.
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shiftLeft = function shiftLeft(numBits) {
if (isLong(numBits))
@ -26492,7 +26432,6 @@ Curve25519Worker.prototype = {
* @function
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shl = LongPrototype.shiftLeft;
@ -26500,7 +26439,6 @@ Curve25519Worker.prototype = {
* Returns this Long with bits arithmetically shifted to the right by the given amount.
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shiftRight = function shiftRight(numBits) {
if (isLong(numBits))
@ -26518,7 +26456,6 @@ Curve25519Worker.prototype = {
* @function
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shr = LongPrototype.shiftRight;
@ -26526,7 +26463,6 @@ Curve25519Worker.prototype = {
* Returns this Long with bits logically shifted to the right by the given amount.
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) {
if (isLong(numBits))
@ -26551,14 +26487,12 @@ Curve25519Worker.prototype = {
* @function
* @param {number|!Long} numBits Number of bits
* @returns {!Long} Shifted Long
* @expose
*/
LongPrototype.shru = LongPrototype.shiftRightUnsigned;
/**
* Converts this Long to signed.
* @returns {!Long} Signed long
* @expose
*/
LongPrototype.toSigned = function toSigned() {
if (!this.unsigned)
@ -26569,7 +26503,6 @@ Curve25519Worker.prototype = {
/**
* Converts this Long to unsigned.
* @returns {!Long} Unsigned long
* @expose
*/
LongPrototype.toUnsigned = function toUnsigned() {
if (this.unsigned)
@ -26577,6 +26510,53 @@ Curve25519Worker.prototype = {
return fromBits(this.low, this.high, true);
};
/**
* Converts this Long to its byte representation.
* @param {boolean=} le Whether little or big endian, defaults to big endian
* @returns {!Array.<number>} Byte representation
*/
LongPrototype.toBytes = function(le) {
return le ? this.toBytesLE() : this.toBytesBE();
}
/**
* Converts this Long to its little endian byte representation.
* @returns {!Array.<number>} Little endian byte representation
*/
LongPrototype.toBytesLE = function() {
var hi = this.high,
lo = this.low;
return [
lo & 0xff,
(lo >>> 8) & 0xff,
(lo >>> 16) & 0xff,
(lo >>> 24) & 0xff,
hi & 0xff,
(hi >>> 8) & 0xff,
(hi >>> 16) & 0xff,
(hi >>> 24) & 0xff
];
}
/**
* Converts this Long to its big endian byte representation.
* @returns {!Array.<number>} Big endian byte representation
*/
LongPrototype.toBytesBE = function() {
var hi = this.high,
lo = this.low;
return [
(hi >>> 24) & 0xff,
(hi >>> 16) & 0xff,
(hi >>> 8) & 0xff,
hi & 0xff,
(lo >>> 24) & 0xff,
(lo >>> 16) & 0xff,
(lo >>> 8) & 0xff,
lo & 0xff
];
}
return Long;
});
@ -35762,6 +35742,10 @@ Internal.SessionRecord = function() {
delete sessions[util.toString(oldestBaseKey)];
}
},
deleteAllSessions: function() {
// Used primarily in session reset scenarios, where we really delete sessions
this.sessions = {};
}
};
return SessionRecord;
@ -36257,7 +36241,7 @@ SessionCipher.prototype = {
}.bind(this));
},
doDecryptWhisperMessage: function(messageBytes, session) {
if (!messageBytes instanceof ArrayBuffer) {
if (!(messageBytes instanceof ArrayBuffer)) {
throw new Error("Expected messageBytes to be an ArrayBuffer");
}
var version = (new Uint8Array(messageBytes))[0];
@ -36432,6 +36416,20 @@ SessionCipher.prototype = {
return this.storage.storeSession(address, record.serialize());
}.bind(this));
}.bind(this));
},
deleteAllSessionsForDevice: function() {
// Used in session reset scenarios, where we really need to delete
var address = this.remoteAddress.toString();
return Internal.SessionLock.queueJobForNumber(address, function() {
return this.getRecord(address).then(function(record) {
if (record === undefined) {
return;
}
record.deleteAllSessions();
return this.storage.storeSession(address, record.serialize());
}.bind(this));
}.bind(this));
}
};
@ -36451,6 +36449,7 @@ libsignal.SessionCipher = function(storage, remoteAddress, options) {
this.getRemoteRegistrationId = cipher.getRemoteRegistrationId.bind(cipher);
this.hasOpenSession = cipher.hasOpenSession.bind(cipher);
this.closeOpenSessionForDevice = cipher.closeOpenSessionForDevice.bind(cipher);
this.deleteAllSessionsForDevice = cipher.deleteAllSessionsForDevice.bind(cipher);
};
/*

View File

@ -844,8 +844,8 @@ MessageReceiver.prototype.extend({
var address = new libsignal.SignalProtocolAddress(number, deviceId);
var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address);
console.log('closing session for', address.toString());
return sessionCipher.closeOpenSessionForDevice();
console.log('deleting sessions for', address.toString());
return sessionCipher.deleteAllSessionsForDevice();
}));
});
},

View File

@ -275,12 +275,14 @@ MessageSender.prototype = {
sendIndividualProto: function(number, proto, timestamp, silent) {
return new Promise(function(resolve, reject) {
this.sendMessageProto(timestamp, [number], proto, function(res) {
if (res.errors.length > 0)
var callback = function(res) {
if (res.errors.length > 0) {
reject(res);
else
} else {
resolve(res);
}, silent);
}
};
this.sendMessageProto(timestamp, [number], proto, callback, silent);
}.bind(this));
},
@ -455,10 +457,11 @@ MessageSender.prototype = {
return new Promise(function(resolve, reject) {
this.sendMessageProto(timestamp, numbers, proto, function(res) {
res.dataMessage = proto.toArrayBuffer();
if (res.errors.length > 0)
if (res.errors.length > 0) {
reject(res);
else
} else {
resolve(res);
}
}.bind(this));
}.bind(this));
},
@ -475,25 +478,56 @@ MessageSender.prototype = {
});
},
closeSession: function(number, timestamp) {
console.log('sending end session');
resetSession: function(number, timestamp) {
console.log('resetting secure session');
var proto = new textsecure.protobuf.DataMessage();
proto.body = "TERMINATE";
proto.flags = textsecure.protobuf.DataMessage.Flags.END_SESSION;
return this.sendIndividualProto(number, proto, timestamp).then(function(res) {
return this.sendSyncMessage(proto.toArrayBuffer(), timestamp, number).then(function() {
return textsecure.storage.protocol.getDeviceIds(number).then(function(deviceIds) {
var logError = function(prefix) {
return function(error) {
console.log(
prefix,
error && error.stack ? error.stack : error
);
throw error;
};
};
var deleteAllSessions = function(number) {
return textsecure.storage.protocol.getDeviceIds(number)
.then(function(deviceIds) {
return Promise.all(deviceIds.map(function(deviceId) {
var address = new libsignal.SignalProtocolAddress(number, deviceId);
console.log('closing session for', address.toString());
var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address);
return sessionCipher.closeOpenSessionForDevice();
})).then(function() {
return res;
});
console.log('deleting sessions for', address.toString());
var sessionCipher = new libsignal.SessionCipher(
textsecure.storage.protocol,
address
);
return sessionCipher.deleteAllSessionsForDevice();
}));
});
};
var sendToContact = deleteAllSessions(number)
.catch(logError('resetSession/deleteAllSessions1 error:'))
.then(function() {
console.log('finished closing local sessions, now sending to contact');
return this.sendIndividualProto(number, proto, timestamp)
.catch(logError('resetSession/sendToContact error:'))
}.bind(this))
.then(function() {
return deleteAllSessions(number)
.catch(logError('resetSession/deleteAllSessions2 error:'));
});
}.bind(this));
var buffer = proto.toArrayBuffer();
var sendSync = this.sendSyncMessage(buffer, timestamp, number)
.catch(logError('resetSession/sendSync error:'));
return Promise.all([
sendToContact,
sendSync
]);
},
sendMessageToGroup: function(groupId, messageText, attachments, timestamp, expireTimer, profileKey) {
@ -682,7 +716,7 @@ textsecure.MessageSender = function(url, username, password, cdn_url) {
this.sendRequestContactSyncMessage = sender.sendRequestContactSyncMessage .bind(sender);
this.sendRequestConfigurationSyncMessage = sender.sendRequestConfigurationSyncMessage.bind(sender);
this.sendMessageToNumber = sender.sendMessageToNumber .bind(sender);
this.closeSession = sender.closeSession .bind(sender);
this.resetSession = sender.resetSession .bind(sender);
this.sendMessageToGroup = sender.sendMessageToGroup .bind(sender);
this.createGroup = sender.createGroup .bind(sender);
this.updateGroup = sender.updateGroup .bind(sender);

16
main.js
View File

@ -24,6 +24,10 @@ app.setAppUserModelId(aumid);
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
function getMainWindow() {
return mainWindow;
}
const config = require("./app/config");
// Very important to put before the single instance check, since it is based on the
@ -249,7 +253,8 @@ function showAbout() {
webPreferences: {
nodeIntegration: false,
preload: path.join(__dirname, 'preload.js')
}
},
parent: mainWindow,
};
aboutWindow = new BrowserWindow(options);
@ -279,7 +284,7 @@ app.on('ready', function() {
locale = loadLocale();
}
autoUpdate.initialize(locale.messages);
autoUpdate.initialize(getMainWindow, locale.messages);
createWindow();
@ -356,3 +361,10 @@ ipc.on("set-auto-hide-menu-bar", function(event, autoHide) {
ipc.on("set-menu-bar-visibility", function(event, visibility) {
mainWindow.setMenuBarVisibility(visibility);
});
ipc.on("close-about", function() {
if (aboutWindow) {
aboutWindow.close();
}
});

View File

@ -31,6 +31,10 @@
console.log('restart');
ipc.send('restart');
};
window.closeAbout = function() {
ipc.send('close-about');
};
ipc.on('debug-log', function() {
Whisper.events.trigger('showDebugLog');
});