Add replayable error for signed key failure

Disable message sending if signed key updates fail too many times, but
allow the user to retry sending.

// FREEBIE
This commit is contained in:
lilia 2017-02-15 18:27:06 -08:00
parent e0fd188d42
commit cd0fe7037b
5 changed files with 77 additions and 7 deletions

View file

@ -11,6 +11,7 @@
INIT_SESSION: 2, INIT_SESSION: 2,
TRANSMIT_MESSAGE: 3, TRANSMIT_MESSAGE: 3,
REBUILD_MESSAGE: 4, REBUILD_MESSAGE: 4,
RETRY_SEND_MESSAGE_PROTO: 5
}; };
window.textsecure = window.textsecure || {}; window.textsecure = window.textsecure || {};
window.textsecure.replay = { window.textsecure.replay = {
@ -89,6 +90,17 @@
SendMessageNetworkError.prototype = new ReplayableError(); SendMessageNetworkError.prototype = new ReplayableError();
SendMessageNetworkError.prototype.constructor = SendMessageNetworkError; SendMessageNetworkError.prototype.constructor = SendMessageNetworkError;
function SignedPreKeyRotationError(numbers, message, timestamp) {
ReplayableError.call(this, {
functionCode : Type.RETRY_SEND_MESSAGE_PROTO,
args : [numbers, message, timestamp]
});
this.name = 'SignedPreKeyRotationError';
this.message = "Too many signed prekey rotation failures";
}
SignedPreKeyRotationError.prototype = new ReplayableError();
SignedPreKeyRotationError.prototype.constructor = SignedPreKeyRotationError;
function MessageError(message, httpError) { function MessageError(message, httpError) {
ReplayableError.call(this, { ReplayableError.call(this, {
functionCode : Type.REBUILD_MESSAGE, functionCode : Type.REBUILD_MESSAGE,
@ -119,6 +131,7 @@
window.textsecure.ReplayableError = ReplayableError; window.textsecure.ReplayableError = ReplayableError;
window.textsecure.OutgoingMessageError = OutgoingMessageError; window.textsecure.OutgoingMessageError = OutgoingMessageError;
window.textsecure.MessageError = MessageError; window.textsecure.MessageError = MessageError;
window.textsecure.SignedPreKeyRotationError = SignedPreKeyRotationError;
})(); })();
@ -39014,6 +39027,11 @@ MessageSender.prototype = {
}.bind(this)); }.bind(this));
}, },
sendMessageProto: function(timestamp, numbers, message, callback) { sendMessageProto: function(timestamp, numbers, message, callback) {
var rejections = textsecure.storage.get('signedKeyRotationRejected', 0);
if (rejections > 5) {
throw new textsecure.SignedPreKeyRotationError(numbers, message.toArrayBuffer(), timestamp);
}
var outgoing = new OutgoingMessage(this.server, timestamp, numbers, message, callback); var outgoing = new OutgoingMessage(this.server, timestamp, numbers, message, callback);
numbers.forEach(function(number) { numbers.forEach(function(number) {
@ -39023,6 +39041,18 @@ MessageSender.prototype = {
}.bind(this)); }.bind(this));
}, },
retrySendMessageProto: function(numbers, encodedMessage, timestamp) {
var proto = textsecure.protobuf.DataMessage.decode(encodedMessage);
return new Promise(function(resolve, reject) {
this.sendMessageProto(timestamp, numbers, proto, function(res) {
if (res.errors.length > 0)
reject(res);
else
resolve(res);
});
}.bind(this));
},
sendIndividualProto: function(number, proto, timestamp) { sendIndividualProto: function(number, proto, timestamp) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
this.sendMessageProto(timestamp, [number], proto, function(res) { this.sendMessageProto(timestamp, [number], proto, function(res) {
@ -39330,6 +39360,7 @@ textsecure.MessageSender = function(url, ports, username, password, attachment_s
textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.ENCRYPT_MESSAGE); textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.ENCRYPT_MESSAGE);
textsecure.replay.registerFunction(sender.retransmitMessage.bind(sender), textsecure.replay.Type.TRANSMIT_MESSAGE); textsecure.replay.registerFunction(sender.retransmitMessage.bind(sender), textsecure.replay.Type.TRANSMIT_MESSAGE);
textsecure.replay.registerFunction(sender.sendMessage.bind(sender), textsecure.replay.Type.REBUILD_MESSAGE); textsecure.replay.registerFunction(sender.sendMessage.bind(sender), textsecure.replay.Type.REBUILD_MESSAGE);
textsecure.replay.registerFunction(sender.retrySendMessageProto.bind(sender), textsecure.replay.Type.RETRY_SEND_MESSAGE_PROTO);
this.sendExpirationTimerUpdateToNumber = sender.sendExpirationTimerUpdateToNumber.bind(sender); this.sendExpirationTimerUpdateToNumber = sender.sendExpirationTimerUpdateToNumber.bind(sender);
this.sendExpirationTimerUpdateToGroup = sender.sendExpirationTimerUpdateToGroup .bind(sender); this.sendExpirationTimerUpdateToGroup = sender.sendExpirationTimerUpdateToGroup .bind(sender);

View file

@ -211,6 +211,9 @@
if (result instanceof Error) { if (result instanceof Error) {
errors = [result]; errors = [result];
this.saveErrors(errors); this.saveErrors(errors);
if (result.name === 'SignedPreKeyRotationError') {
getAccountManager().rotateSignedPreKey();
}
} else { } else {
errors = result.errors; errors = result.errors;
this.saveErrors(errors); this.saveErrors(errors);
@ -283,7 +286,8 @@
var error = _.find(this.get('errors'), function(e) { var error = _.find(this.get('errors'), function(e) {
return (e.name === 'MessageError' || return (e.name === 'MessageError' ||
e.name === 'OutgoingMessageError' || e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError'); e.name === 'SendMessageNetworkError' ||
e.name === 'SignedPreKeyRotationError');
}); });
return !!error; return !!error;
}, },
@ -292,11 +296,18 @@
return e.number === number && return e.number === number &&
(e.name === 'MessageError' || (e.name === 'MessageError' ||
e.name === 'OutgoingMessageError' || e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError'); e.name === 'SendMessageNetworkError' ||
e.name === 'SignedPreKeyRotationError');
}); });
this.set({errors: errors[1]}); this.set({errors: errors[1]});
return errors[0][0]; return errors[0][0];
}, },
isReplayableError: function(e) {
return (e.name === 'MessageError' ||
e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError' ||
e.name === 'SignedPreKeyRotationError');
},
resend: function(number) { resend: function(number) {
var error = this.removeOutgoingErrors(number); var error = this.removeOutgoingErrors(number);

View file

@ -131,11 +131,8 @@
'click .error-message': 'select' 'click .error-message': 'select'
}, },
retryMessage: function() { retryMessage: function() {
var retrys = _.filter(this.model.get('errors'), function(e) { var retrys = _.filter(this.model.get('errors'),
return (e.name === 'MessageError' || this.model.isReplayableError.bind(this.model));
e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError');
});
_.map(retrys, 'number').forEach(function(number) { _.map(retrys, 'number').forEach(function(number) {
this.model.resend(number); this.model.resend(number);
}.bind(this)); }.bind(this));

View file

@ -10,6 +10,7 @@
INIT_SESSION: 2, INIT_SESSION: 2,
TRANSMIT_MESSAGE: 3, TRANSMIT_MESSAGE: 3,
REBUILD_MESSAGE: 4, REBUILD_MESSAGE: 4,
RETRY_SEND_MESSAGE_PROTO: 5
}; };
window.textsecure = window.textsecure || {}; window.textsecure = window.textsecure || {};
window.textsecure.replay = { window.textsecure.replay = {
@ -88,6 +89,17 @@
SendMessageNetworkError.prototype = new ReplayableError(); SendMessageNetworkError.prototype = new ReplayableError();
SendMessageNetworkError.prototype.constructor = SendMessageNetworkError; SendMessageNetworkError.prototype.constructor = SendMessageNetworkError;
function SignedPreKeyRotationError(numbers, message, timestamp) {
ReplayableError.call(this, {
functionCode : Type.RETRY_SEND_MESSAGE_PROTO,
args : [numbers, message, timestamp]
});
this.name = 'SignedPreKeyRotationError';
this.message = "Too many signed prekey rotation failures";
}
SignedPreKeyRotationError.prototype = new ReplayableError();
SignedPreKeyRotationError.prototype.constructor = SignedPreKeyRotationError;
function MessageError(message, httpError) { function MessageError(message, httpError) {
ReplayableError.call(this, { ReplayableError.call(this, {
functionCode : Type.REBUILD_MESSAGE, functionCode : Type.REBUILD_MESSAGE,
@ -118,5 +130,6 @@
window.textsecure.ReplayableError = ReplayableError; window.textsecure.ReplayableError = ReplayableError;
window.textsecure.OutgoingMessageError = OutgoingMessageError; window.textsecure.OutgoingMessageError = OutgoingMessageError;
window.textsecure.MessageError = MessageError; window.textsecure.MessageError = MessageError;
window.textsecure.SignedPreKeyRotationError = SignedPreKeyRotationError;
})(); })();

View file

@ -183,6 +183,11 @@ MessageSender.prototype = {
}.bind(this)); }.bind(this));
}, },
sendMessageProto: function(timestamp, numbers, message, callback) { sendMessageProto: function(timestamp, numbers, message, callback) {
var rejections = textsecure.storage.get('signedKeyRotationRejected', 0);
if (rejections > 5) {
throw new textsecure.SignedPreKeyRotationError(numbers, message.toArrayBuffer(), timestamp);
}
var outgoing = new OutgoingMessage(this.server, timestamp, numbers, message, callback); var outgoing = new OutgoingMessage(this.server, timestamp, numbers, message, callback);
numbers.forEach(function(number) { numbers.forEach(function(number) {
@ -192,6 +197,18 @@ MessageSender.prototype = {
}.bind(this)); }.bind(this));
}, },
retrySendMessageProto: function(numbers, encodedMessage, timestamp) {
var proto = textsecure.protobuf.DataMessage.decode(encodedMessage);
return new Promise(function(resolve, reject) {
this.sendMessageProto(timestamp, numbers, proto, function(res) {
if (res.errors.length > 0)
reject(res);
else
resolve(res);
});
}.bind(this));
},
sendIndividualProto: function(number, proto, timestamp) { sendIndividualProto: function(number, proto, timestamp) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
this.sendMessageProto(timestamp, [number], proto, function(res) { this.sendMessageProto(timestamp, [number], proto, function(res) {
@ -499,6 +516,7 @@ textsecure.MessageSender = function(url, ports, username, password, attachment_s
textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.ENCRYPT_MESSAGE); textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.ENCRYPT_MESSAGE);
textsecure.replay.registerFunction(sender.retransmitMessage.bind(sender), textsecure.replay.Type.TRANSMIT_MESSAGE); textsecure.replay.registerFunction(sender.retransmitMessage.bind(sender), textsecure.replay.Type.TRANSMIT_MESSAGE);
textsecure.replay.registerFunction(sender.sendMessage.bind(sender), textsecure.replay.Type.REBUILD_MESSAGE); textsecure.replay.registerFunction(sender.sendMessage.bind(sender), textsecure.replay.Type.REBUILD_MESSAGE);
textsecure.replay.registerFunction(sender.retrySendMessageProto.bind(sender), textsecure.replay.Type.RETRY_SEND_MESSAGE_PROTO);
this.sendExpirationTimerUpdateToNumber = sender.sendExpirationTimerUpdateToNumber.bind(sender); this.sendExpirationTimerUpdateToNumber = sender.sendExpirationTimerUpdateToNumber.bind(sender);
this.sendExpirationTimerUpdateToGroup = sender.sendExpirationTimerUpdateToGroup .bind(sender); this.sendExpirationTimerUpdateToGroup = sender.sendExpirationTimerUpdateToGroup .bind(sender);