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' textsecure.storage.user.getDeviceId() != '1'
) { ) {
window.getSyncRequest(); 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'; const udSupportKey = 'hasRegisterSupportForUnauthenticatedDelivery';

View file

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

View file

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

View file

@ -274,8 +274,18 @@ MessageReceiver.prototype.extend({
return; return;
} }
const promise = textsecure.crypto let promise;
.decryptWebsocketMessage(request.body, this.signalingKey) 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 => { .then(plaintext => {
const envelope = textsecure.protobuf.Envelope.decode(plaintext); const envelope = textsecure.protobuf.Envelope.decode(plaintext);
// After this point, decoding errors are not the server's // After this point, decoding errors are not the server's

View file

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

View file

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

View file

@ -22,6 +22,7 @@ message WebSocketRequestMessage {
optional string verb = 1; optional string verb = 1;
optional string path = 2; optional string path = 2;
optional bytes body = 3; optional bytes body = 3;
repeated string headers = 5;
optional uint64 id = 4; optional uint64 id = 4;
} }
@ -29,6 +30,7 @@ message WebSocketResponseMessage {
optional uint64 id = 1; optional uint64 id = 1;
optional uint32 status = 2; optional uint32 status = 2;
optional string message = 3; optional string message = 3;
repeated string headers = 5;
optional bytes body = 4; optional bytes body = 4;
} }