Run key generation in a worker

Ground work for a smoother registration flow. Overall UX still needs
some polish but at least now we can have a progress gif or animation or
whatever. Also adds the phonenumber-confirmation step as a simple alert
box, which will be replaced with a nice dialogue in a later commit.
This commit is contained in:
lilia 2015-03-25 17:08:05 -07:00
parent 0a9598ae21
commit bfe23d86aa
5 changed files with 137 additions and 68 deletions

76
js/generate_keys.js Normal file
View file

@ -0,0 +1,76 @@
/* vim: ts=4:sw=4
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
/*
* Load this script in a Web Worker to generate new prekeys without
* tying up the main thread.
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
*
* Because workers don't have access to the window or localStorage, we
* create our own version that proxies back to the caller for actual
* storage.
*
* Example usage:
*
var myWorker = new Worker('/js/generate_keys.js');
myWorker.onmessage = function(e) {
switch(e.data.method) {
case 'set':
localStorage.setItem(e.data.key, e.data.value);
break;
case 'remove':
localStorage.removeItem(e.data.key);
break;
case 'done':
console.log(e.data.keys);
}
};
*/
var store = {};
var window = this;
importScripts('libtextsecure.js');
window.textsecure.storage.impl = {
/*****************************
*** Override Storage Routines ***
*****************************/
put: function(key, value) {
if (value === undefined)
throw new Error("Tried to store undefined");
store[key] = value;
postMessage({method: 'set', key: key, value: value});
},
get: function(key, defaultValue) {
if (key in store) {
return store[key];
} else {
return defaultValue;
}
},
remove: function(key) {
delete store[key];
postMessage({method: 'remove', key: key});
},
};
onmessage = function(e) {
store = e.data;
textsecure.protocol_wrapper.generateKeys().then(function(keys) {
postMessage({method: 'done', keys: keys});
});
}

View file

@ -38388,7 +38388,7 @@ window.axolotl.sessions = {
;(function() {
function loadProtoBufs(filename) {
return dcodeIO.ProtoBuf.loadProtoFile({root: 'protos', file: filename}).build('textsecure');
return dcodeIO.ProtoBuf.loadProtoFile({root: '/protos', file: filename}).build('textsecure');
};
var pushMessages = loadProtoBufs('IncomingPushMessageSignal.proto');
@ -38926,34 +38926,21 @@ window.textsecure.registerSingleDevice = function(number, verificationCode, step
});
}
window.textsecure.registerSecondDevice = function(encodedProvisionEnvelope, cryptoInfo, stepDone) {
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(encodedProvisionEnvelope, 'binary');
return cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(identityKey) {
stepDone(1);
window.textsecure.registerSecondDevice = function(provisionMessage) {
var signalingKey = textsecure.crypto.getRandomBytes(32 + 20);
textsecure.storage.put('signaling_key', signalingKey);
var signalingKey = textsecure.crypto.getRandomBytes(32 + 20);
textsecure.storage.put('signaling_key', signalingKey);
var password = btoa(getString(textsecure.crypto.getRandomBytes(16)));
password = password.substring(0, password.length - 2);
textsecure.storage.put("password", password);
var password = btoa(getString(textsecure.crypto.getRandomBytes(16)));
password = password.substring(0, password.length - 2);
textsecure.storage.put("password", password);
var registrationId = new Uint16Array(textsecure.crypto.getRandomBytes(2))[0];
registrationId = registrationId & 0x3fff;
textsecure.storage.put("registrationId", registrationId);
var registrationId = new Uint16Array(textsecure.crypto.getRandomBytes(2))[0];
registrationId = registrationId & 0x3fff;
textsecure.storage.put("registrationId", registrationId);
return textsecure.api.confirmCode(identityKey.number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) {
textsecure.storage.user.setNumberAndDeviceId(identityKey.number, result.deviceId);
textsecure.storage.put("regionCode", libphonenumber.util.getRegionCodeForNumber(identityKey.number));
stepDone(2);
return textsecure.protocol_wrapper.generateKeys().then(function(keys) {
stepDone(3);
return textsecure.api.registerKeys(keys).then(function() {
stepDone(4);
});
});
});
return textsecure.api.confirmCode(provisionMessage.number, provisionMessage.provisioningCode, password, signalingKey, registrationId, false).then(function(result) {
textsecure.storage.user.setNumberAndDeviceId(provisionMessage.number, result.deviceId);
textsecure.storage.put("regionCode", libphonenumber.util.getRegionCodeForNumber(provisionMessage.number));
});
};

View file

@ -56,23 +56,42 @@
request.respond(200, 'OK');
} else if (request.path == "/v1/message" && request.verb == "PUT") {
$('#qr').hide();
textsecure.registerSecondDevice(request.body, cryptoInfo, function(step) {
switch(step) {
case 1:
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(request.body, 'binary');
cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(provisionMessage) {
if (confirm(provisionMessage.number)) {
$('#status').text('Registering new device...');
break;
case 2:
$('#status').text('Generating keys...');
break;
case 3:
$('#status').text('Uploading keys...');
break;
case 4:
$('#status').text('All done!');
textsecure.registration.done();
$('#init-setup').hide();
$('#setup-complete').show().addClass('in');
initOptions();
window.textsecure.registerSecondDevice(provisionMessage).then(function() {
$('#status').text('Generating keys...');
var counter = 0;
var myWorker = new Worker('/js/generate_keys.js');
myWorker.postMessage({
maxPreKeyId: textsecure.storage.get("maxPreKeyId", 0),
signedKeyId: textsecure.storage.get("signedKeyId", 0),
libaxolotl25519KeyidentityKey: textsecure.storage.get("libaxolotl25519KeyidentityKey"),
});
myWorker.onmessage = function(e) {
switch(e.data.method) {
case 'set':
textsecure.storage.put(e.data.key, e.data.value);
counter = counter + 1;
$('#status').text('Generating keys...' + counter);
break;
case 'remove':
textsecure.storage.remove(e.data.key);
break;
case 'done':
$('#status').text('Uploading keys...');
textsecure.api.registerKeys(e.data.keys).then(function() {
$('#status').text('All done!');
textsecure.registration.done();
$('#init-setup').hide();
$('#setup-complete').show().addClass('in');
initOptions();
});
}
};
});
}
});
} else

View file

@ -279,33 +279,20 @@ window.textsecure.registerSingleDevice = function(number, verificationCode, step
});
}
window.textsecure.registerSecondDevice = function(encodedProvisionEnvelope, cryptoInfo, stepDone) {
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(encodedProvisionEnvelope, 'binary');
return cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(identityKey) {
stepDone(1);
window.textsecure.registerSecondDevice = function(provisionMessage) {
var signalingKey = textsecure.crypto.getRandomBytes(32 + 20);
textsecure.storage.put('signaling_key', signalingKey);
var signalingKey = textsecure.crypto.getRandomBytes(32 + 20);
textsecure.storage.put('signaling_key', signalingKey);
var password = btoa(getString(textsecure.crypto.getRandomBytes(16)));
password = password.substring(0, password.length - 2);
textsecure.storage.put("password", password);
var password = btoa(getString(textsecure.crypto.getRandomBytes(16)));
password = password.substring(0, password.length - 2);
textsecure.storage.put("password", password);
var registrationId = new Uint16Array(textsecure.crypto.getRandomBytes(2))[0];
registrationId = registrationId & 0x3fff;
textsecure.storage.put("registrationId", registrationId);
var registrationId = new Uint16Array(textsecure.crypto.getRandomBytes(2))[0];
registrationId = registrationId & 0x3fff;
textsecure.storage.put("registrationId", registrationId);
return textsecure.api.confirmCode(identityKey.number, identityKey.provisioningCode, password, signalingKey, registrationId, false).then(function(result) {
textsecure.storage.user.setNumberAndDeviceId(identityKey.number, result.deviceId);
textsecure.storage.put("regionCode", libphonenumber.util.getRegionCodeForNumber(identityKey.number));
stepDone(2);
return textsecure.protocol_wrapper.generateKeys().then(function(keys) {
stepDone(3);
return textsecure.api.registerKeys(keys).then(function() {
stepDone(4);
});
});
});
return textsecure.api.confirmCode(provisionMessage.number, provisionMessage.provisioningCode, password, signalingKey, registrationId, false).then(function(result) {
textsecure.storage.user.setNumberAndDeviceId(provisionMessage.number, result.deviceId);
textsecure.storage.put("regionCode", libphonenumber.util.getRegionCodeForNumber(provisionMessage.number));
});
};

View file

@ -1,7 +1,7 @@
;(function() {
function loadProtoBufs(filename) {
return dcodeIO.ProtoBuf.loadProtoFile({root: 'protos', file: filename}).build('textsecure');
return dcodeIO.ProtoBuf.loadProtoFile({root: '/protos', file: filename}).build('textsecure');
};
var pushMessages = loadProtoBufs('IncomingPushMessageSignal.proto');