瀏覽代碼

Fetch and parse bundles, then generate sessions for them

udpates #497
JC Brand 7 年之前
父節點
當前提交
839210f87c
共有 1 個文件被更改,包括 63 次插入39 次删除
  1. 63 39
      src/converse-omemo.js

+ 63 - 39
src/converse-omemo.js

@@ -70,61 +70,80 @@
                             'to': this.get('jid')
                             'to': this.get('jid')
                         }).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
                         }).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
                             .c('items', {'xmlns': `${Strophe.NS.OMEMO_BUNDLES}:${device_id}`});
                             .c('items', {'xmlns': `${Strophe.NS.OMEMO_BUNDLES}:${device_id}`});
-                        _converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
+                        _converse.connection.sendIQ(
+                            stanza,
+                            (iq) => resolve((device_id, this.parseBundle(iq))),
+                            reject,
+                            _converse.IQ_TIMEOUT
+                        );
                     });
                     });
                 },
                 },
 
 
-                fetchBundles () {
-                    return getDevicesForContact(this.get('jid')).then((devices) => {
-                        return Promise.all(_.map(devices, (device_id) => this.fetchBundle(device_id)));
-                    });
+                parseBundle (device_id, stanza) {
+                    const publish_el = sizzle(`publish[node="${Strophe.NS.OMEMO_BUNDLES}:${device_id}"]`, stanza).pop();
+                    const bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop();
+                    const prekeys = _.map(
+                        sizzle(`> prekeys > preKeyPublic`, bundle_el),
+                        (key) => { return (key.getAttribute('id'), key.textContent) });
+
+                    return {
+                        'device_id': device_id,
+                        'identity_key': bundle_el.querySelector('> identityKey').textContent,
+                        'prekeys': prekeys
+                    }
                 },
                 },
 
 
+                fetchBundles () {
+                    const { _converse } = this.__super__;
+                    return new Promise((resolve, reject) => {
+                        getDevicesForContact(this.get('jid'))
+                            .then((devices) => Promise.all(_.map(devices, (device_id) => this.fetchBundle(device_id))))
+                            .then((bundles) => {
+                                this.buildSessions()
+                                    .then(() => resolve(bundles))
+                                    .catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
+                            });
+                    }).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
+                },
 
 
-                buildSession () {
-                    // TODO
-                    return Promise.resolve();
-                    // const { _converse } = this.__super__,
-                    //       device_id = _converse.omemo_store.get('device_id');
-
-                    // return new Promise((resolve, reject) => {
-                    //     getDevicesForContact(this.get('jid')).then((devices) => {
-                    //         const session_promises = _.map(devices, (recipient_id) => {
-                    //             const address = new libsignal.SignalProtocolAddress(recipient_id, device_id),
-                    //                 sessionBuilder = new libsignal.SessionBuilder(_converse.omemo_store, address);
-                    //             return sessionBuilder.processPreKey({
-                    //                 'registrationId': _converse.omemo_store.get('registration_id'),
-                    //                 'identityKey': _converse.omemo_store.get('identity_keypair'),
-                    //                 'signedPreKey': {
-                    //                     'keyId': '', // <Number>,
-                    //                     'publicKey': '', // <ArrayBuffer>,
-                    //                     'signature': '', // <ArrayBuffer>
-                    //                 },
-                    //                 'preKey': {
-                    //                     'keyId': '', // <Number>,
-                    //                     'publicKey': '', // <ArrayBuffer>
-                    //                 }
-                    //             });
-                    //         });
-                    //         resolve(session_promises);
-                    //     }).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
-                    // });
+                buildSessions (bundles) {
+                    const { _converse } = this.__super__,
+                          device_id = _converse.omemo_store.get('device_id');
+
+                    return Promise.all(_.map(bundles, (bundle) => {
+                        const recipient_id = bundles['device_id'];
+                        const address = new libsignal.SignalProtocolAddress(recipient_id, device_id);
+                        const sessionBuilder = new libsignal.SessionBuilder(_converse.omemo_store, address);
+                        return sessionBuilder.processPreKey({
+                            'registrationId': _converse.omemo_store.get('registration_id'),
+                            'identityKey': _converse.omemo_store.get('identity_keypair'),
+                            'signedPreKey': {
+                                'keyId': '', // <Number>,
+                                'publicKey': '', // <ArrayBuffer>,
+                                'signature': '', // <ArrayBuffer>
+                            },
+                            'preKey': {
+                                'keyId': '', // <Number>,
+                                'publicKey': '', // <ArrayBuffer>
+                            }
+                        });
+                    }));
                 },
                 },
 
 
                 encryptMessage (message) {
                 encryptMessage (message) {
                     // TODO:
                     // TODO:
-                    return Promise.resolve();
                     // const { _converse } = this.__super__;
                     // const { _converse } = this.__super__;
                     // const plaintext = message.get('message');
                     // const plaintext = message.get('message');
+                    // const address = new libsignal.SignalProtocolAddress(recipientId, deviceId);
                     // return new Promise((resolve, reject) => {
                     // return new Promise((resolve, reject) => {
                     //     var sessionCipher = new window.libsignal.SessionCipher(_converse.omemo_store, address);
                     //     var sessionCipher = new window.libsignal.SessionCipher(_converse.omemo_store, address);
                     //     sessionCipher.encrypt(plaintext).then((ciphertext) => {});
                     //     sessionCipher.encrypt(plaintext).then((ciphertext) => {});
                     // });
                     // });
                 },
                 },
 
 
-                createOMEMOMessageStanza (message) {
+                createOMEMOMessageStanza (message, bundles) {
                     const { _converse } = this.__super__;
                     const { _converse } = this.__super__;
-                    const body = "I sent you an OMEMO encrypted message but your client doesn’t seem to support that. "+
+                    const body = "This is an OMEMO encrypted message which your client doesn’t seem to support. "+
                                  "Find more information on https://conversations.im/omemo";
                                  "Find more information on https://conversations.im/omemo";
                     return new Promise((resolve, reject) => {
                     return new Promise((resolve, reject) => {
                         this.encryptMessage(message).then((payload) => {
                         this.encryptMessage(message).then((payload) => {
@@ -134,8 +153,13 @@
                                     'type': this.get('message_type'),
                                     'type': this.get('message_type'),
                                     'id': message.get('msgid')
                                     'id': message.get('msgid')
                                 }).c('body').t(body).up()
                                 }).c('body').t(body).up()
-                                  .c('encrypted').t(payload).up()
-                                .c(_converse.ACTIVE, {'xmlns': Strophe.NS.CHATSTATES}).up();
+                                  .c('encrypted').t(payload)
+                                  .c('header').t(payload).up()
+
+                            _.forEach(bundles, (bundle) => {
+                                const prekey = bundle.prekeys[Math.random(bundle.prekeys.length)].textContent;
+                                stanza('key', {'rid': bundle.identity_key}).t(prekey).up()
+                            });
                             // TODO: set storage hint urn:xmpp:hints
                             // TODO: set storage hint urn:xmpp:hints
                             resolve(stanza);
                             resolve(stanza);
                         }).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
                         }).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
@@ -144,7 +168,7 @@
 
 
                 createMessageStanza (message) {
                 createMessageStanza (message) {
                     if (this.get('omemo_active')) {
                     if (this.get('omemo_active')) {
-                        return this.buildSession().then(() => this.createOMEMOMessageStanza(message));
+                        return this.fetchBundles().then((bundles) => this.createOMEMOMessageStanza(message, bundles));
                     } else {
                     } else {
                         return Promise.resolve(this.__super__.createMessageStanza.apply(this, arguments));
                         return Promise.resolve(this.__super__.createMessageStanza.apply(this, arguments));
                     }
                     }