diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 3786e9e47..b4ca335a2 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -324,5 +324,9 @@
"timestampFormat_M": {
"description": "Timestamp format string for displaying month and day (but not the year) of a date within the current year, ex: use 'MMM D' for 'Aug 8', or 'D MMM' for '8 Aug'.",
"message": "MMM D"
+ },
+ "unblockToSend": {
+ "message": "Unblock this contact to send a message.",
+ "description": "Brief message shown when trying to message a blocked number"
}
}
diff --git a/background.html b/background.html
index c5d338eef..d90c903b9 100644
--- a/background.html
+++ b/background.html
@@ -479,6 +479,7 @@
+
diff --git a/js/libtextsecure.js b/js/libtextsecure.js
index 3e5a033f1..44f1ff3e4 100644
--- a/js/libtextsecure.js
+++ b/js/libtextsecure.js
@@ -38100,7 +38100,10 @@ MessageReceiver.prototype.extend({
// fault, and we should handle them gracefully and tell the
// user they received an invalid message
request.respond(200, 'OK');
- this.queueEnvelope(envelope);
+
+ if (!this.isBlocked(envelope.source)) {
+ this.queueEnvelope(envelope);
+ }
}.bind(this)).catch(function(e) {
request.respond(500, 'Bad encrypted websocket message');
@@ -38272,6 +38275,8 @@ MessageReceiver.prototype.extend({
this.handleContacts(syncMessage.contacts);
} else if (syncMessage.groups) {
this.handleGroups(syncMessage.groups);
+ } else if (syncMessage.blocked) {
+ this.handleBlocked(syncMessage.blocked);
} else if (syncMessage.request) {
console.log('Got SyncMessage Request');
} else if (syncMessage.read) {
@@ -38348,6 +38353,12 @@ MessageReceiver.prototype.extend({
});
});
},
+ handleBlocked: function(blocked) {
+ textsecure.storage.put('blocked', blocked.numbers);
+ },
+ isBlocked: function(number) {
+ return textsecure.storage.get('blocked', []).indexOf(number) >= 0;
+ },
handleAttachment: function(attachment) {
function decryptAttachment(encrypted) {
return textsecure.crypto.decryptAttachment(
diff --git a/js/models/blockedNumbers.js b/js/models/blockedNumbers.js
new file mode 100644
index 000000000..76aa6a996
--- /dev/null
+++ b/js/models/blockedNumbers.js
@@ -0,0 +1,10 @@
+/*
+ * vim: ts=4:sw=4:expandtab
+ */
+(function () {
+ 'use strict';
+ window.Whisper = window.Whisper || {};
+ storage.isBlocked = function(number) {
+ return storage.get('blocked', []).indexOf(number) >= 0;
+ };
+})();
diff --git a/js/views/conversation_view.js b/js/views/conversation_view.js
index 14d2f4391..13d6e9924 100644
--- a/js/views/conversation_view.js
+++ b/js/views/conversation_view.js
@@ -10,6 +10,11 @@
return { toastMessage: i18n('expiredWarning') };
}
});
+ Whisper.BlockedToast = Whisper.ToastView.extend({
+ render_attributes: function() {
+ return { toastMessage: i18n('unblockToSend') };
+ }
+ });
Whisper.ConversationView = Whisper.View.extend({
className: function() {
@@ -276,6 +281,12 @@
toast.render();
return;
}
+ if (this.model.isPrivate() && storage.isBlocked(this.model.id)) {
+ var toast = new Whisper.BlockedToast();
+ toast.$el.insertAfter(this.$el);
+ toast.render();
+ return;
+ }
e.preventDefault();
var input = this.$messageField;
var message = this.replace_colons(input.val()).trim();
diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js
index 5fed062aa..6e8d98b9b 100644
--- a/libtextsecure/message_receiver.js
+++ b/libtextsecure/message_receiver.js
@@ -70,7 +70,10 @@ MessageReceiver.prototype.extend({
// fault, and we should handle them gracefully and tell the
// user they received an invalid message
request.respond(200, 'OK');
- this.queueEnvelope(envelope);
+
+ if (!this.isBlocked(envelope.source)) {
+ this.queueEnvelope(envelope);
+ }
}.bind(this)).catch(function(e) {
request.respond(500, 'Bad encrypted websocket message');
@@ -242,6 +245,8 @@ MessageReceiver.prototype.extend({
this.handleContacts(syncMessage.contacts);
} else if (syncMessage.groups) {
this.handleGroups(syncMessage.groups);
+ } else if (syncMessage.blocked) {
+ this.handleBlocked(syncMessage.blocked);
} else if (syncMessage.request) {
console.log('Got SyncMessage Request');
} else if (syncMessage.read) {
@@ -318,6 +323,12 @@ MessageReceiver.prototype.extend({
});
});
},
+ handleBlocked: function(blocked) {
+ textsecure.storage.put('blocked', blocked.numbers);
+ },
+ isBlocked: function(number) {
+ return textsecure.storage.get('blocked', []).indexOf(number) >= 0;
+ },
handleAttachment: function(attachment) {
function decryptAttachment(encrypted) {
return textsecure.crypto.decryptAttachment(
diff --git a/protos/IncomingPushMessageSignal.proto b/protos/IncomingPushMessageSignal.proto
index 9c780bbca..652a3ebe7 100644
--- a/protos/IncomingPushMessageSignal.proto
+++ b/protos/IncomingPushMessageSignal.proto
@@ -52,11 +52,16 @@ message SyncMessage {
optional AttachmentPointer blob = 1;
}
+ message Blocked {
+ repeated string numbers = 1;
+ }
+
message Request {
enum Type {
UNKNOWN = 0;
CONTACTS = 1;
GROUPS = 2;
+ BLOCKED = 3;
}
optional Type type = 1;
}
@@ -70,6 +75,7 @@ message SyncMessage {
optional Groups groups = 3;
optional Request request = 4;
repeated Read read = 5;
+ optional Blocked blocked = 6;
}
message AttachmentPointer {