Merge pull request #16 from sachaaaaa/friend_response

Handle prekeys in incoming friend request
pull/20/head
sachaaaaa 7 years ago committed by GitHub
commit 1cf8710127
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -52,9 +52,11 @@ const migrations = [
const contactPreKeys = transaction.db.createObjectStore('contactPreKeys', { keyPath: 'id', autoIncrement : true }); const contactPreKeys = transaction.db.createObjectStore('contactPreKeys', { keyPath: 'id', autoIncrement : true });
contactPreKeys.createIndex('identityKeyString', 'identityKeyString', { unique: false }); contactPreKeys.createIndex('identityKeyString', 'identityKeyString', { unique: false });
contactPreKeys.createIndex('keyId', 'keyId', { unique: false });
const contactSignedPreKeys = transaction.db.createObjectStore('contactSignedPreKeys', { keyPath: 'id', autoIncrement : true }); const contactSignedPreKeys = transaction.db.createObjectStore('contactSignedPreKeys', { keyPath: 'id', autoIncrement : true });
contactSignedPreKeys.createIndex('identityKeyString', 'identityKeyString', { unique: false }); contactSignedPreKeys.createIndex('identityKeyString', 'identityKeyString', { unique: false });
contactSignedPreKeys.createIndex('keyId', 'keyId', { unique: false });
window.log.info('creating debug log'); window.log.info('creating debug log');
transaction.db.createObjectStore('debug'); transaction.db.createObjectStore('debug');

@ -179,7 +179,23 @@
const Group = Model.extend({ storeName: 'groups' }); const Group = Model.extend({ storeName: 'groups' });
const Item = Model.extend({ storeName: 'items' }); const Item = Model.extend({ storeName: 'items' });
const ContactPreKey = Model.extend({ storeName: 'contactPreKeys' }); const ContactPreKey = Model.extend({ storeName: 'contactPreKeys' });
const ContactPreKeyCollection = Backbone.Collection.extend({
storeName: 'contactPreKeys',
database: Whisper.Database,
model: ContactPreKey,
fetchBy(filter) {
return this.fetch({ conditions: filter, });
},
});
const ContactSignedPreKey = Model.extend({ storeName: 'contactSignedPreKeys' }); const ContactSignedPreKey = Model.extend({ storeName: 'contactSignedPreKeys' });
const ContactSignedPreKeyCollection = Backbone.Collection.extend({
storeName: 'contactSignedPreKeys',
database: Whisper.Database,
model: ContactSignedPreKey,
fetchBy(filter) {
return this.fetch({ conditions: filter, });
},
});
function SignalProtocolStore() {} function SignalProtocolStore() {}
@ -261,6 +277,24 @@
); );
}); });
}, },
loadContactPreKeys(filters) {
const contactPreKeys = new ContactPreKeyCollection();
return new Promise((resolve, reject) => {
contactPreKeys.fetchBy(filters).then(() => {
resolve(
contactPreKeys.map(prekey => ({
id: prekey.get('id'),
keyId: prekey.get('keyId'),
publicKey: prekey.get('publicKey'),
identityKeyString: prekey.get('identityKeyString'),
}))
);
}).fail(e => {
window.log.error('Failed to fetch signed prekey with filters', filters);
reject(e);
});
});
},
storeContactPreKey(pubKey, preKey) { storeContactPreKey(pubKey, preKey) {
const prekey = new ContactPreKey({ const prekey = new ContactPreKey({
// id: (autoincrement) // id: (autoincrement)
@ -340,6 +374,27 @@
}); });
}); });
}, },
loadContactSignedPreKeys(filters) {
const contactSignedPreKeys = new ContactSignedPreKeyCollection();
return new Promise((resolve, reject) => {
contactSignedPreKeys.fetchBy(filters).then(() => {
resolve(
contactSignedPreKeys.map(prekey => ({
id: prekey.get('id'),
identityKeyString: prekey.get('identityKeyString'),
publicKey: prekey.get('publicKey'),
signature: prekey.get('signature'),
created_at: prekey.get('created_at'),
keyId: prekey.get('keyId'),
confirmed: prekey.get('confirmed'),
}))
);
}).fail(e => {
window.log.error('Failed to fetch signed prekey with filters', filters);
reject(e);
});
});
},
loadContactSignedPreKey(pubKey) { loadContactSignedPreKey(pubKey) {
const prekey = new ContactSignedPreKey({ identityKeyString: pubKey }); const prekey = new ContactSignedPreKey({ identityKeyString: pubKey });
return new Promise(resolve => { return new Promise(resolve => {

@ -1,4 +1,4 @@
/* global window, libsignal, textsecure */ /* global window, libsignal, textsecure, OutgoingMessage */
// eslint-disable-next-line func-names // eslint-disable-next-line func-names
(function() { (function() {
@ -74,20 +74,77 @@
]); ]);
const preKeyMessage = new textsecure.protobuf.PreKeyBundleMessage({ const preKeyMessage = new textsecure.protobuf.PreKeyBundleMessage({
identityKey, identityKey: new Uint8Array(identityKey),
deviceId: 1, // TODO: fetch from somewhere deviceId: 1, // TODO: fetch from somewhere
preKeyId: preKey.keyId, preKeyId: preKey.keyId,
signedKeyId, signedKeyId,
preKey: preKey.pubKey, preKey: new Uint8Array(preKey.pubKey),
signedKey: signedKey.pubKey, signedKey: new Uint8Array(signedKey.pubKey),
signature: signedKey.signature, signature: new Uint8Array(signedKey.signature),
}); });
return preKeyMessage; return preKeyMessage;
} }
savePreKeyBundleForNumber = async function({ pubKey, preKeyId, preKey, signedKeyId, signedKey, signature }) {
const signedKeyPromise = new Promise(async (resolve) => {
const existingSignedKeys = await textsecure.storage.protocol.loadContactSignedPreKeys({ identityKeyString: pubKey, keyId: signedKeyId });
if (!existingSignedKeys || (existingSignedKeys instanceof Array && existingSignedKeys.length == 0))
{
const signedPreKey = {
keyId: signedKeyId,
publicKey: signedKey,
signature,
};
await textsecure.storage.protocol.storeContactSignedPreKey(pubKey, signedPreKey);
}
resolve();
});
const preKeyPromise = new Promise(async (resolve) => {
const existingPreKeys = textsecure.storage.protocol.loadContactPreKeys({ identityKeyString: pubKey, keyId: preKeyId });
if (!existingPreKeys || (existingPreKeys instanceof Array && existingPreKeys.length == 0))
{
const preKeyObject = {
publicKey: preKey,
keyId: preKeyId,
}
await textsecure.storage.protocol.storeContactPreKey(pubKey, preKeyObject);
}
resolve();
});
await Promise.all([signedKeyPromise, preKeyPromise]);
}
sendEmptyMessageWithPreKeys = async function(pubKey) {
// empty content message
const content = new textsecure.protobuf.Content();
// will be called once the transmission succeeded or failed
const callback = res => {
if (res.errors.length > 0) {
res.errors.forEach(error => console.error(error));
} else {
console.log('empty message sent successfully');
}
};
// send an empty message. The logic in ougoing_message will attach the prekeys.
const outgoingMessage = new textsecure.OutgoingMessage(
null, //server
Date.now(), //timestamp,
[pubKey], //numbers
content, //message
true, //silent
callback, //callback
);
await outgoingMessage.sendToNumber(pubKey);
}
window.libloki.FallBackSessionCipher = FallBackSessionCipher; window.libloki.FallBackSessionCipher = FallBackSessionCipher;
window.libloki.getPreKeyBundleForNumber = getPreKeyBundleForNumber; window.libloki.getPreKeyBundleForNumber = getPreKeyBundleForNumber;
window.libloki.FallBackDecryptionError = FallBackDecryptionError; window.libloki.FallBackDecryptionError = FallBackDecryptionError;
window.libloki.savePreKeyBundleForNumber = savePreKeyBundleForNumber;
window.libloki.sendEmptyMessageWithPreKeys = sendEmptyMessageWithPreKeys;
})(); })();

@ -836,8 +836,13 @@ MessageReceiver.prototype.extend({
} }
}); });
}, },
innerHandleContentMessage(envelope, plaintext) { async innerHandleContentMessage(envelope, plaintext) {
const content = textsecure.protobuf.Content.decode(plaintext); const content = textsecure.protobuf.Content.decode(plaintext);
if (content.preKeyBundleMessage) {
await this.handlePreKeyBundleMessage(envelope, content.preKeyBundleMessage);
}
if (content.syncMessage) { if (content.syncMessage) {
return this.handleSyncMessage(envelope, content.syncMessage); return this.handleSyncMessage(envelope, content.syncMessage);
} else if (content.dataMessage) { } else if (content.dataMessage) {
@ -1059,6 +1064,30 @@ MessageReceiver.prototype.extend({
return this.removeFromCache(envelope); return this.removeFromCache(envelope);
}, },
async handlePreKeyBundleMessage(envelope, preKeyBundleMessage) {
const { preKeyId, signedKeyId } = preKeyBundleMessage;
const [ identityKey, preKey, signedKey, signature ] = [
preKeyBundleMessage.identityKey,
preKeyBundleMessage.preKey,
preKeyBundleMessage.signedKey,
preKeyBundleMessage.signature
].map(k => dcodeIO.ByteBuffer.wrap(k).toArrayBuffer());
if (envelope.source != StringView.arrayBufferToHex(identityKey)) {
throw new Error("Error in handlePreKeyBundleMessage: envelope pubkey does not match pubkey in prekey bundle");
}
const pubKey = envelope.source;
return await libloki.savePreKeyBundleForNumber({
pubKey,
preKeyId,
signedKeyId,
preKey,
signedKey,
signature,
});
},
isBlocked(number) { isBlocked(number) {
return textsecure.storage.get('blocked', []).indexOf(number) >= 0; return textsecure.storage.get('blocked', []).indexOf(number) >= 0;
}, },

@ -116,7 +116,7 @@ OutgoingMessage.prototype = {
if (updateDevices === undefined) { if (updateDevices === undefined) {
return this.server.getKeysForNumber(number).then(handleResult); return this.server.getKeysForNumber(number).then(handleResult);
} }
let promise = Promise.resolve(); let promise = Promise.resolve(true);
updateDevices.forEach(device => { updateDevices.forEach(device => {
promise = promise.then(() => promise = promise.then(() =>
Promise.all([ Promise.all([
@ -217,7 +217,7 @@ OutgoingMessage.prototype = {
request: requestMessage request: requestMessage
}); });
const bytes = new Uint8Array(websocketMessage.encode().toArrayBuffer()) const bytes = new Uint8Array(websocketMessage.encode().toArrayBuffer())
bytes.toString(); // print bytes for debugging purposes: can be injected in mock socket server console.log(bytes.toString()); // print bytes for debugging purposes: can be injected in mock socket server
return bytes; return bytes;
}, },
doSendMessage(number, deviceIds, recurse) { doSendMessage(number, deviceIds, recurse) {
@ -413,3 +413,6 @@ OutgoingMessage.prototype = {
); );
}, },
}; };
window.textsecure = window.textsecure || {};
window.textsecure.OutgoingMessage = OutgoingMessage;

Loading…
Cancel
Save