|
|
@ -25246,6 +25246,7 @@ axolotlInternal.curve25519 = function() {
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
keyPair: function(privKey) {
|
|
|
|
keyPair: function(privKey) {
|
|
|
|
|
|
|
|
return new Promise(function(resolve) {
|
|
|
|
var priv = new Uint8Array(privKey);
|
|
|
|
var priv = new Uint8Array(privKey);
|
|
|
|
priv[0] &= 248;
|
|
|
|
priv[0] &= 248;
|
|
|
|
priv[31] &= 127;
|
|
|
|
priv[31] &= 127;
|
|
|
@ -25272,7 +25273,9 @@ axolotlInternal.curve25519 = function() {
|
|
|
|
Module._free(privateKey_ptr);
|
|
|
|
Module._free(privateKey_ptr);
|
|
|
|
Module._free(basepoint_ptr);
|
|
|
|
Module._free(basepoint_ptr);
|
|
|
|
|
|
|
|
|
|
|
|
return Promise.resolve({ pubKey: res.buffer, privKey: privKey });
|
|
|
|
resolve({ pubKey: res.buffer, privKey: privKey });
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
sharedSecret: function(pubKey, privKey) {
|
|
|
|
sharedSecret: function(pubKey, privKey) {
|
|
|
|
// Where to store the result
|
|
|
|
// Where to store the result
|
|
|
@ -25353,6 +25356,61 @@ axolotlInternal.curve25519 = function() {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}();
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var axolotlInternal = axolotlInternal || {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// I am the...workee?
|
|
|
|
|
|
|
|
var origCurve25519 = axolotlInternal.curve25519;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
axolotlInternal.startWorker = function(url) {
|
|
|
|
|
|
|
|
axolotlInternal.stopWorker(); // there can be only one
|
|
|
|
|
|
|
|
axolotlInternal.curve25519 = new Curve25519Worker(url);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
axolotlInternal.stopWorker = function() {
|
|
|
|
|
|
|
|
if (axolotlInternal.curve25519 instanceof Curve25519Worker) {
|
|
|
|
|
|
|
|
var worker = axolotlInternal.curve25519.worker;
|
|
|
|
|
|
|
|
axolotlInternal.curve25519 = origCurve25519;
|
|
|
|
|
|
|
|
worker.terminate();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function Curve25519Worker(url) {
|
|
|
|
|
|
|
|
this.jobs = {};
|
|
|
|
|
|
|
|
this.jobId = 0;
|
|
|
|
|
|
|
|
this.worker = new Worker(url);
|
|
|
|
|
|
|
|
this.worker.onmessage = function(e) {
|
|
|
|
|
|
|
|
var job = this.jobs[e.data.id];
|
|
|
|
|
|
|
|
if (e.data.error && typeof job.onerror === 'function') {
|
|
|
|
|
|
|
|
job.onerror(new Error(e.data.error));
|
|
|
|
|
|
|
|
} else if (typeof job.onsuccess === 'function') {
|
|
|
|
|
|
|
|
job.onsuccess(e.data.result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
delete this.jobs[e.data.id];
|
|
|
|
|
|
|
|
}.bind(this);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Curve25519Worker.prototype = {
|
|
|
|
|
|
|
|
constructor: Curve25519Worker,
|
|
|
|
|
|
|
|
postMessage: function(methodName, args, onsuccess, onerror) {
|
|
|
|
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
|
|
|
|
this.jobs[this.jobId] = { onsuccess: resolve, onerror: reject };
|
|
|
|
|
|
|
|
this.worker.postMessage({ id: this.jobId, methodName: methodName, args: args });
|
|
|
|
|
|
|
|
this.jobId++;
|
|
|
|
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
keyPair: function(privKey) {
|
|
|
|
|
|
|
|
return this.postMessage('keyPair', [privKey]);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
sharedSecret: function(pubKey, privKey) {
|
|
|
|
|
|
|
|
return this.postMessage('sharedSecret', [pubKey, privKey]);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
sign: function(privKey, message) {
|
|
|
|
|
|
|
|
return this.postMessage('sign', [privKey, message]);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
verify: function(pubKey, message, sig) {
|
|
|
|
|
|
|
|
return this.postMessage('verify', [pubKey, message, sig]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
;(function(){
|
|
|
|
;(function(){
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* CryptoJS core components.
|
|
|
|
* CryptoJS core components.
|
|
|
@ -36816,7 +36874,57 @@ axolotlInternal.utils = function() {
|
|
|
|
'use strict';
|
|
|
|
'use strict';
|
|
|
|
window.axolotl = window.axolotl || {};
|
|
|
|
window.axolotl = window.axolotl || {};
|
|
|
|
|
|
|
|
|
|
|
|
window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
function isNonNegativeInteger(n) {
|
|
|
|
|
|
|
|
return (typeof n === 'number' && (n % 1) === 0 && n >= 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.axolotl.util = {
|
|
|
|
|
|
|
|
generateIdentityKeyPair: function() {
|
|
|
|
|
|
|
|
return axolotlInternal.crypto.createKeyPair();
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
generateRegistrationId: function() {
|
|
|
|
|
|
|
|
var registrationId = new Uint16Array(axolotlInternal.crypto.getRandomBytes(2))[0];
|
|
|
|
|
|
|
|
return registrationId & 0x3fff;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
generateSignedPreKey: function (identityKeyPair, signedKeyId) {
|
|
|
|
|
|
|
|
if (!(identityKeyPair.privKey instanceof ArrayBuffer) ||
|
|
|
|
|
|
|
|
identityKeyPair.privKey.byteLength != 32 ||
|
|
|
|
|
|
|
|
!(identityKeyPair.pubKey instanceof ArrayBuffer) ||
|
|
|
|
|
|
|
|
identityKeyPair.pubKey.byteLength != 33) {
|
|
|
|
|
|
|
|
throw new TypeError('Invalid argument for identityKeyPair');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isNonNegativeInteger(signedKeyId)) {
|
|
|
|
|
|
|
|
throw new TypeError(
|
|
|
|
|
|
|
|
'Invalid argument for signedKeyId: ' + signedKeyId
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return axolotlInternal.crypto.createKeyPair().then(function(keyPair) {
|
|
|
|
|
|
|
|
return axolotlInternal.crypto.Ed25519Sign(identityKeyPair.privKey, keyPair.pubKey).then(function(sig) {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
keyId : signedKeyId,
|
|
|
|
|
|
|
|
keyPair : keyPair,
|
|
|
|
|
|
|
|
signature : sig
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
generatePreKey: function(keyId) {
|
|
|
|
|
|
|
|
if (!isNonNegativeInteger(keyId)) {
|
|
|
|
|
|
|
|
throw new TypeError('Invalid argument for keyId: ' + keyId);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return axolotlInternal.crypto.createKeyPair().then(function(keyPair) {
|
|
|
|
|
|
|
|
return { keyId: keyId, keyPair: keyPair };
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.axolotl.protocol = function(storage_interface) {
|
|
|
|
var self = {};
|
|
|
|
var self = {};
|
|
|
|
|
|
|
|
|
|
|
|
/******************************
|
|
|
|
/******************************
|
|
|
@ -36840,41 +36948,23 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
***************************/
|
|
|
|
***************************/
|
|
|
|
var crypto_storage = {};
|
|
|
|
var crypto_storage = {};
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.putKeyPair = function(keyName, keyPair) {
|
|
|
|
function getRecord(encodedNumber) {
|
|
|
|
storage_interface.put("25519Key" + keyName, keyPair);
|
|
|
|
return storage_interface.getSession(encodedNumber).then(function(serialized) {
|
|
|
|
}
|
|
|
|
if (serialized === undefined) {
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.getNewStoredKeyPair = function(keyName) {
|
|
|
|
|
|
|
|
return axolotlInternal.crypto.createKeyPair().then(function(keyPair) {
|
|
|
|
|
|
|
|
crypto_storage.putKeyPair(keyName, keyPair);
|
|
|
|
|
|
|
|
return keyPair;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.getStoredKeyPair = function(keyName) {
|
|
|
|
|
|
|
|
var res = storage_interface.get("25519Key" + keyName);
|
|
|
|
|
|
|
|
if (res === undefined)
|
|
|
|
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
return { pubKey: axolotlInternal.utils.convertToArrayBuffer(res.pubKey), privKey: axolotlInternal.utils.convertToArrayBuffer(res.privKey) };
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return axolotlInternal.RecipientRecord.deserialize(serialized);
|
|
|
|
crypto_storage.removeStoredKeyPair = function(keyName) {
|
|
|
|
});
|
|
|
|
storage_interface.remove("25519Key" + keyName);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.getIdentityKey = function() {
|
|
|
|
|
|
|
|
return this.getStoredKeyPair("identityKey");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.saveSession = function(encodedNumber, session, registrationId) {
|
|
|
|
crypto_storage.saveSession = function(encodedNumber, session, registrationId) {
|
|
|
|
var record = storage_interface.sessions.get(encodedNumber);
|
|
|
|
return getRecord(encodedNumber).then(function(record) {
|
|
|
|
if (record === undefined) {
|
|
|
|
if (record === undefined) {
|
|
|
|
if (registrationId === undefined)
|
|
|
|
if (registrationId === undefined)
|
|
|
|
throw new Error("Tried to save a session for an existing device that didn't exist");
|
|
|
|
throw new Error("Tried to save a session for an existing device that didn't exist");
|
|
|
|
else
|
|
|
|
else
|
|
|
|
record = new axolotl.sessions.RecipientRecord(session.indexInfo.remoteIdentityKey, registrationId);
|
|
|
|
record = new axolotlInternal.RecipientRecord(session.indexInfo.remoteIdentityKey, registrationId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var sessions = record._sessions;
|
|
|
|
var sessions = record._sessions;
|
|
|
|
|
|
|
|
|
|
|
|
if (record.identityKey === null)
|
|
|
|
if (record.identityKey === null)
|
|
|
@ -36884,7 +36974,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
|
|
|
|
|
|
|
|
var doDeleteSession = false;
|
|
|
|
var doDeleteSession = false;
|
|
|
|
if (session.indexInfo.closed != -1) {
|
|
|
|
if (session.indexInfo.closed != -1) {
|
|
|
|
doDeleteSession = (session.indexInfo.closed < (new Date().getTime() - MESSAGE_LOST_THRESHOLD_MS));
|
|
|
|
doDeleteSession = (session.indexInfo.closed < (Date.now() - MESSAGE_LOST_THRESHOLD_MS));
|
|
|
|
|
|
|
|
|
|
|
|
if (!doDeleteSession) {
|
|
|
|
if (!doDeleteSession) {
|
|
|
|
var keysLeft = false;
|
|
|
|
var keysLeft = false;
|
|
|
@ -36916,24 +37006,27 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
else if (record.registrationId === null)
|
|
|
|
else if (record.registrationId === null)
|
|
|
|
throw new Error("Had open sessions on a record that had no registrationId set");
|
|
|
|
throw new Error("Had open sessions on a record that had no registrationId set");
|
|
|
|
|
|
|
|
|
|
|
|
var identityKey = storage_interface.identityKeys.get(encodedNumber);
|
|
|
|
return storage_interface.getIdentityKey(encodedNumber).then(function(identityKey) {
|
|
|
|
if (identityKey === undefined)
|
|
|
|
if (identityKey !== undefined && axolotlInternal.utils.convertToString(identityKey) !== axolotlInternal.utils.convertToString(record.identityKey))
|
|
|
|
storage_interface.identityKeys.put(encodedNumber, record.identityKey);
|
|
|
|
|
|
|
|
else if (axolotlInternal.utils.convertToString(identityKey) !== axolotlInternal.utils.convertToString(record.identityKey))
|
|
|
|
|
|
|
|
throw new Error("Tried to change identity key at save time");
|
|
|
|
throw new Error("Tried to change identity key at save time");
|
|
|
|
|
|
|
|
|
|
|
|
storage_interface.sessions.put(encodedNumber, record);
|
|
|
|
return storage_interface.putIdentityKey(encodedNumber, record.identityKey).then(function() {
|
|
|
|
|
|
|
|
return storage_interface.putSession(encodedNumber, record.serialize());
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var getSessions = function(encodedNumber) {
|
|
|
|
var getSessions = function(encodedNumber) {
|
|
|
|
var record = storage_interface.sessions.get(encodedNumber);
|
|
|
|
return getRecord(encodedNumber).then(function(record) {
|
|
|
|
if (record === undefined)
|
|
|
|
if (record === undefined)
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
return record._sessions;
|
|
|
|
return record._sessions;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.getOpenSession = function(encodedNumber) {
|
|
|
|
crypto_storage.getOpenSession = function(encodedNumber) {
|
|
|
|
var sessions = getSessions(encodedNumber);
|
|
|
|
return getSessions(encodedNumber).then(function(sessions) {
|
|
|
|
if (sessions === undefined)
|
|
|
|
if (sessions === undefined)
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
|
|
|
|
|
|
|
@ -36941,10 +37034,11 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
if (sessions[key].indexInfo.closed == -1)
|
|
|
|
if (sessions[key].indexInfo.closed == -1)
|
|
|
|
return sessions[key];
|
|
|
|
return sessions[key];
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.getSessionByRemoteEphemeralKey = function(encodedNumber, remoteEphemeralKey) {
|
|
|
|
crypto_storage.getSessionByRemoteEphemeralKey = function(encodedNumber, remoteEphemeralKey) {
|
|
|
|
var sessions = getSessions(encodedNumber);
|
|
|
|
return getSessions(encodedNumber).then(function(sessions) {
|
|
|
|
if (sessions === undefined)
|
|
|
|
if (sessions === undefined)
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
|
|
|
|
|
|
|
@ -36964,15 +37058,17 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
return openSession;
|
|
|
|
return openSession;
|
|
|
|
|
|
|
|
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.getSessionOrIdentityKeyByBaseKey = function(encodedNumber, baseKey) {
|
|
|
|
crypto_storage.getSessionOrIdentityKeyByBaseKey = function(encodedNumber, baseKey) {
|
|
|
|
var record = storage_interface.sessions.get(encodedNumber);
|
|
|
|
return getRecord(encodedNumber).then(function(record) {
|
|
|
|
if (record === undefined) {
|
|
|
|
if (record === undefined) {
|
|
|
|
var identityKey = storage_interface.identityKeys.get(encodedNumber);
|
|
|
|
return storage_interface.getIdentityKey(encodedNumber).then(function(identityKey) {
|
|
|
|
if (identityKey === undefined)
|
|
|
|
if (identityKey === undefined)
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
return { indexInfo: { remoteIdentityKey: identityKey } };
|
|
|
|
return { indexInfo: { remoteIdentityKey: identityKey } };
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var sessions = record._sessions;
|
|
|
|
var sessions = record._sessions;
|
|
|
|
|
|
|
|
|
|
|
@ -36984,6 +37080,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
return { indexInfo: { remoteIdentityKey: record.identityKey } };
|
|
|
|
return { indexInfo: { remoteIdentityKey: record.identityKey } };
|
|
|
|
|
|
|
|
|
|
|
|
throw new Error("Datastore inconsistency: device was stored without identity key");
|
|
|
|
throw new Error("Datastore inconsistency: device was stored without identity key");
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************
|
|
|
|
/*****************************
|
|
|
@ -37026,7 +37123,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var initSession = function(isInitiator, ourEphemeralKey, ourSignedKey, encodedNumber, theirIdentityPubKey, theirEphemeralPubKey, theirSignedPubKey) {
|
|
|
|
var initSession = function(isInitiator, ourEphemeralKey, ourSignedKey, encodedNumber, theirIdentityPubKey, theirEphemeralPubKey, theirSignedPubKey) {
|
|
|
|
var ourIdentityKey = crypto_storage.getIdentityKey();
|
|
|
|
var ourIdentityKey = storage_interface.getMyIdentityKey();
|
|
|
|
|
|
|
|
|
|
|
|
if (isInitiator) {
|
|
|
|
if (isInitiator) {
|
|
|
|
if (ourSignedKey !== undefined)
|
|
|
|
if (ourSignedKey !== undefined)
|
|
|
@ -37112,7 +37209,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
var ratchet = axolotlInternal.utils.convertToString(entry.ephemeralKey);
|
|
|
|
var ratchet = axolotlInternal.utils.convertToString(entry.ephemeralKey);
|
|
|
|
console.log("Checking old chain with added time " + (entry.added/1000));
|
|
|
|
console.log("Checking old chain with added time " + (entry.added/1000));
|
|
|
|
if ((!objectContainsKeys(session[ratchet].messageKeys) && (session[ratchet].chainKey === undefined || session[ratchet].chainKey.key === undefined))
|
|
|
|
if ((!objectContainsKeys(session[ratchet].messageKeys) && (session[ratchet].chainKey === undefined || session[ratchet].chainKey.key === undefined))
|
|
|
|
|| entry.added < new Date().getTime() - MESSAGE_LOST_THRESHOLD_MS) {
|
|
|
|
|| entry.added < Date.now() - MESSAGE_LOST_THRESHOLD_MS) {
|
|
|
|
delete session[ratchet];
|
|
|
|
delete session[ratchet];
|
|
|
|
console.log("...deleted");
|
|
|
|
console.log("...deleted");
|
|
|
|
} else
|
|
|
|
} else
|
|
|
@ -37135,7 +37232,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
for (var i in session) {
|
|
|
|
for (var i in session) {
|
|
|
|
if (session[i].chainKey !== undefined && session[i].chainKey.key !== undefined) {
|
|
|
|
if (session[i].chainKey !== undefined && session[i].chainKey.key !== undefined) {
|
|
|
|
if (!sessionClosedByRemote)
|
|
|
|
if (!sessionClosedByRemote)
|
|
|
|
session.oldRatchetList[session.oldRatchetList.length] = { added: new Date().getTime(), ephemeralKey: i };
|
|
|
|
session.oldRatchetList[session.oldRatchetList.length] = { added: Date.now(), ephemeralKey: i };
|
|
|
|
else
|
|
|
|
else
|
|
|
|
delete session[i].chainKey.key;
|
|
|
|
delete session[i].chainKey.key;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -37143,28 +37240,25 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
// Delete current root key and our ephemeral key pair to disallow ratchet stepping
|
|
|
|
// Delete current root key and our ephemeral key pair to disallow ratchet stepping
|
|
|
|
delete session.currentRatchet['rootKey'];
|
|
|
|
delete session.currentRatchet['rootKey'];
|
|
|
|
delete session.currentRatchet['ephemeralKeyPair'];
|
|
|
|
delete session.currentRatchet['ephemeralKeyPair'];
|
|
|
|
session.indexInfo.closed = new Date().getTime();
|
|
|
|
session.indexInfo.closed = Date.now();
|
|
|
|
removeOldChains(session);
|
|
|
|
removeOldChains(session);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.closeOpenSessionForDevice = function(encodedNumber) {
|
|
|
|
self.closeOpenSessionForDevice = function(encodedNumber) {
|
|
|
|
var session = crypto_storage.getOpenSession(encodedNumber);
|
|
|
|
return crypto_storage.getOpenSession(encodedNumber).then(function(session) {
|
|
|
|
if (session === undefined)
|
|
|
|
if (session === undefined)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
closeSession(session);
|
|
|
|
closeSession(session);
|
|
|
|
crypto_storage.saveSession(encodedNumber, session);
|
|
|
|
return crypto_storage.saveSession(encodedNumber, session);
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var refreshPreKeys;
|
|
|
|
|
|
|
|
var initSessionFromPreKeyWhisperMessage = function(encodedNumber, message) {
|
|
|
|
var initSessionFromPreKeyWhisperMessage = function(encodedNumber, message) {
|
|
|
|
var preKeyPair = crypto_storage.getStoredKeyPair("preKey" + message.preKeyId);
|
|
|
|
return storage_interface.getPreKey(message.preKeyId).then(function(preKeyPair) {
|
|
|
|
var signedPreKeyPair = crypto_storage.getStoredKeyPair("signedKey" + message.signedPreKeyId);
|
|
|
|
return storage_interface.getSignedPreKey(message.signedPreKeyId).then(function(signedPreKeyPair) {
|
|
|
|
|
|
|
|
return crypto_storage.getSessionOrIdentityKeyByBaseKey(encodedNumber, axolotlInternal.utils.convertToArrayBuffer(message.baseKey)).then(function(session) {
|
|
|
|
//TODO: Call refreshPreKeys when it looks like all our prekeys are used up?
|
|
|
|
return crypto_storage.getOpenSession(encodedNumber).then(function(open_session) {
|
|
|
|
|
|
|
|
|
|
|
|
var session = crypto_storage.getSessionOrIdentityKeyByBaseKey(encodedNumber, axolotlInternal.utils.convertToArrayBuffer(message.baseKey));
|
|
|
|
|
|
|
|
var open_session = crypto_storage.getOpenSession(encodedNumber);
|
|
|
|
|
|
|
|
if (signedPreKeyPair === undefined) {
|
|
|
|
if (signedPreKeyPair === undefined) {
|
|
|
|
// Session may or may not be the right one, but if its not, we can't do anything about it
|
|
|
|
// Session may or may not be the right one, but if its not, we can't do anything about it
|
|
|
|
// ...fall through and let decryptWhisperMessage handle that case
|
|
|
|
// ...fall through and let decryptWhisperMessage handle that case
|
|
|
@ -37193,11 +37287,16 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
// Note that the session is not actually saved until the very end of decryptWhisperMessage
|
|
|
|
// Note that the session is not actually saved until the very end of decryptWhisperMessage
|
|
|
|
// ... to ensure that the sender actually holds the private keys for all reported pubkeys
|
|
|
|
// ... to ensure that the sender actually holds the private keys for all reported pubkeys
|
|
|
|
return [new_session, function() {
|
|
|
|
return [new_session, function() {
|
|
|
|
|
|
|
|
return storage_interface.removePreKey(message.preKeyId).then(function() {
|
|
|
|
if (open_session !== undefined)
|
|
|
|
if (open_session !== undefined)
|
|
|
|
crypto_storage.saveSession(encodedNumber, open_session);
|
|
|
|
return crypto_storage.saveSession(encodedNumber, open_session);
|
|
|
|
crypto_storage.removeStoredKeyPair("preKey" + message.preKeyId);
|
|
|
|
});
|
|
|
|
}];
|
|
|
|
}];
|
|
|
|
});;
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var fillMessageKeys = function(chain, counter) {
|
|
|
|
var fillMessageKeys = function(chain, counter) {
|
|
|
@ -37255,7 +37354,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
if (!objectContainsKeys(previousRatchet.messageKeys))
|
|
|
|
if (!objectContainsKeys(previousRatchet.messageKeys))
|
|
|
|
delete session[axolotlInternal.utils.convertToString(ratchet.lastRemoteEphemeralKey)];
|
|
|
|
delete session[axolotlInternal.utils.convertToString(ratchet.lastRemoteEphemeralKey)];
|
|
|
|
else
|
|
|
|
else
|
|
|
|
session.oldRatchetList[session.oldRatchetList.length] = { added: new Date().getTime(), ephemeralKey: ratchet.lastRemoteEphemeralKey };
|
|
|
|
session.oldRatchetList[session.oldRatchetList.length] = { added: Date.now(), ephemeralKey: ratchet.lastRemoteEphemeralKey };
|
|
|
|
}).then(finish);
|
|
|
|
}).then(finish);
|
|
|
|
} else
|
|
|
|
} else
|
|
|
|
return finish();
|
|
|
|
return finish();
|
|
|
@ -37271,12 +37370,18 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
var message = axolotlInternal.protobuf.WhisperMessage.decode(messageProto, 'binary');
|
|
|
|
var message = axolotlInternal.protobuf.WhisperMessage.decode(messageProto, 'binary');
|
|
|
|
var remoteEphemeralKey = axolotlInternal.utils.convertToArrayBuffer(message.ephemeralKey);
|
|
|
|
var remoteEphemeralKey = axolotlInternal.utils.convertToArrayBuffer(message.ephemeralKey);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var promise;
|
|
|
|
if (session === undefined) {
|
|
|
|
if (session === undefined) {
|
|
|
|
var session = crypto_storage.getSessionByRemoteEphemeralKey(encodedNumber, remoteEphemeralKey);
|
|
|
|
promise = crypto_storage.getSessionByRemoteEphemeralKey(encodedNumber, remoteEphemeralKey).then(function(session) {
|
|
|
|
if (session === undefined)
|
|
|
|
if (session === undefined)
|
|
|
|
throw new Error("No session found to decrypt message from " + encodedNumber);
|
|
|
|
throw new Error("No session found to decrypt message from " + encodedNumber);
|
|
|
|
|
|
|
|
return session;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
promise = Promise.resolve(session);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return promise.then(function(session) {
|
|
|
|
return maybeStepRatchet(session, remoteEphemeralKey, message.previousCounter).then(function() {
|
|
|
|
return maybeStepRatchet(session, remoteEphemeralKey, message.previousCounter).then(function() {
|
|
|
|
var chain = session[axolotlInternal.utils.convertToString(message.ephemeralKey)];
|
|
|
|
var chain = session[axolotlInternal.utils.convertToString(message.ephemeralKey)];
|
|
|
|
|
|
|
|
|
|
|
@ -37287,7 +37392,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
var messageProtoArray = axolotlInternal.utils.convertToArrayBuffer(messageProto);
|
|
|
|
var messageProtoArray = axolotlInternal.utils.convertToArrayBuffer(messageProto);
|
|
|
|
var macInput = new Uint8Array(messageProtoArray.byteLength + 33*2 + 1);
|
|
|
|
var macInput = new Uint8Array(messageProtoArray.byteLength + 33*2 + 1);
|
|
|
|
macInput.set(new Uint8Array(axolotlInternal.utils.convertToArrayBuffer(session.indexInfo.remoteIdentityKey)));
|
|
|
|
macInput.set(new Uint8Array(axolotlInternal.utils.convertToArrayBuffer(session.indexInfo.remoteIdentityKey)));
|
|
|
|
macInput.set(new Uint8Array(axolotlInternal.utils.convertToArrayBuffer(crypto_storage.getIdentityKey().pubKey)), 33);
|
|
|
|
macInput.set(new Uint8Array(axolotlInternal.utils.convertToArrayBuffer(storage_interface.getMyIdentityKey().pubKey)), 33);
|
|
|
|
macInput[33*2] = (3 << 4) | 3;
|
|
|
|
macInput[33*2] = (3 << 4) | 3;
|
|
|
|
macInput.set(new Uint8Array(messageProtoArray), 33*2 + 1);
|
|
|
|
macInput.set(new Uint8Array(messageProtoArray), 33*2 + 1);
|
|
|
|
|
|
|
|
|
|
|
@ -37309,17 +37414,19 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
|
|
|
|
|
|
|
|
delete session['pendingPreKey'];
|
|
|
|
delete session['pendingPreKey'];
|
|
|
|
removeOldChains(session);
|
|
|
|
removeOldChains(session);
|
|
|
|
crypto_storage.saveSession(encodedNumber, session, registrationId);
|
|
|
|
return crypto_storage.saveSession(encodedNumber, session, registrationId).then(function() {
|
|
|
|
return [plaintext, function() {
|
|
|
|
return [plaintext, function() {
|
|
|
|
closeSession(session, true);
|
|
|
|
closeSession(session, true);
|
|
|
|
removeOldChains(session);
|
|
|
|
removeOldChains(session);
|
|
|
|
crypto_storage.saveSession(encodedNumber, session);
|
|
|
|
return crypto_storage.saveSession(encodedNumber, session);
|
|
|
|
}];
|
|
|
|
}];
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
/*************************
|
|
|
@ -37338,7 +37445,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
return initSessionFromPreKeyWhisperMessage(from, preKeyProto).then(function(sessions) {
|
|
|
|
return initSessionFromPreKeyWhisperMessage(from, preKeyProto).then(function(sessions) {
|
|
|
|
return doDecryptWhisperMessage(from, axolotlInternal.utils.convertToString(preKeyProto.message), sessions[0], preKeyProto.registrationId).then(function(result) {
|
|
|
|
return doDecryptWhisperMessage(from, axolotlInternal.utils.convertToString(preKeyProto.message), sessions[0], preKeyProto.registrationId).then(function(result) {
|
|
|
|
if (sessions[1] !== undefined)
|
|
|
|
if (sessions[1] !== undefined)
|
|
|
|
sessions[1]();
|
|
|
|
return sessions[1]().then(function() { return result; });
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -37346,7 +37453,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
|
|
|
|
|
|
|
|
// return Promise(encoded [PreKey]WhisperMessage)
|
|
|
|
// return Promise(encoded [PreKey]WhisperMessage)
|
|
|
|
self.encryptMessageFor = function(deviceObject, pushMessageContent) {
|
|
|
|
self.encryptMessageFor = function(deviceObject, pushMessageContent) {
|
|
|
|
var session = crypto_storage.getOpenSession(deviceObject.encodedNumber);
|
|
|
|
return crypto_storage.getOpenSession(deviceObject.encodedNumber).then(function(session) {
|
|
|
|
var hadSession = session !== undefined;
|
|
|
|
var hadSession = session !== undefined;
|
|
|
|
|
|
|
|
|
|
|
|
var doEncryptPushMessageContent = function() {
|
|
|
|
var doEncryptPushMessageContent = function() {
|
|
|
@ -37371,7 +37478,7 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
var encodedMsg = axolotlInternal.utils.convertToArrayBuffer(msg.encode());
|
|
|
|
var encodedMsg = axolotlInternal.utils.convertToArrayBuffer(msg.encode());
|
|
|
|
|
|
|
|
|
|
|
|
var macInput = new Uint8Array(encodedMsg.byteLength + 33*2 + 1);
|
|
|
|
var macInput = new Uint8Array(encodedMsg.byteLength + 33*2 + 1);
|
|
|
|
macInput.set(new Uint8Array(axolotlInternal.utils.convertToArrayBuffer(crypto_storage.getIdentityKey().pubKey)));
|
|
|
|
macInput.set(new Uint8Array(axolotlInternal.utils.convertToArrayBuffer(storage_interface.getMyIdentityKey().pubKey)));
|
|
|
|
macInput.set(new Uint8Array(axolotlInternal.utils.convertToArrayBuffer(session.indexInfo.remoteIdentityKey)), 33);
|
|
|
|
macInput.set(new Uint8Array(axolotlInternal.utils.convertToArrayBuffer(session.indexInfo.remoteIdentityKey)), 33);
|
|
|
|
macInput[33*2] = (3 << 4) | 3;
|
|
|
|
macInput[33*2] = (3 << 4) | 3;
|
|
|
|
macInput.set(new Uint8Array(encodedMsg), 33*2 + 1);
|
|
|
|
macInput.set(new Uint8Array(encodedMsg), 33*2 + 1);
|
|
|
@ -37384,16 +37491,17 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
|
|
|
|
|
|
|
|
removeOldChains(session);
|
|
|
|
removeOldChains(session);
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.saveSession(deviceObject.encodedNumber, session, !hadSession ? deviceObject.registrationId : undefined);
|
|
|
|
return crypto_storage.saveSession(deviceObject.encodedNumber, session, !hadSession ? deviceObject.registrationId : undefined).then(function() {
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var preKeyMsg = new axolotlInternal.protobuf.PreKeyWhisperMessage();
|
|
|
|
var preKeyMsg = new axolotlInternal.protobuf.PreKeyWhisperMessage();
|
|
|
|
preKeyMsg.identityKey = axolotlInternal.utils.convertToArrayBuffer(crypto_storage.getIdentityKey().pubKey);
|
|
|
|
preKeyMsg.identityKey = axolotlInternal.utils.convertToArrayBuffer(storage_interface.getMyIdentityKey().pubKey);
|
|
|
|
preKeyMsg.registrationId = storage_interface.getMyRegistrationId();
|
|
|
|
preKeyMsg.registrationId = storage_interface.getMyRegistrationId();
|
|
|
|
|
|
|
|
|
|
|
|
if (session === undefined) {
|
|
|
|
if (session === undefined) {
|
|
|
@ -37404,9 +37512,10 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
preKeyMsg.preKeyId = deviceObject.preKeyId;
|
|
|
|
preKeyMsg.preKeyId = deviceObject.preKeyId;
|
|
|
|
preKeyMsg.signedPreKeyId = deviceObject.signedKeyId;
|
|
|
|
preKeyMsg.signedPreKeyId = deviceObject.signedKeyId;
|
|
|
|
preKeyMsg.baseKey = axolotlInternal.utils.convertToArrayBuffer(baseKey.pubKey);
|
|
|
|
preKeyMsg.baseKey = axolotlInternal.utils.convertToArrayBuffer(baseKey.pubKey);
|
|
|
|
return initSession(true, baseKey, undefined, deviceObject.encodedNumber,
|
|
|
|
return initSession(true, baseKey, undefined,
|
|
|
|
deviceIdentityKey, axolotlInternal.utils.convertToArrayBuffer(deviceObject.preKey), deviceSignedKey)
|
|
|
|
deviceObject.encodedNumber, deviceIdentityKey,
|
|
|
|
.then(function(new_session) {
|
|
|
|
axolotlInternal.utils.convertToArrayBuffer(deviceObject.preKey),
|
|
|
|
|
|
|
|
deviceSignedKey).then(function(new_session) {
|
|
|
|
session = new_session;
|
|
|
|
session = new_session;
|
|
|
|
session.pendingPreKey = { preKeyId: deviceObject.preKeyId, signedKeyId: deviceObject.signedKeyId, baseKey: baseKey.pubKey };
|
|
|
|
session.pendingPreKey = { preKeyId: deviceObject.preKeyId, signedKeyId: deviceObject.signedKeyId, baseKey: baseKey.pubKey };
|
|
|
|
return doEncryptPushMessageContent().then(function(message) {
|
|
|
|
return doEncryptPushMessageContent().then(function(message) {
|
|
|
@ -37430,70 +37539,9 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
} else
|
|
|
|
} else
|
|
|
|
return {type: 1, body: axolotlInternal.utils.convertToString(message)};
|
|
|
|
return {type: 1, body: axolotlInternal.utils.convertToString(message)};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var GENERATE_KEYS_KEYS_GENERATED = 100;
|
|
|
|
|
|
|
|
self.generateKeys = function() {
|
|
|
|
|
|
|
|
var identityKeyPair = crypto_storage.getIdentityKey();
|
|
|
|
|
|
|
|
var identityKeyCalculated = function(identityKeyPair) {
|
|
|
|
|
|
|
|
var firstPreKeyId = storage_interface.get("maxPreKeyId", 0);
|
|
|
|
|
|
|
|
storage_interface.put("maxPreKeyId", firstPreKeyId + GENERATE_KEYS_KEYS_GENERATED);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var signedKeyId = storage_interface.get("signedKeyId", 0);
|
|
|
|
|
|
|
|
storage_interface.put("signedKeyId", signedKeyId + 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var keys = {};
|
|
|
|
|
|
|
|
keys.identityKey = identityKeyPair.pubKey;
|
|
|
|
|
|
|
|
keys.preKeys = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var generateKey = function(keyId) {
|
|
|
|
|
|
|
|
return crypto_storage.getNewStoredKeyPair("preKey" + keyId, false).then(function(keyPair) {
|
|
|
|
|
|
|
|
keys.preKeys[keyId] = {keyId: keyId, publicKey: keyPair.pubKey};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var promises = [];
|
|
|
|
|
|
|
|
for (var i = firstPreKeyId; i < firstPreKeyId + GENERATE_KEYS_KEYS_GENERATED; i++)
|
|
|
|
|
|
|
|
promises[i] = generateKey(i);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
promises[firstPreKeyId + GENERATE_KEYS_KEYS_GENERATED] = crypto_storage.getNewStoredKeyPair("signedKey" + signedKeyId).then(function(keyPair) {
|
|
|
|
|
|
|
|
return axolotlInternal.crypto.Ed25519Sign(identityKeyPair.privKey, keyPair.pubKey).then(function(sig) {
|
|
|
|
|
|
|
|
keys.signedPreKey = {keyId: signedKeyId, publicKey: keyPair.pubKey, signature: sig};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: Process by date added and agressively call generateKeys when we get near maxPreKeyId in a message
|
|
|
|
|
|
|
|
crypto_storage.removeStoredKeyPair("signedKey" + (signedKeyId - 2));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Promise.all(promises).then(function() {
|
|
|
|
|
|
|
|
storage_interface.put("lastPreKeyUpdate", Date.now());
|
|
|
|
|
|
|
|
return keys;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (identityKeyPair === undefined)
|
|
|
|
|
|
|
|
return crypto_storage.getNewStoredKeyPair("identityKey").then(function(keyPair) { return identityKeyCalculated(keyPair); });
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
return identityKeyCalculated(identityKeyPair);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: Replace this stuff
|
|
|
|
|
|
|
|
refreshPreKeys = function() {
|
|
|
|
|
|
|
|
self.generateKeys().then(function(keys) {
|
|
|
|
|
|
|
|
console.log("Pre Keys updated!");
|
|
|
|
|
|
|
|
return updateKeysCallback(keys);
|
|
|
|
|
|
|
|
}).catch(function(e) {
|
|
|
|
|
|
|
|
//TODO: Notify the user somehow???
|
|
|
|
|
|
|
|
console.error(e);
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (updateKeysCallback)
|
|
|
|
|
|
|
|
window.setInterval(function() {
|
|
|
|
|
|
|
|
// Note that this will not ever run until generateKeys has been called at least once
|
|
|
|
|
|
|
|
if (storage_interface.get("lastPreKeyUpdate", Date.now()) < Date.now() - MESSAGE_LOST_THRESHOLD_MS)
|
|
|
|
|
|
|
|
refreshPreKeys();
|
|
|
|
|
|
|
|
}, 60 * 1000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.createIdentityKeyRecvSocket = function() {
|
|
|
|
self.createIdentityKeyRecvSocket = function() {
|
|
|
|
var socketInfo = {};
|
|
|
|
var socketInfo = {};
|
|
|
|
var keyPair;
|
|
|
|
var keyPair;
|
|
|
@ -37514,16 +37562,16 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
|
|
|
|
|
|
|
|
return verifyMAC(ivAndCiphertext, keys[1], mac).then(function() {
|
|
|
|
return verifyMAC(ivAndCiphertext, keys[1], mac).then(function() {
|
|
|
|
return axolotlInternal.crypto.decrypt(keys[0], ciphertext, iv).then(function(plaintext) {
|
|
|
|
return axolotlInternal.crypto.decrypt(keys[0], ciphertext, iv).then(function(plaintext) {
|
|
|
|
var identityKeyMsg = axolotlInternal.protobuf.ProvisionMessage.decode(plaintext);
|
|
|
|
var provisionMessage = axolotlInternal.protobuf.ProvisionMessage.decode(plaintext);
|
|
|
|
|
|
|
|
|
|
|
|
return axolotlInternal.crypto.createKeyPair(axolotlInternal.utils.convertToArrayBuffer(identityKeyMsg.identityKeyPrivate)).then(function(identityKeyPair) {
|
|
|
|
|
|
|
|
if (crypto_storage.getStoredKeyPair("identityKey") !== undefined)
|
|
|
|
|
|
|
|
throw new Error("Tried to overwrite identity key");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
crypto_storage.putKeyPair("identityKey", identityKeyPair);
|
|
|
|
|
|
|
|
identityKeyMsg.identityKeyPrivate = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return identityKeyMsg;
|
|
|
|
return axolotlInternal.crypto.createKeyPair(
|
|
|
|
|
|
|
|
provisionMessage.identityKeyPrivate.toArrayBuffer()
|
|
|
|
|
|
|
|
).then(function(identityKeyPair) {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
identityKeyPair : identityKeyPair,
|
|
|
|
|
|
|
|
number : provisionMessage.number,
|
|
|
|
|
|
|
|
provisioningCode : provisionMessage.provisioningCode
|
|
|
|
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -37538,6 +37586,32 @@ window.axolotl.protocol = function(storage_interface, updateKeysCallback) {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.getRegistrationId = function(encodedNumber) {
|
|
|
|
|
|
|
|
return getRecord(encodedNumber).then(function(record) {
|
|
|
|
|
|
|
|
if (record === undefined) {
|
|
|
|
|
|
|
|
return undefined;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return record.registrationId;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.hasOpenSession = function(encodedNumber) {
|
|
|
|
|
|
|
|
return getRecord(encodedNumber).then(function(record) {
|
|
|
|
|
|
|
|
if (record === undefined) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return record.haveOpenSession();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.startWorker = function(url) {
|
|
|
|
|
|
|
|
axolotlInternal.startWorker(url);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
self.stopWorker = function() {
|
|
|
|
|
|
|
|
axolotlInternal.stopWorker();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
return self;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -37660,10 +37734,11 @@ axolotlInternal.protobuf = function() {
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
;(function() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var axolotlInternal = axolotlInternal || {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
axolotlInternal.RecipientRecord = function() {
|
|
|
|
'use strict';
|
|
|
|
'use strict';
|
|
|
|
window.axolotl = window.axolotl || {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var RecipientRecord = function(identityKey, registrationId) {
|
|
|
|
var RecipientRecord = function(identityKey, registrationId) {
|
|
|
|
this._sessions = {};
|
|
|
|
this._sessions = {};
|
|
|
@ -37678,26 +37753,23 @@ RecipientRecord.prototype.serialize = function() {
|
|
|
|
return axolotlInternal.utils.jsonThing({sessions: this._sessions, registrationId: this.registrationId, identityKey: this.identityKey});
|
|
|
|
return axolotlInternal.utils.jsonThing({sessions: this._sessions, registrationId: this.registrationId, identityKey: this.identityKey});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RecipientRecord.prototype.deserialize = function(serialized) {
|
|
|
|
RecipientRecord.deserialize = function(serialized) {
|
|
|
|
var data = JSON.parse(serialized);
|
|
|
|
var data = JSON.parse(serialized);
|
|
|
|
this._sessions = data.sessions;
|
|
|
|
var record = new RecipientRecord(data.identityKey, data.registrationId);
|
|
|
|
if (this._sessions === undefined || this._sessions === null || typeof this._sessions !== "object" || Array.isArray(this._sessions))
|
|
|
|
record._sessions = data.sessions;
|
|
|
|
|
|
|
|
if (record._sessions === undefined || record._sessions === null || typeof record._sessions !== "object" || Array.isArray(record._sessions))
|
|
|
|
throw new Error("Error deserializing RecipientRecord");
|
|
|
|
throw new Error("Error deserializing RecipientRecord");
|
|
|
|
this.identityKey = data.identityKey;
|
|
|
|
if (record.identityKey === undefined || record.registrationId === undefined)
|
|
|
|
this.registrationId = data.registrationId;
|
|
|
|
|
|
|
|
if (this.identityKey === undefined || this.registrationId === undefined)
|
|
|
|
|
|
|
|
throw new Error("Error deserializing RecipientRecord");
|
|
|
|
throw new Error("Error deserializing RecipientRecord");
|
|
|
|
|
|
|
|
return record;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RecipientRecord.prototype.haveOpenSession = function() {
|
|
|
|
RecipientRecord.prototype.haveOpenSession = function() {
|
|
|
|
return this.registrationId !== null;
|
|
|
|
return this.registrationId !== null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
window.axolotl.sessions = {
|
|
|
|
return RecipientRecord;
|
|
|
|
RecipientRecord: RecipientRecord,
|
|
|
|
}();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
})();
|
|
|
|
'use strict';
|
|
|
|
'use strict';
|
|
|
|