Support for web socket communication with no signaling key

This commit is contained in:
Scott Nonnenberg 2019-01-11 08:53:35 -08:00
parent 00755072ee
commit 43e5d16020
7 changed files with 66 additions and 25 deletions

View file

@ -681,7 +681,19 @@
textsecure.storage.user.getDeviceId() != '1'
) {
window.getSyncRequest();
window.getAccountManager().maybeUpdateDeviceName();
try {
const manager = window.getAccountManager();
await Promise.all([
manager.maybeUpdateDeviceName(),
manager.maybeDeleteSignalingKey(),
]);
} catch (e) {
window.log.error(
'Problem with account manager updates after starting new version: ',
e && e.stack ? e.stack : e
);
}
}
const udSupportKey = 'hasRegisterSupportForUnauthenticatedDelivery';

View file

@ -326,6 +326,7 @@ function HTTPError(message, providedCode, response, stack) {
const URL_CALLS = {
accounts: 'v1/accounts',
updateDeviceName: 'v1/accounts/name',
removeSignalingKey: 'v1/accounts/signaling_key',
attachment: 'v1/attachments',
deliveryCert: 'v1/certificate/delivery',
supportUnauthenticatedDelivery: 'v1/devices/unauthenticated_delivery',
@ -388,6 +389,7 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
sendMessagesUnauth,
setSignedPreKey,
updateDeviceName,
removeSignalingKey,
};
function _ajax(param) {
@ -518,14 +520,12 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
number,
code,
newPassword,
signalingKey,
registrationId,
deviceName,
options = {}
) {
const { accessKey } = options;
const jsonData = {
signalingKey: _btoa(_getString(signalingKey)),
supportsSms: false,
fetchesMessages: true,
registrationId,
@ -580,6 +580,13 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
});
}
function removeSignalingKey() {
return _ajax({
call: 'removeSignalingKey',
httpType: 'DELETE',
});
}
function getDevices() {
return _ajax({
call: 'devices',

View file

@ -99,6 +99,12 @@
async deviceNameIsEncrypted() {
await textsecure.storage.user.setDeviceNameEncrypted();
},
async maybeDeleteSignalingKey() {
const key = await textsecure.storage.user.getSignalingKey();
if (key) {
await this.server.removeSignalingKey();
}
},
registerSingleDevice(number, verificationCode) {
const registerKeys = this.server.registerKeys.bind(this.server);
const createAccount = this.createAccount.bind(this);
@ -400,7 +406,6 @@
options = {}
) {
const { accessKey } = options;
const signalingKey = libsignal.crypto.getRandomBytes(32 + 20);
let password = btoa(getString(libsignal.crypto.getRandomBytes(16)));
password = password.substring(0, password.length - 2);
const registrationId = libsignal.KeyHelper.generateRegistrationId();
@ -417,7 +422,6 @@
number,
verificationCode,
password,
signalingKey,
registrationId,
encryptedDeviceName,
{ accessKey }
@ -441,7 +445,6 @@
await Promise.all([
textsecure.storage.remove('identityKey'),
textsecure.storage.remove('signaling_key'),
textsecure.storage.remove('password'),
textsecure.storage.remove('registrationId'),
textsecure.storage.remove('number_id'),
@ -464,7 +467,6 @@
});
await textsecure.storage.put('identityKey', identityKeyPair);
await textsecure.storage.put('signaling_key', signalingKey);
await textsecure.storage.put('password', password);
await textsecure.storage.put('registrationId', registrationId);
if (profileKey) {

View file

@ -274,8 +274,18 @@ MessageReceiver.prototype.extend({
return;
}
const promise = textsecure.crypto
.decryptWebsocketMessage(request.body, this.signalingKey)
let promise;
const headers = request.headers || [];
if (headers.includes('X-Signal-Key: true')) {
promise = textsecure.crypto.decryptWebsocketMessage(
request.body,
this.signalingKey
);
} else {
promise = Promise.resolve(request.body.toArrayBuffer());
}
promise = promise
.then(plaintext => {
const envelope = textsecure.protobuf.Envelope.decode(plaintext);
// After this point, decoding errors are not the server's

View file

@ -39,5 +39,9 @@
getDeviceNameEncrypted() {
return textsecure.storage.get('deviceNameEncrypted');
},
getSignalingKey() {
return textsecure.storage.get('signaling_key');
},
};
})();

View file

@ -27,6 +27,7 @@
const Request = function Request(options) {
this.verb = options.verb || options.type;
this.path = options.path || options.url;
this.headers = options.headers;
this.body = options.body || options.data;
this.success = options.success;
this.error = options.error;
@ -50,6 +51,7 @@
this.verb = request.verb;
this.path = request.path;
this.body = request.body;
this.headers = request.headers;
this.respond = (status, message) => {
socket.send(
@ -77,6 +79,7 @@
verb: request.verb,
path: request.path,
body: request.body,
headers: request.headers,
id: request.id,
},
})
@ -105,6 +108,7 @@
verb: message.request.verb,
path: message.request.path,
body: message.request.body,
headers: message.request.headers,
id: message.request.id,
socket,
})

View file

@ -19,27 +19,29 @@ package signalservice;
option java_package = "org.whispersystems.websocket.messages.protobuf";
message WebSocketRequestMessage {
optional string verb = 1;
optional string path = 2;
optional bytes body = 3;
optional uint64 id = 4;
optional string verb = 1;
optional string path = 2;
optional bytes body = 3;
repeated string headers = 5;
optional uint64 id = 4;
}
message WebSocketResponseMessage {
optional uint64 id = 1;
optional uint32 status = 2;
optional string message = 3;
optional bytes body = 4;
optional uint64 id = 1;
optional uint32 status = 2;
optional string message = 3;
repeated string headers = 5;
optional bytes body = 4;
}
message WebSocketMessage {
enum Type {
UNKNOWN = 0;
REQUEST = 1;
RESPONSE = 2;
}
enum Type {
UNKNOWN = 0;
REQUEST = 1;
RESPONSE = 2;
}
optional Type type = 1;
optional WebSocketRequestMessage request = 2;
optional WebSocketResponseMessage response = 3;
optional Type type = 1;
optional WebSocketRequestMessage request = 2;
optional WebSocketResponseMessage response = 3;
}