Add textsecure.AccountManager
This class should be used for account registration and for refreshing prekeys for your account.
This commit is contained in:
parent
a960acacc6
commit
f465bdddbf
7 changed files with 327 additions and 225 deletions
|
@ -56,6 +56,7 @@ module.exports = function(grunt) {
|
||||||
'libtextsecure/helpers.js',
|
'libtextsecure/helpers.js',
|
||||||
'libtextsecure/stringview.js',
|
'libtextsecure/stringview.js',
|
||||||
'libtextsecure/api.js',
|
'libtextsecure/api.js',
|
||||||
|
'libtextsecure/account_manager.js',
|
||||||
'libtextsecure/message_receiver.js',
|
'libtextsecure/message_receiver.js',
|
||||||
'libtextsecure/sendmessage.js',
|
'libtextsecure/sendmessage.js',
|
||||||
],
|
],
|
||||||
|
|
|
@ -38913,116 +38913,6 @@ textsecure.processDecrypted = function(decrypted, source) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
window.textsecure.refreshPreKeys = function() {
|
|
||||||
return textsecure.api.getMyKeys().then(function(preKeyCount) {
|
|
||||||
if (preKeyCount < 10) {
|
|
||||||
generateKeys();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function createAccount(number, verificationCode, identityKeyPair, single_device) {
|
|
||||||
textsecure.storage.put('identityKey', identityKeyPair);
|
|
||||||
|
|
||||||
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 registrationId = axolotl.util.generateRegistrationId();
|
|
||||||
textsecure.storage.put("registrationId", registrationId);
|
|
||||||
|
|
||||||
return textsecure.api.confirmCode(
|
|
||||||
number, verificationCode, password, signalingKey, registrationId, single_device
|
|
||||||
).then(function(response) {
|
|
||||||
textsecure.storage.user.setNumberAndDeviceId(number, response.deviceId || 1);
|
|
||||||
textsecure.storage.put("regionCode", libphonenumber.util.getRegionCodeForNumber(number));
|
|
||||||
|
|
||||||
return textsecure.protocol_wrapper.generateKeys().then(textsecure.registration.done);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateKeys(count, progressCallback) {
|
|
||||||
if (count === undefined) {
|
|
||||||
throw TypeError('generateKeys: count is undefined');
|
|
||||||
}
|
|
||||||
if (typeof progressCallback !== 'function') {
|
|
||||||
progressCallback = undefined;
|
|
||||||
}
|
|
||||||
var store = textsecure.storage.axolotl;
|
|
||||||
var identityKey = store.getMyIdentityKey();
|
|
||||||
var result = { preKeys: [], identityKey: identityKey.pubKey };
|
|
||||||
var promises = [];
|
|
||||||
|
|
||||||
var startId = textsecure.storage.get('maxPreKeyId', 1);
|
|
||||||
var signedKeyId = textsecure.storage.get('signedKeyId', 1);
|
|
||||||
|
|
||||||
for (var keyId = startId; keyId < startId+count; ++keyId) {
|
|
||||||
promises.push(
|
|
||||||
axolotl.util.generatePreKey(keyId).then(function(res) {
|
|
||||||
store.putPreKey(res.keyId, res.keyPair);
|
|
||||||
result.preKeys.push({
|
|
||||||
keyId : res.keyId,
|
|
||||||
publicKey : res.keyPair.pubKey
|
|
||||||
});
|
|
||||||
if (progressCallback) { progressCallback(); }
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
promises.push(
|
|
||||||
axolotl.util.generateSignedPreKey(identityKey, signedKeyId).then(function(res) {
|
|
||||||
store.putSignedPreKey(res.keyId, res.keyPair);
|
|
||||||
result.signedPreKey = {
|
|
||||||
keyId : res.keyId,
|
|
||||||
publicKey : res.keyPair.pubKey,
|
|
||||||
signature : res.signature
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
store.removeSignedPreKey(signedKeyId - 2);
|
|
||||||
textsecure.storage.put('maxPreKeyId', startId + count);
|
|
||||||
textsecure.storage.put('signedKeyId', signedKeyId + 1);
|
|
||||||
|
|
||||||
return Promise.all(promises).then(function() {
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.textsecure.registerSecondDevice = function(setProvisioningUrl, confirmNumber, progressCallback) {
|
|
||||||
return textsecure.protocol_wrapper.createIdentityKeyRecvSocket().then(function(cryptoInfo) {
|
|
||||||
return new Promise(function(resolve) {
|
|
||||||
new WebSocketResource(textsecure.api.getTempWebsocket(), function(request) {
|
|
||||||
if (request.path == "/v1/address" && request.verb == "PUT") {
|
|
||||||
var proto = textsecure.protobuf.ProvisioningUuid.decode(request.body);
|
|
||||||
setProvisioningUrl([
|
|
||||||
'tsdevice:/?uuid=', proto.uuid, '&pub_key=',
|
|
||||||
encodeURIComponent(btoa(getString(cryptoInfo.pubKey)))
|
|
||||||
].join(''));
|
|
||||||
request.respond(200, 'OK');
|
|
||||||
} else if (request.path == "/v1/message" && request.verb == "PUT") {
|
|
||||||
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(request.body, 'binary');
|
|
||||||
request.respond(200, 'OK');
|
|
||||||
resolve(cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(provisionMessage) {
|
|
||||||
return confirmNumber(provisionMessage.number).then(function() {
|
|
||||||
return createAccount(
|
|
||||||
provisionMessage.number,
|
|
||||||
provisionMessage.provisioningCode,
|
|
||||||
provisionMessage.identityKeyPair,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
console.log('Unknown websocket message', request.path);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/* vim: ts=4:sw=4:expandtab
|
/* vim: ts=4:sw=4:expandtab
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -39480,6 +39370,167 @@ window.textsecure.api = function () {
|
||||||
return self;
|
return self;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
/* vim: ts=4:sw=4:expandtab
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
;(function () {
|
||||||
|
'use strict';
|
||||||
|
window.textsecure = window.textsecure || {};
|
||||||
|
|
||||||
|
function AccountManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountManager.prototype = {
|
||||||
|
constructor: AccountManager,
|
||||||
|
requestVoiceVerification: function(number) {
|
||||||
|
return TextSecureServer.requestVerificationVoice(number);
|
||||||
|
},
|
||||||
|
requestSMSVerification: function(number) {
|
||||||
|
return TextSecureServer.requestVerificationSMS(number);
|
||||||
|
},
|
||||||
|
registerSingleDevice: function(number, verificationCode) {
|
||||||
|
return axolotl.util.generateIdentityKeyPair().then(function(identityKeyPair) {
|
||||||
|
return createAccount(number, verificationCode, identityKeyPair, true).
|
||||||
|
then(function() { return generateKeys(100); }).
|
||||||
|
then(TextSecureServer.registerKeys).
|
||||||
|
then(textsecure.registration.done);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
registerSecondDevice: function(setProvisioningUrl, confirmNumber, progressCallback) {
|
||||||
|
return textsecure.protocol_wrapper.createIdentityKeyRecvSocket().then(function(cryptoInfo) {
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
new WebSocketResource(textsecure.api.getTempWebsocket(), function(request) {
|
||||||
|
if (request.path == "/v1/address" && request.verb == "PUT") {
|
||||||
|
var proto = textsecure.protobuf.ProvisioningUuid.decode(request.body);
|
||||||
|
setProvisioningUrl([
|
||||||
|
'tsdevice:/?uuid=', proto.uuid, '&pub_key=',
|
||||||
|
encodeURIComponent(btoa(getString(cryptoInfo.pubKey)))
|
||||||
|
].join(''));
|
||||||
|
request.respond(200, 'OK');
|
||||||
|
} else if (request.path == "/v1/message" && request.verb == "PUT") {
|
||||||
|
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(request.body, 'binary');
|
||||||
|
request.respond(200, 'OK');
|
||||||
|
resolve(cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(provisionMessage) {
|
||||||
|
return confirmNumber(provisionMessage.number).then(function() {
|
||||||
|
return createAccount(
|
||||||
|
provisionMessage.number,
|
||||||
|
provisionMessage.provisioningCode,
|
||||||
|
provisionMessage.identityKeyPair,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
console.log('Unknown websocket message', request.path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).then(function() {
|
||||||
|
return generateKeys(100, progressCallback);
|
||||||
|
}).then(TextSecureServer.registerKeys).then(textsecure.registration.done);
|
||||||
|
},
|
||||||
|
refreshPreKeys: function() {
|
||||||
|
return textsecure.api.getMyKeys().then(function(preKeyCount) {
|
||||||
|
if (preKeyCount < 10) {
|
||||||
|
return generateKeys(100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function createAccount(number, verificationCode, identityKeyPair, single_device) {
|
||||||
|
textsecure.storage.put('identityKey', identityKeyPair);
|
||||||
|
|
||||||
|
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 registrationId = axolotl.util.generateRegistrationId();
|
||||||
|
textsecure.storage.put("registrationId", registrationId);
|
||||||
|
|
||||||
|
return textsecure.api.confirmCode(
|
||||||
|
number, verificationCode, password, signalingKey, registrationId, single_device
|
||||||
|
).then(function(response) {
|
||||||
|
textsecure.storage.user.setNumberAndDeviceId(number, response.deviceId || 1);
|
||||||
|
textsecure.storage.put("regionCode", libphonenumber.util.getRegionCodeForNumber(number));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
textsecure.AccountManager = AccountManager;
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
function generateKeys(count, progressCallback) {
|
||||||
|
if (typeof progressCallback !== 'function') {
|
||||||
|
progressCallback = undefined;
|
||||||
|
}
|
||||||
|
var startId = textsecure.storage.get('maxPreKeyId', 1);
|
||||||
|
var signedKeyId = textsecure.storage.get('signedKeyId', 1);
|
||||||
|
|
||||||
|
if (typeof startId != 'number') {
|
||||||
|
throw new Error('Invalid maxPreKeyId');
|
||||||
|
}
|
||||||
|
if (typeof signedKeyId != 'number') {
|
||||||
|
throw new Error('Invalid signedKeyId');
|
||||||
|
}
|
||||||
|
|
||||||
|
textsecure.protocol_wrapper.startWorker();
|
||||||
|
|
||||||
|
var store = textsecure.storage.axolotl;
|
||||||
|
var identityKey = store.getMyIdentityKey();
|
||||||
|
var result = { preKeys: [], identityKey: identityKey.pubKey };
|
||||||
|
var promises = [];
|
||||||
|
|
||||||
|
for (var keyId = startId; keyId < startId+count; ++keyId) {
|
||||||
|
promises.push(
|
||||||
|
axolotl.util.generatePreKey(keyId).then(function(res) {
|
||||||
|
store.putPreKey(res.keyId, res.keyPair);
|
||||||
|
result.preKeys.push({
|
||||||
|
keyId : res.keyId,
|
||||||
|
publicKey : res.keyPair.pubKey
|
||||||
|
});
|
||||||
|
if (progressCallback) { progressCallback(); }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
promises.push(
|
||||||
|
axolotl.util.generateSignedPreKey(identityKey, signedKeyId).then(function(res) {
|
||||||
|
store.putSignedPreKey(res.keyId, res.keyPair);
|
||||||
|
result.signedPreKey = {
|
||||||
|
keyId : res.keyId,
|
||||||
|
publicKey : res.keyPair.pubKey,
|
||||||
|
signature : res.signature
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
store.removeSignedPreKey(signedKeyId - 2);
|
||||||
|
textsecure.storage.put('maxPreKeyId', startId + count);
|
||||||
|
textsecure.storage.put('signedKeyId', signedKeyId + 1);
|
||||||
|
return Promise.all(promises).then(function() {
|
||||||
|
textsecure.protocol_wrapper.stopWorker();
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* vim: ts=4:sw=4:expandtab
|
/* vim: ts=4:sw=4:expandtab
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
$('.confirmation-dialog').hide();
|
$('.confirmation-dialog').hide();
|
||||||
$('.progress-dialog').show();
|
$('.progress-dialog').show();
|
||||||
$('.progress-dialog .status').text('Registering new device...');
|
$('.progress-dialog .status').text('Generating Keys');
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
$('.modal-container').show();
|
$('.modal-container').show();
|
||||||
|
@ -78,7 +78,8 @@
|
||||||
$('#init-setup').show().addClass('in');
|
$('#init-setup').show().addClass('in');
|
||||||
$('#status').text("Connecting...");
|
$('#status').text("Connecting...");
|
||||||
|
|
||||||
bg.textsecure.registerSecondDevice(setProvisioningUrl, confirmNumber, incrementCounter).then(function() {
|
var accountManager = new bg.textsecure.AccountManager();
|
||||||
|
accountManager.registerSecondDevice(setProvisioningUrl, confirmNumber, incrementCounter).then(function() {
|
||||||
$('.modal-container').hide();
|
$('.modal-container').hide();
|
||||||
$('#init-setup').hide();
|
$('#init-setup').hide();
|
||||||
$('#setup-complete').show().addClass('in');
|
$('#setup-complete').show().addClass('in');
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
;(function() {
|
;(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
var bg = extension.windows.getBackground();
|
var bg = extension.windows.getBackground();
|
||||||
|
var accountManager = new bg.textsecure.AccountManager();
|
||||||
|
|
||||||
function log(s) {
|
function log(s) {
|
||||||
console.log(s);
|
console.log(s);
|
||||||
|
@ -61,7 +62,7 @@
|
||||||
$('#error').hide();
|
$('#error').hide();
|
||||||
var number = phoneView.validateNumber();
|
var number = phoneView.validateNumber();
|
||||||
if (number) {
|
if (number) {
|
||||||
bg.textsecure.api.requestVerificationVoice(number).catch(displayError);
|
accountManager.requestVoiceVerification(number).catch(displayError);
|
||||||
$('#step2').addClass('in').fadeIn();
|
$('#step2').addClass('in').fadeIn();
|
||||||
} else {
|
} else {
|
||||||
$('#number-container').addClass('invalid');
|
$('#number-container').addClass('invalid');
|
||||||
|
@ -72,7 +73,7 @@
|
||||||
$('#error').hide();
|
$('#error').hide();
|
||||||
var number = phoneView.validateNumber();
|
var number = phoneView.validateNumber();
|
||||||
if (number) {
|
if (number) {
|
||||||
bg.textsecure.api.requestVerificationSMS(number).catch(displayError);
|
accountManager.requestSMSVerification(number).catch(displayError);
|
||||||
$('#step2').addClass('in').fadeIn();
|
$('#step2').addClass('in').fadeIn();
|
||||||
} else {
|
} else {
|
||||||
$('#number-container').addClass('invalid');
|
$('#number-container').addClass('invalid');
|
||||||
|
@ -86,7 +87,7 @@
|
||||||
|
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
localStorage.setItem('first_install_ran', 1);
|
localStorage.setItem('first_install_ran', 1);
|
||||||
bg.textsecure.registerSingleDevice(number, verificationCode).then(function() {
|
accountManager.registerSingleDevice(number, verificationCode).then(function() {
|
||||||
extension.navigator.tabs.create("options.html");
|
extension.navigator.tabs.create("options.html");
|
||||||
window.close();
|
window.close();
|
||||||
}).catch(function(e) {
|
}).catch(function(e) {
|
||||||
|
|
157
libtextsecure/account_manager.js
Normal file
157
libtextsecure/account_manager.js
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/* vim: ts=4:sw=4:expandtab
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
;(function () {
|
||||||
|
'use strict';
|
||||||
|
window.textsecure = window.textsecure || {};
|
||||||
|
|
||||||
|
function AccountManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountManager.prototype = {
|
||||||
|
constructor: AccountManager,
|
||||||
|
requestVoiceVerification: function(number) {
|
||||||
|
return TextSecureServer.requestVerificationVoice(number);
|
||||||
|
},
|
||||||
|
requestSMSVerification: function(number) {
|
||||||
|
return TextSecureServer.requestVerificationSMS(number);
|
||||||
|
},
|
||||||
|
registerSingleDevice: function(number, verificationCode) {
|
||||||
|
return axolotl.util.generateIdentityKeyPair().then(function(identityKeyPair) {
|
||||||
|
return createAccount(number, verificationCode, identityKeyPair, true).
|
||||||
|
then(function() { return generateKeys(100); }).
|
||||||
|
then(TextSecureServer.registerKeys).
|
||||||
|
then(textsecure.registration.done);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
registerSecondDevice: function(setProvisioningUrl, confirmNumber, progressCallback) {
|
||||||
|
return textsecure.protocol_wrapper.createIdentityKeyRecvSocket().then(function(cryptoInfo) {
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
new WebSocketResource(textsecure.api.getTempWebsocket(), function(request) {
|
||||||
|
if (request.path == "/v1/address" && request.verb == "PUT") {
|
||||||
|
var proto = textsecure.protobuf.ProvisioningUuid.decode(request.body);
|
||||||
|
setProvisioningUrl([
|
||||||
|
'tsdevice:/?uuid=', proto.uuid, '&pub_key=',
|
||||||
|
encodeURIComponent(btoa(getString(cryptoInfo.pubKey)))
|
||||||
|
].join(''));
|
||||||
|
request.respond(200, 'OK');
|
||||||
|
} else if (request.path == "/v1/message" && request.verb == "PUT") {
|
||||||
|
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(request.body, 'binary');
|
||||||
|
request.respond(200, 'OK');
|
||||||
|
resolve(cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(provisionMessage) {
|
||||||
|
return confirmNumber(provisionMessage.number).then(function() {
|
||||||
|
return createAccount(
|
||||||
|
provisionMessage.number,
|
||||||
|
provisionMessage.provisioningCode,
|
||||||
|
provisionMessage.identityKeyPair,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
console.log('Unknown websocket message', request.path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).then(function() {
|
||||||
|
return generateKeys(100, progressCallback);
|
||||||
|
}).then(TextSecureServer.registerKeys).then(textsecure.registration.done);
|
||||||
|
},
|
||||||
|
refreshPreKeys: function() {
|
||||||
|
return textsecure.api.getMyKeys().then(function(preKeyCount) {
|
||||||
|
if (preKeyCount < 10) {
|
||||||
|
return generateKeys(100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function createAccount(number, verificationCode, identityKeyPair, single_device) {
|
||||||
|
textsecure.storage.put('identityKey', identityKeyPair);
|
||||||
|
|
||||||
|
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 registrationId = axolotl.util.generateRegistrationId();
|
||||||
|
textsecure.storage.put("registrationId", registrationId);
|
||||||
|
|
||||||
|
return textsecure.api.confirmCode(
|
||||||
|
number, verificationCode, password, signalingKey, registrationId, single_device
|
||||||
|
).then(function(response) {
|
||||||
|
textsecure.storage.user.setNumberAndDeviceId(number, response.deviceId || 1);
|
||||||
|
textsecure.storage.put("regionCode", libphonenumber.util.getRegionCodeForNumber(number));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
textsecure.AccountManager = AccountManager;
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
function generateKeys(count, progressCallback) {
|
||||||
|
if (typeof progressCallback !== 'function') {
|
||||||
|
progressCallback = undefined;
|
||||||
|
}
|
||||||
|
var startId = textsecure.storage.get('maxPreKeyId', 1);
|
||||||
|
var signedKeyId = textsecure.storage.get('signedKeyId', 1);
|
||||||
|
|
||||||
|
if (typeof startId != 'number') {
|
||||||
|
throw new Error('Invalid maxPreKeyId');
|
||||||
|
}
|
||||||
|
if (typeof signedKeyId != 'number') {
|
||||||
|
throw new Error('Invalid signedKeyId');
|
||||||
|
}
|
||||||
|
|
||||||
|
var store = textsecure.storage.axolotl;
|
||||||
|
var identityKey = store.getMyIdentityKey();
|
||||||
|
var result = { preKeys: [], identityKey: identityKey.pubKey };
|
||||||
|
var promises = [];
|
||||||
|
|
||||||
|
for (var keyId = startId; keyId < startId+count; ++keyId) {
|
||||||
|
promises.push(
|
||||||
|
axolotl.util.generatePreKey(keyId).then(function(res) {
|
||||||
|
store.putPreKey(res.keyId, res.keyPair);
|
||||||
|
result.preKeys.push({
|
||||||
|
keyId : res.keyId,
|
||||||
|
publicKey : res.keyPair.pubKey
|
||||||
|
});
|
||||||
|
if (progressCallback) { progressCallback(); }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
promises.push(
|
||||||
|
axolotl.util.generateSignedPreKey(identityKey, signedKeyId).then(function(res) {
|
||||||
|
store.putSignedPreKey(res.keyId, res.keyPair);
|
||||||
|
result.signedPreKey = {
|
||||||
|
keyId : res.keyId,
|
||||||
|
publicKey : res.keyPair.pubKey,
|
||||||
|
signature : res.signature
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
store.removeSignedPreKey(signedKeyId - 2);
|
||||||
|
textsecure.storage.put('maxPreKeyId', startId + count);
|
||||||
|
textsecure.storage.put('signedKeyId', signedKeyId + 1);
|
||||||
|
return Promise.all(promises).then(function() {
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
|
@ -247,113 +247,3 @@ textsecure.processDecrypted = function(decrypted, source) {
|
||||||
return decrypted;
|
return decrypted;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
window.textsecure.refreshPreKeys = function() {
|
|
||||||
return textsecure.api.getMyKeys().then(function(preKeyCount) {
|
|
||||||
if (preKeyCount < 10) {
|
|
||||||
generateKeys();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function createAccount(number, verificationCode, identityKeyPair, single_device) {
|
|
||||||
textsecure.storage.put('identityKey', identityKeyPair);
|
|
||||||
|
|
||||||
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 registrationId = axolotl.util.generateRegistrationId();
|
|
||||||
textsecure.storage.put("registrationId", registrationId);
|
|
||||||
|
|
||||||
return textsecure.api.confirmCode(
|
|
||||||
number, verificationCode, password, signalingKey, registrationId, single_device
|
|
||||||
).then(function(response) {
|
|
||||||
textsecure.storage.user.setNumberAndDeviceId(number, response.deviceId || 1);
|
|
||||||
textsecure.storage.put("regionCode", libphonenumber.util.getRegionCodeForNumber(number));
|
|
||||||
|
|
||||||
return textsecure.protocol_wrapper.generateKeys().then(textsecure.registration.done);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateKeys(count, progressCallback) {
|
|
||||||
if (count === undefined) {
|
|
||||||
throw TypeError('generateKeys: count is undefined');
|
|
||||||
}
|
|
||||||
if (typeof progressCallback !== 'function') {
|
|
||||||
progressCallback = undefined;
|
|
||||||
}
|
|
||||||
var store = textsecure.storage.axolotl;
|
|
||||||
var identityKey = store.getMyIdentityKey();
|
|
||||||
var result = { preKeys: [], identityKey: identityKey.pubKey };
|
|
||||||
var promises = [];
|
|
||||||
|
|
||||||
var startId = textsecure.storage.get('maxPreKeyId', 1);
|
|
||||||
var signedKeyId = textsecure.storage.get('signedKeyId', 1);
|
|
||||||
|
|
||||||
for (var keyId = startId; keyId < startId+count; ++keyId) {
|
|
||||||
promises.push(
|
|
||||||
axolotl.util.generatePreKey(keyId).then(function(res) {
|
|
||||||
store.putPreKey(res.keyId, res.keyPair);
|
|
||||||
result.preKeys.push({
|
|
||||||
keyId : res.keyId,
|
|
||||||
publicKey : res.keyPair.pubKey
|
|
||||||
});
|
|
||||||
if (progressCallback) { progressCallback(); }
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
promises.push(
|
|
||||||
axolotl.util.generateSignedPreKey(identityKey, signedKeyId).then(function(res) {
|
|
||||||
store.putSignedPreKey(res.keyId, res.keyPair);
|
|
||||||
result.signedPreKey = {
|
|
||||||
keyId : res.keyId,
|
|
||||||
publicKey : res.keyPair.pubKey,
|
|
||||||
signature : res.signature
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
store.removeSignedPreKey(signedKeyId - 2);
|
|
||||||
textsecure.storage.put('maxPreKeyId', startId + count);
|
|
||||||
textsecure.storage.put('signedKeyId', signedKeyId + 1);
|
|
||||||
|
|
||||||
return Promise.all(promises).then(function() {
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.textsecure.registerSecondDevice = function(setProvisioningUrl, confirmNumber, progressCallback) {
|
|
||||||
return textsecure.protocol_wrapper.createIdentityKeyRecvSocket().then(function(cryptoInfo) {
|
|
||||||
return new Promise(function(resolve) {
|
|
||||||
new WebSocketResource(textsecure.api.getTempWebsocket(), function(request) {
|
|
||||||
if (request.path == "/v1/address" && request.verb == "PUT") {
|
|
||||||
var proto = textsecure.protobuf.ProvisioningUuid.decode(request.body);
|
|
||||||
setProvisioningUrl([
|
|
||||||
'tsdevice:/?uuid=', proto.uuid, '&pub_key=',
|
|
||||||
encodeURIComponent(btoa(getString(cryptoInfo.pubKey)))
|
|
||||||
].join(''));
|
|
||||||
request.respond(200, 'OK');
|
|
||||||
} else if (request.path == "/v1/message" && request.verb == "PUT") {
|
|
||||||
var envelope = textsecure.protobuf.ProvisionEnvelope.decode(request.body, 'binary');
|
|
||||||
request.respond(200, 'OK');
|
|
||||||
resolve(cryptoInfo.decryptAndHandleDeviceInit(envelope).then(function(provisionMessage) {
|
|
||||||
return confirmNumber(provisionMessage.number).then(function() {
|
|
||||||
return createAccount(
|
|
||||||
provisionMessage.number,
|
|
||||||
provisionMessage.provisioningCode,
|
|
||||||
provisionMessage.identityKeyPair,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
console.log('Unknown websocket message', request.path);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
<script type="text/javascript" src="../storage/devices.js" data-cover></script>
|
<script type="text/javascript" src="../storage/devices.js" data-cover></script>
|
||||||
<script type="text/javascript" src="../api.js"></script>
|
<script type="text/javascript" src="../api.js"></script>
|
||||||
<script type="text/javascript" src="../sendmessage.js" data-cover></script>
|
<script type="text/javascript" src="../sendmessage.js" data-cover></script>
|
||||||
|
<script type="text/javascript" src="../account_manager.js" data-></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="fake_api.js"></script>
|
<script type="text/javascript" src="fake_api.js"></script>
|
||||||
<script type="text/javascript" src="helpers_test.js"></script>
|
<script type="text/javascript" src="helpers_test.js"></script>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue