Mostly done device-bringup stuff
This commit is contained in:
parent
c0a8c00884
commit
02d0c58e5e
8 changed files with 64 additions and 73 deletions
|
@ -5694,8 +5694,8 @@ CryptoJS.lib.Cipher || (function (undefined) {
|
||||||
WhisperMessage : protocolMessages.WhisperMessage,
|
WhisperMessage : protocolMessages.WhisperMessage,
|
||||||
PreKeyWhisperMessage : protocolMessages.PreKeyWhisperMessage,
|
PreKeyWhisperMessage : protocolMessages.PreKeyWhisperMessage,
|
||||||
ProvisioningUuid : deviceMessages.ProvisioningUuid,
|
ProvisioningUuid : deviceMessages.ProvisioningUuid,
|
||||||
DeviceInit : deviceMessages.DeviceInit,
|
ProvisionEnvelope : deviceMessages.ProvisionEnvelope,
|
||||||
IdentityKey : deviceMessages.IdentityKey,
|
ProvisionMessage : deviceMessages.ProvisionMessage,
|
||||||
DeviceControl : deviceMessages.DeviceControl,
|
DeviceControl : deviceMessages.DeviceControl,
|
||||||
WebSocketResponseMessage : subProtocolMessages.WebSocketResponseMessage,
|
WebSocketResponseMessage : subProtocolMessages.WebSocketResponseMessage,
|
||||||
WebSocketRequestMessage : subProtocolMessages.WebSocketRequestMessage,
|
WebSocketRequestMessage : subProtocolMessages.WebSocketRequestMessage,
|
||||||
|
@ -6190,13 +6190,9 @@ window.textsecure.registerSingleDevice = function(number, verificationCode, step
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.textsecure.registerSecondDevice = function(encodedDeviceInit, cryptoInfo, stepDone) {
|
window.textsecure.registerSecondDevice = function(encodedProvisionEnvelope, cryptoInfo, stepDone) {
|
||||||
var deviceInit = textsecure.protobuf.DeviceInit.decode(encodedDeviceInit, 'binary');
|
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(encodedProvisionEnvelope, 'binary');
|
||||||
return cryptoInfo.decryptAndHandleDeviceInit(deviceInit).then(function(identityKey) {
|
return cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(identityKey) {
|
||||||
if (identityKey.server != textsecure.api.relay)
|
|
||||||
throw new Error("Unknown relay used by master");
|
|
||||||
var number = identityKey.phoneNumber;
|
|
||||||
|
|
||||||
stepDone(1);
|
stepDone(1);
|
||||||
|
|
||||||
var signalingKey = textsecure.crypto.getRandomBytes(32 + 20);
|
var signalingKey = textsecure.crypto.getRandomBytes(32 + 20);
|
||||||
|
@ -6210,10 +6206,10 @@ window.textsecure.registerSecondDevice = function(encodedDeviceInit, cryptoInfo,
|
||||||
registrationId = registrationId & 0x3fff;
|
registrationId = registrationId & 0x3fff;
|
||||||
textsecure.storage.putUnencrypted("registrationId", registrationId);
|
textsecure.storage.putUnencrypted("registrationId", registrationId);
|
||||||
|
|
||||||
return textsecure.api.confirmCode(number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) {
|
return textsecure.api.confirmCode(identityKey.number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) {
|
||||||
var numberId = number + "." + result;
|
var numberId = identityKey.number + "." + result.deviceId;
|
||||||
textsecure.storage.putUnencrypted("number_id", numberId);
|
textsecure.storage.putUnencrypted("number_id", numberId);
|
||||||
textsecure.storage.putUnencrypted("regionCode", libphonenumber.util.getRegion(number));
|
textsecure.storage.putUnencrypted("regionCode", libphonenumber.util.getRegionCodeForNumber(identityKey.number));
|
||||||
stepDone(2);
|
stepDone(2);
|
||||||
|
|
||||||
return textsecure.protocol.generateKeys().then(function(keys) {
|
return textsecure.protocol.generateKeys().then(function(keys) {
|
||||||
|
@ -6758,7 +6754,7 @@ window.textsecure.api = function () {
|
||||||
URL_CALLS.devices = "/v1/devices";
|
URL_CALLS.devices = "/v1/devices";
|
||||||
URL_CALLS.keys = "/v2/keys";
|
URL_CALLS.keys = "/v2/keys";
|
||||||
URL_CALLS.push = "/v1/websocket";
|
URL_CALLS.push = "/v1/websocket";
|
||||||
URL_CALLS.temp_push = "/v1/provisioning";
|
URL_CALLS.temp_push = "/v1/websocket/provisioning";
|
||||||
URL_CALLS.messages = "/v1/messages";
|
URL_CALLS.messages = "/v1/messages";
|
||||||
URL_CALLS.attachment = "/v1/attachments";
|
URL_CALLS.attachment = "/v1/attachments";
|
||||||
|
|
||||||
|
@ -7950,26 +7946,26 @@ window.textsecure.protocol = function() {
|
||||||
var keyPair;
|
var keyPair;
|
||||||
|
|
||||||
socketInfo.decryptAndHandleDeviceInit = function(deviceInit) {
|
socketInfo.decryptAndHandleDeviceInit = function(deviceInit) {
|
||||||
var masterEphemeral = toArrayBuffer(deviceInit.masterEphemeralPubKey);
|
var masterEphemeral = toArrayBuffer(deviceInit.publicKey);
|
||||||
var message = toArrayBuffer(deviceInit.identityKeyMessage);
|
var message = toArrayBuffer(deviceInit.body);
|
||||||
|
|
||||||
return textsecure.crypto.ECDHE(masterEphemeral, keyPair.privKey).then(function(ecRes) {
|
return textsecure.crypto.ECDHE(masterEphemeral, keyPair.privKey).then(function(ecRes) {
|
||||||
return HKDF(ecRes, masterEphemeral, "WhisperDeviceInit").then(function(keys) {
|
return HKDF(ecRes, '', "TextSecure Provisioning Message").then(function(keys) {
|
||||||
if (new Uint8Array(message)[0] != (3 << 4) | 3)
|
if (new Uint8Array(message)[0] != 1)
|
||||||
throw new Error("Bad version number on IdentityKeyMessage");
|
throw new Error("Bad version number on ProvisioningMessage");
|
||||||
|
|
||||||
var iv = message.slice(1, 16 + 1);
|
var iv = message.slice(1, 16 + 1);
|
||||||
var mac = message.slice(message.length - 32, message.length);
|
var mac = message.slice(message.byteLength - 32, message.byteLength);
|
||||||
var ivAndCiphertext = message.slice(0, message.length - 32);
|
var ivAndCiphertext = message.slice(0, message.byteLength - 32);
|
||||||
var ciphertext = message.slice(16 + 1, message.length - 32);
|
var ciphertext = message.slice(16 + 1, message.byteLength - 32);
|
||||||
|
|
||||||
return verifyMAC(ivAndCiphertext, ecRes[1], mac).then(function() {
|
return verifyMAC(ivAndCiphertext, keys[1], mac).then(function() {
|
||||||
window.textsecure.crypto.decrypt(ecRes[0], ciphertext, iv).then(function(plaintext) {
|
return window.textsecure.crypto.decrypt(keys[0], ciphertext, iv).then(function(plaintext) {
|
||||||
var identityKeyMsg = textsecure.protobuf.IdentityKey.decode(plaintext);
|
var identityKeyMsg = textsecure.protobuf.ProvisionMessage.decode(plaintext);
|
||||||
|
|
||||||
textsecure.crypto.createKeyPair(toArrayBuffer(identityKeyMsg.identityKey)).then(function(identityKeyPair) {
|
return textsecure.crypto.createKeyPair(toArrayBuffer(identityKeyMsg.identityKeyPrivate)).then(function(identityKeyPair) {
|
||||||
crypto_storage.putKeyPair("identityKey", identityKeyPair);
|
crypto_storage.putKeyPair("identityKey", identityKeyPair);
|
||||||
identityKeyMsg.identityKey = null;
|
identityKeyMsg.identityKeyPrivate = null;
|
||||||
|
|
||||||
return identityKeyMsg;
|
return identityKeyMsg;
|
||||||
});
|
});
|
||||||
|
|
|
@ -142,14 +142,13 @@
|
||||||
new WebSocketResource(socket, function(request) {
|
new WebSocketResource(socket, function(request) {
|
||||||
if (request.path == "/v1/address" && request.verb == "PUT") {
|
if (request.path == "/v1/address" && request.verb == "PUT") {
|
||||||
var proto = textsecure.protobuf.ProvisioningUuid.decode(request.body);
|
var proto = textsecure.protobuf.ProvisioningUuid.decode(request.body);
|
||||||
qrCode.makeCode('textsecure-device-init:/' +
|
qrCode.makeCode('tsdevice:/' +
|
||||||
'?channel_uuid=' + proto.uuid +
|
'?uuid=' + proto.uuid +
|
||||||
'&channel_server=' + textsecure.api.relay +
|
'&pub_key=' + btoa(getString(cryptoInfo.pubKey)));
|
||||||
'&publicKey=' + btoa(getString(cryptoInfo.publicKey)));
|
|
||||||
$('img').removeAttr('style');
|
$('img').removeAttr('style');
|
||||||
$('#multi-device .status').text("Use your phone to scan the QR code.")
|
$('#multi-device .status').text("Use your phone to scan the QR code.")
|
||||||
request.respond(200, 'OK');
|
request.respond(200, 'OK');
|
||||||
} else {
|
} else if (request.path == "/v1/message" && request.verb == "PUT") {
|
||||||
$('#init-setup').hide();
|
$('#init-setup').hide();
|
||||||
$('#verify1done').text('');
|
$('#verify1done').text('');
|
||||||
$('#verify2done').text('');
|
$('#verify2done').text('');
|
||||||
|
@ -158,8 +157,7 @@
|
||||||
$('#verify5done').text('');
|
$('#verify5done').text('');
|
||||||
$('#verify').show().addClass('in');
|
$('#verify').show().addClass('in');
|
||||||
|
|
||||||
|
textsecure.registerSecondDevice(request.body, cryptoInfo, function(step) {
|
||||||
textsecure.registerSecondDevice(message.body, cryptoInfo, function(step) {
|
|
||||||
switch(step) {
|
switch(step) {
|
||||||
case 1:
|
case 1:
|
||||||
$('#verify1done').text('done');
|
$('#verify1done').text('done');
|
||||||
|
@ -171,16 +169,19 @@
|
||||||
$('#verify3done').text('done');
|
$('#verify3done').text('done');
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
//TODO: User needs to verify number before we continue
|
//XXX: User needs to verify number before we continue
|
||||||
$('#complete-number').text(parsedNumber);
|
|
||||||
$('#verify4done').text('done');
|
$('#verify4done').text('done');
|
||||||
|
//$('#complete-number').text(parsedNumber);
|
||||||
|
textsecure.registration.done();
|
||||||
case 5:
|
case 5:
|
||||||
|
//TODO: Do sync to get 5!
|
||||||
$('#verify').hide();
|
$('#verify').hide();
|
||||||
$('#setup-complete').show().addClass('in');
|
$('#setup-complete').show().addClass('in');
|
||||||
textsecure.registration.done();
|
textsecure.registration.done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else
|
||||||
|
console.log(request.path);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,7 +37,7 @@ window.textsecure.api = function () {
|
||||||
URL_CALLS.devices = "/v1/devices";
|
URL_CALLS.devices = "/v1/devices";
|
||||||
URL_CALLS.keys = "/v2/keys";
|
URL_CALLS.keys = "/v2/keys";
|
||||||
URL_CALLS.push = "/v1/websocket";
|
URL_CALLS.push = "/v1/websocket";
|
||||||
URL_CALLS.temp_push = "/v1/provisioning";
|
URL_CALLS.temp_push = "/v1/websocket/provisioning";
|
||||||
URL_CALLS.messages = "/v1/messages";
|
URL_CALLS.messages = "/v1/messages";
|
||||||
URL_CALLS.attachment = "/v1/attachments";
|
URL_CALLS.attachment = "/v1/attachments";
|
||||||
|
|
||||||
|
|
|
@ -268,13 +268,9 @@ window.textsecure.registerSingleDevice = function(number, verificationCode, step
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.textsecure.registerSecondDevice = function(encodedDeviceInit, cryptoInfo, stepDone) {
|
window.textsecure.registerSecondDevice = function(encodedProvisionEnvelope, cryptoInfo, stepDone) {
|
||||||
var deviceInit = textsecure.protobuf.DeviceInit.decode(encodedDeviceInit, 'binary');
|
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(encodedProvisionEnvelope, 'binary');
|
||||||
return cryptoInfo.decryptAndHandleDeviceInit(deviceInit).then(function(identityKey) {
|
return cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(identityKey) {
|
||||||
if (identityKey.server != textsecure.api.relay)
|
|
||||||
throw new Error("Unknown relay used by master");
|
|
||||||
var number = identityKey.phoneNumber;
|
|
||||||
|
|
||||||
stepDone(1);
|
stepDone(1);
|
||||||
|
|
||||||
var signalingKey = textsecure.crypto.getRandomBytes(32 + 20);
|
var signalingKey = textsecure.crypto.getRandomBytes(32 + 20);
|
||||||
|
@ -288,17 +284,16 @@ window.textsecure.registerSecondDevice = function(encodedDeviceInit, cryptoInfo,
|
||||||
registrationId = registrationId & 0x3fff;
|
registrationId = registrationId & 0x3fff;
|
||||||
textsecure.storage.putUnencrypted("registrationId", registrationId);
|
textsecure.storage.putUnencrypted("registrationId", registrationId);
|
||||||
|
|
||||||
return textsecure.api.confirmCode(number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) {
|
return textsecure.api.confirmCode(identityKey.number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) {
|
||||||
var numberId = number + "." + result;
|
var numberId = identityKey.number + "." + result.deviceId;
|
||||||
textsecure.storage.putUnencrypted("number_id", numberId);
|
textsecure.storage.putUnencrypted("number_id", numberId);
|
||||||
textsecure.storage.putUnencrypted("regionCode", libphonenumber.util.getRegion(number));
|
textsecure.storage.putUnencrypted("regionCode", libphonenumber.util.getRegionCodeForNumber(identityKey.number));
|
||||||
stepDone(2);
|
stepDone(2);
|
||||||
|
|
||||||
return textsecure.protocol.generateKeys().then(function(keys) {
|
return textsecure.protocol.generateKeys().then(function(keys) {
|
||||||
stepDone(3);
|
stepDone(3);
|
||||||
return textsecure.api.registerKeys(keys).then(function() {
|
return textsecure.api.registerKeys(keys).then(function() {
|
||||||
stepDone(4);
|
stepDone(4);
|
||||||
//TODO: Send DeviceControl.NEW_DEVICE_REGISTERED to all other devices
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
WhisperMessage : protocolMessages.WhisperMessage,
|
WhisperMessage : protocolMessages.WhisperMessage,
|
||||||
PreKeyWhisperMessage : protocolMessages.PreKeyWhisperMessage,
|
PreKeyWhisperMessage : protocolMessages.PreKeyWhisperMessage,
|
||||||
ProvisioningUuid : deviceMessages.ProvisioningUuid,
|
ProvisioningUuid : deviceMessages.ProvisioningUuid,
|
||||||
DeviceInit : deviceMessages.DeviceInit,
|
ProvisionEnvelope : deviceMessages.ProvisionEnvelope,
|
||||||
IdentityKey : deviceMessages.IdentityKey,
|
ProvisionMessage : deviceMessages.ProvisionMessage,
|
||||||
DeviceControl : deviceMessages.DeviceControl,
|
DeviceControl : deviceMessages.DeviceControl,
|
||||||
WebSocketResponseMessage : subProtocolMessages.WebSocketResponseMessage,
|
WebSocketResponseMessage : subProtocolMessages.WebSocketResponseMessage,
|
||||||
WebSocketRequestMessage : subProtocolMessages.WebSocketRequestMessage,
|
WebSocketRequestMessage : subProtocolMessages.WebSocketRequestMessage,
|
||||||
|
|
|
@ -762,26 +762,26 @@ window.textsecure.protocol = function() {
|
||||||
var keyPair;
|
var keyPair;
|
||||||
|
|
||||||
socketInfo.decryptAndHandleDeviceInit = function(deviceInit) {
|
socketInfo.decryptAndHandleDeviceInit = function(deviceInit) {
|
||||||
var masterEphemeral = toArrayBuffer(deviceInit.masterEphemeralPubKey);
|
var masterEphemeral = toArrayBuffer(deviceInit.publicKey);
|
||||||
var message = toArrayBuffer(deviceInit.identityKeyMessage);
|
var message = toArrayBuffer(deviceInit.body);
|
||||||
|
|
||||||
return textsecure.crypto.ECDHE(masterEphemeral, keyPair.privKey).then(function(ecRes) {
|
return textsecure.crypto.ECDHE(masterEphemeral, keyPair.privKey).then(function(ecRes) {
|
||||||
return HKDF(ecRes, masterEphemeral, "WhisperDeviceInit").then(function(keys) {
|
return HKDF(ecRes, '', "TextSecure Provisioning Message").then(function(keys) {
|
||||||
if (new Uint8Array(message)[0] != (3 << 4) | 3)
|
if (new Uint8Array(message)[0] != 1)
|
||||||
throw new Error("Bad version number on IdentityKeyMessage");
|
throw new Error("Bad version number on ProvisioningMessage");
|
||||||
|
|
||||||
var iv = message.slice(1, 16 + 1);
|
var iv = message.slice(1, 16 + 1);
|
||||||
var mac = message.slice(message.length - 32, message.length);
|
var mac = message.slice(message.byteLength - 32, message.byteLength);
|
||||||
var ivAndCiphertext = message.slice(0, message.length - 32);
|
var ivAndCiphertext = message.slice(0, message.byteLength - 32);
|
||||||
var ciphertext = message.slice(16 + 1, message.length - 32);
|
var ciphertext = message.slice(16 + 1, message.byteLength - 32);
|
||||||
|
|
||||||
return verifyMAC(ivAndCiphertext, ecRes[1], mac).then(function() {
|
return verifyMAC(ivAndCiphertext, keys[1], mac).then(function() {
|
||||||
window.textsecure.crypto.decrypt(ecRes[0], ciphertext, iv).then(function(plaintext) {
|
return window.textsecure.crypto.decrypt(keys[0], ciphertext, iv).then(function(plaintext) {
|
||||||
var identityKeyMsg = textsecure.protobuf.IdentityKey.decode(plaintext);
|
var identityKeyMsg = textsecure.protobuf.ProvisionMessage.decode(plaintext);
|
||||||
|
|
||||||
textsecure.crypto.createKeyPair(toArrayBuffer(identityKeyMsg.identityKey)).then(function(identityKeyPair) {
|
return textsecure.crypto.createKeyPair(toArrayBuffer(identityKeyMsg.identityKeyPrivate)).then(function(identityKeyPair) {
|
||||||
crypto_storage.putKeyPair("identityKey", identityKeyPair);
|
crypto_storage.putKeyPair("identityKey", identityKeyPair);
|
||||||
identityKeyMsg.identityKey = null;
|
identityKeyMsg.identityKeyPrivate = null;
|
||||||
|
|
||||||
return identityKeyMsg;
|
return identityKeyMsg;
|
||||||
});
|
});
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
<div class='col-xs-offset-1 col-md-6'>
|
<div class='col-xs-offset-1 col-md-6'>
|
||||||
<div id="verify" class="collapse narrow">
|
<div id="verify" class="collapse narrow">
|
||||||
<div id="verify1">Receiving identity key...<span class="done"></span></div>
|
<div id="verify1">Receiving identity key...<span class="verify1done"></span></div>
|
||||||
<div id="verify2">Verifying number and setup code...<span class="done" id="verify2done"></span></div>
|
<div id="verify2">Verifying number and setup code...<span class="done" id="verify2done"></span></div>
|
||||||
<div id="verify3">Generating keys...<span class="done" id="verify3done"></span></div>
|
<div id="verify3">Generating keys...<span class="done" id="verify3done"></span></div>
|
||||||
<div id="verify4">Registering...<span class="done" id="verify4done"></span></div>
|
<div id="verify4">Registering...<span class="done" id="verify4done"></span></div>
|
||||||
|
|
|
@ -4,17 +4,16 @@ message ProvisioningUuid {
|
||||||
optional string uuid = 1;
|
optional string uuid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeviceInit {
|
|
||||||
required bytes masterEphemeralPubKey = 1;
|
message ProvisionEnvelope {
|
||||||
required bytes identityKeyMessage = 2; // contains an IdentityKey
|
optional bytes publicKey = 1;
|
||||||
|
optional bytes body = 2; // Encrypted ProvisionMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
message IdentityKey {
|
message ProvisionMessage {
|
||||||
required bytes identityKey = 1;
|
optional bytes identityKeyPrivate = 2;
|
||||||
required string phoneNumber = 2;
|
optional string number = 3;
|
||||||
required string server = 3;
|
optional string provisioningCode = 4;
|
||||||
required bool masterSupportsSms = 4;
|
|
||||||
required uint32 provisioningCode = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeviceControl {
|
message DeviceControl {
|
||||||
|
|
Loading…
Reference in a new issue