Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
converse.js
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
converse.js
Commits
fa0e7aef
Commit
fa0e7aef
authored
Aug 22, 2018
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updated so that own device is properly created and published
Based on live testing. Updated tests accordingly.
parent
a422f078
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
417 additions
and
325 deletions
+417
-325
dist/converse.js
dist/converse.js
+173
-175
spec/chatbox.js
spec/chatbox.js
+3
-3
spec/omemo.js
spec/omemo.js
+147
-41
spec/presence.js
spec/presence.js
+5
-5
src/converse-omemo.js
src/converse-omemo.js
+88
-100
tests/utils.js
tests/utils.js
+1
-1
No files found.
dist/converse.js
View file @
fa0e7aef
...
@@ -63067,9 +63067,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -63067,9 +63067,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
* that contains the message stanza, if it was
* that contains the message stanza, if it was
* contained, otherwise it's the message stanza itself.
* contained, otherwise it's the message stanza itself.
*/
*/
const _converse = this.__super__._converse,
const archive = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop(),
__ = _converse.__,
archive = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop(),
spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(),
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(),
chat_state = stanza.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING || stanza.getElementsByTagName(_converse.PAUSED).length && _converse.PAUSED || stanza.getElementsByTagName(_converse.INACTIVE).length && _converse.INACTIVE || stanza.getElementsByTagName(_converse.ACTIVE).length && _converse.ACTIVE || stanza.getElementsByTagName(_converse.GONE).length && _converse.GONE;
chat_state = stanza.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING || stanza.getElementsByTagName(_converse.PAUSED).length && _converse.PAUSED || stanza.getElementsByTagName(_converse.INACTIVE).length && _converse.INACTIVE || stanza.getElementsByTagName(_converse.ACTIVE).length && _converse.ACTIVE || stanza.getElementsByTagName(_converse.GONE).length && _converse.GONE;
...
@@ -63775,9 +63773,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -63775,9 +63773,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
emojione.ascii = true;
emojione.ascii = true;
function onWindowStateChanged(data) {
function onWindowStateChanged(data) {
_converse.chatboxviews.each(function (chatboxview) {
if (_converse.chatboxviews) {
chatboxview.onWindowStateChanged(data.state);
_converse.chatboxviews.each(chatboxview => {
});
chatboxview.onWindowStateChanged(data.state);
});
}
}
}
_converse.api.listen.on('windowStateChanged', onWindowStateChanged);
_converse.api.listen.on('windowStateChanged', onWindowStateChanged);
...
@@ -66011,11 +66011,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -66011,11 +66011,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
_converse.connection.reset();
_converse.connection.reset();
_converse.off();
_converse.stopListening();
_converse.stopListening();
_converse.tearDown();
_converse.tearDown();
_converse.off();
}
}
if ('onpagehide' in window) {
if ('onpagehide' in window) {
...
@@ -69986,6 +69986,10 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -69986,6 +69986,10 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
});
});
_converse.api.listen.on('afterTearDown', () => {
_converse.api.listen.on('afterTearDown', () => {
if (!_converse.chatboxviews) {
return;
}
const container = _converse.chatboxviews.el.querySelector("#converse-modals");
const container = _converse.chatboxviews.el.querySelector("#converse-modals");
if (container) {
if (container) {
...
@@ -74075,6 +74079,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74075,6 +74079,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
this.devicelist = _converse.devicelists.get(_converse.bare_jid);
this.devicelist = _converse.devicelists.get(_converse.bare_jid);
this.devicelist.devices.on('change:bundle', this.debouncedRender, this);
this.devicelist.devices.on('change:bundle', this.debouncedRender, this);
this.devicelist.devices.on('reset', this.debouncedRender, this);
this.devicelist.devices.on('reset', this.debouncedRender, this);
this.devicelist.devices.on('remove', this.debouncedRender, this);
return this.__super__.initialize.apply(this, arguments);
return this.__super__.initialize.apply(this, arguments);
},
},
...
@@ -74131,6 +74136,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74131,6 +74136,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
});
});
this.devicelist.devices.on('change:bundle', this.render, this);
this.devicelist.devices.on('change:bundle', this.render, this);
this.devicelist.devices.on('change:trusted', this.render, this);
this.devicelist.devices.on('change:trusted', this.render, this);
this.devicelist.devices.on('remove', this.render, this);
this.devicelist.devices.on('reset', this.render, this);
return this.__super__.initialize.apply(this, arguments);
return this.__super__.initialize.apply(this, arguments);
},
},
...
@@ -74162,21 +74169,30 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74162,21 +74169,30 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
address = new libsignal.SignalProtocolAddress(device.get('jid'), device.get('id')),
address = new libsignal.SignalProtocolAddress(device.get('jid'), device.get('id')),
sessionBuilder = new libsignal.SessionBuilder(_converse.omemo_store, address),
sessionBuilder = new libsignal.SessionBuilder(_converse.omemo_store, address),
prekey = device.getRandomPreKey();
prekey = device.getRandomPreKey();
return sessionBuilder.processPreKey({
'registrationId': _converse.omemo_store.get('registration_id'),
try {
'identityKey': _converse.omemo_store.get('identity_keypair'),
return sessionBuilder.processPreKey({
'signedPreKey': {
'registrationId': parseInt(_converse.omemo_store.get('device_id'), 10),
'keyId': bundle.signed_prekey.id,
'identityKey': _converse.omemo_store.get('identity_key'),
// <Number>
'signedPreKey': {
'publicKey': u.base64ToArrayBuffer(bundle.signed_prekey.public_key),
'keyId': bundle.signed_prekey.id,
'signature': u.base64ToArrayBuffer(bundle.signed_prekey.signature)
// <Number>
},
'publicKey': u.base64ToArrayBuffer(bundle.signed_prekey.public_key),
'preKey': {
'signature': u.base64ToArrayBuffer(bundle.signed_prekey.signature)
'keyId': prekey.id,
},
// <Number>
'preKey': {
'publicKey': u.base64ToArrayBuffer(prekey.key)
'keyId': prekey.id,
}
// <Number>
});
'publicKey': u.base64ToArrayBuffer(prekey.key)
}
});
} catch (e) {
_converse.log(`Error: could not build session for device ${device.get('id')}`, Strophe.LogLevel.ERROR);
_converse.log(e.message, Strophe.LogLevel.ERROR);
return Promise.resolve();
}
},
},
getKeyAndTag(string) {
getKeyAndTag(string) {
...
@@ -74447,21 +74463,14 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74447,21 +74463,14 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
_converse.NUM_PREKEYS = 100; // Set here so that tests can override
_converse.NUM_PREKEYS = 100; // Set here so that tests can override
function generateFingerprint(device) {
function generateFingerprint(device) {
return new Promise((resolve, reject) => {
let bundle;
device.getBundle().then(bundle => {
return device.getBundle().then(b => {
if (_.isNil(bundle)) {
bundle = b;
resolve();
return crypto.subtle.digest('SHA-1', u.base64ToArrayBuffer(bundle['identity_key']));
} // TODO: only generate fingerprints when necessary
}).then(fp => {
bundle['fingerprint'] = u.arrayBufferToHex(fp);
device.save('bundle', bundle);
crypto.subtle.digest('SHA-1', u.base64ToArrayBuffer(bundle['identity_key'])).then(fp => {
device.trigger('change:bundle'); // Doesn't get triggered automatically due to pass-by-reference
bundle['fingerprint'] = u.arrayBufferToHex(fp);
device.save('bundle', bundle);
device.trigger('change:bundle'); // Doesn't get triggered automatically due to pass-by-reference
resolve();
}).catch(reject);
});
});
});
}
}
...
@@ -74470,19 +74479,13 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74470,19 +74479,13 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
};
};
_converse.getDevicesForContact = function (jid) {
_converse.getDevicesForContact = function (jid) {
return new Promise((resolve, reject) => {
let devicelist;
_converse.api.waitUntil('OMEMOInitialized').then(() => {
return _converse.api.waitUntil('OMEMOInitialized').then(() => {
let devicelist = _converse.devicelists.get(jid);
devicelist = _converse.devicelists.get(jid) || _converse.devicelists.create({
'jid': jid
if (_.isNil(devicelist)) {
});
devicelist = _converse.devicelists.create({
return devicelist.fetchDevices();
'jid': jid
}).then(() => devicelist.devices);
});
}
devicelist.fetchDevices().then(() => resolve(devicelist.devices));
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
});
};
};
_converse.contactHasOMEMOSupport = function (jid) {
_converse.contactHasOMEMOSupport = function (jid) {
...
@@ -74508,35 +74511,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74508,35 +74511,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
}
}
}
}
return device_id;
return device_id.toString();
}
function generateBundle() {
/* The first thing that needs to happen if a client wants to
* start using OMEMO is they need to generate an IdentityKey
* and a Device ID. The IdentityKey is a Curve25519 [6]
* public/private Key pair. The Device ID is a randomly
* generated integer between 1 and 2^31 - 1.
*/
return new Promise((resolve, reject) => {
libsignal.KeyHelper.generateIdentityKeyPair().then(identity_keypair => {
const data = {
'device_id': generateDeviceID(),
'identity_keypair': identity_keypair,
'prekeys': {}
};
libsignal.KeyHelper.generateSignedPreKey(identity_keypair, 0).then(signed_prekey => {
data['signed_prekey'] = signed_prekey;
const key_promises = _.map(_.range(0, _converse.NUM_PREKEYS), id => libsignal.KeyHelper.generatePreKey(id));
Promise.all(key_promises).then(keys => {
data['prekeys'] = keys;
resolve(data);
});
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
});
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
}
}
_converse.OMEMOStore = Backbone.Model.extend({
_converse.OMEMOStore = Backbone.Model.extend({
...
@@ -74666,11 +74641,39 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74666,11 +74641,39 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
return Promise.resolve();
return Promise.resolve();
},
},
createNewDeviceBundle() {
generateBundle() {
return generateBundle().then(data => {
/* The first thing that needs to happen if a client wants to
// TODO: should storeSession be used here?
* start using OMEMO is they need to generate an IdentityKey
_converse.omemo_store.save(data);
* and a Device ID. The IdentityKey is a Curve25519 [6]
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
* public/private Key pair. The Device ID is a randomly
* generated integer between 1 and 2^31 - 1.
*/
const data = {
'device_id': generateDeviceID()
};
return libsignal.KeyHelper.generateIdentityKeyPair().then(identity_keypair => {
data['identity_keypair'] = identity_keypair;
data['identity_key'] = identity_keypair.pubKey;
return libsignal.KeyHelper.generateSignedPreKey(identity_keypair, 1);
}).then(signed_prekey => {
_converse.omemo_store.storeSignedPreKey(signed_prekey.keyId, signed_prekey.keyPair);
data['signed_prekey'] = signed_prekey;
return Promise.all(_.map(_.range(0, _converse.NUM_PREKEYS), id => libsignal.KeyHelper.generatePreKey(id)));
}).then(keys => {
_.forEach(keys, k => _converse.omemo_store.storePreKey(k.keyId, k.keyPair));
data['prekeys'] = keys;
this.save(data); // Save the bundle to the device
const devicelist = _converse.devicelists.get(_converse.bare_jid),
device = devicelist.devices.create({
'id': data.device_id,
'jid': _converse.bare_jid
});
device.save('bundle', data);
});
},
},
fetchSession() {
fetchSession() {
...
@@ -74679,13 +74682,13 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74679,13 +74682,13 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
this.fetch({
this.fetch({
'success': () => {
'success': () => {
if (!_converse.omemo_store.get('device_id')) {
if (!_converse.omemo_store.get('device_id')) {
this.
createNewDevic
eBundle().then(resolve).catch(resolve);
this.
generat
eBundle().then(resolve).catch(resolve);
} else {
} else {
resolve();
resolve();
}
}
},
},
'error': () => {
'error': () => {
this.
createNewDevic
eBundle().then(resolve).catch(resolve);
this.
generat
eBundle().then(resolve).catch(resolve);
}
}
});
});
});
});
...
@@ -74760,13 +74763,13 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74760,13 +74763,13 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
this.devices.fetch({
this.devices.fetch({
'success': collection => {
'success': collection => {
if (collection.length === 0) {
if (collection.length === 0) {
this.fetchDevicesFromServer().then(
resolve).catch(reject
);
this.fetchDevicesFromServer().then(
ids => this.publishCurrentDevice(ids)).then(resolve).catch(resolve
);
} else {
} else {
resolve();
resolve();
}
}
},
},
'error': () => {
'error': () => {
this.fetchDevicesFromServer().then(
resolve).catch(reject
);
this.fetchDevicesFromServer().then(
ids => this.publishCurrentDevice(ids)).then(resolve).catch(resolve
);
}
}
});
});
});
});
...
@@ -74775,26 +74778,51 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74775,26 +74778,51 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
return this._devices_promise;
return this._devices_promise;
},
},
publishCurrentDevice(device_ids) {
if (this.get('jid') !== _converse.bare_jid) {
// We only publish for ourselves.
return Promise.resolve();
}
return restoreOMEMOSession().then(() => {
const device_id = _converse.omemo_store.get('device_id');
if (!_.includes(device_ids, device_id)) {
return this.publishDevices();
} else {
const own_device = this.devices.findWhere({
'id': device_id
});
if (!own_device.get('active')) {
own_device.set('active', true, {
'silent': true
});
return this.publishDevices();
}
}
});
},
fetchDevicesFromServer() {
fetchDevicesFromServer() {
return new Promise((resolve, reject) => {
const stanza = $iq({
const stanza = $iq({
'type': 'get',
'type': 'get',
'from': _converse.bare_jid,
'from': _converse.bare_jid,
'to': this.get('jid')
'to': this.get('jid')
}).c('pubsub', {
}).c('pubsub', {
'xmlns': Strophe.NS.PUBSUB
'xmlns': Strophe.NS.PUBSUB
}).c('items', {
}).c('items', {
'node': Strophe.NS.OMEMO_DEVICELIST
'node': Strophe.NS.OMEMO_DEVICELIST
});
});
return _converse.api.sendIQ(stanza).then(iq => {
const device_ids = _.map(sizzle(`list[xmlns="${Strophe.NS.OMEMO}"] device`, iq), dev => dev.getAttribute('id'));
_converse.connection.sendIQ(stanza, iq => {
_.forEach(device_ids, id => this.devices.create({
_.forEach(sizzle(`list[xmlns="${Strophe.NS.OMEMO}"] device`, iq), dev => this.devices.create({
'id': id,
'id': dev.getAttribute('id'),
'jid': this.get('jid')
'jid': this.get('jid')
}));
}));
resolve();
return device_ids;
}, reject, _converse.IQ_TIMEOUT);
});
});
},
},
...
@@ -74821,22 +74849,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74821,22 +74849,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
return _converse.api.sendIQ(stanza);
return _converse.api.sendIQ(stanza);
},
},
addOwnDevice(device_id) {
/* Add this device to our list of devices stored on the
* server.
* https://xmpp.org/extensions/xep-0384.html#usecases-announcing
*/
if (this.get('jid') !== _converse.bare_jid) {
throw new Error("Cannot add device to someone else's device list");
}
this.devices.create({
'id': device_id.toString(),
'jid': this.get('jid')
});
return this.publishDevices();
},
removeOwnDevices(device_ids) {
removeOwnDevices(device_ids) {
if (this.get('jid') !== _converse.bare_jid) {
if (this.get('jid') !== _converse.bare_jid) {
throw new Error("Cannot remove devices from someone else's device list");
throw new Error("Cannot remove devices from someone else's device list");
...
@@ -74854,28 +74866,26 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74854,28 +74866,26 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
publishBundle() {
publishBundle() {
const store = _converse.omemo_store,
const store = _converse.omemo_store,
signed_prekey = store.get('signed_prekey');
signed_prekey = store.get('signed_prekey');
return new Promise((resolve, reject) => {
const stanza = $iq({
const stanza = $iq({
'from': _converse.bare_jid,
'from': _converse.bare_jid,
'type': 'set'
'type': 'set'
}).c('pubsub', {
}).c('pubsub', {
'xmlns': Strophe.NS.PUBSUB
'xmlns': Strophe.NS.PUBSUB
}).c('publish', {
}).c('publish', {
'node': `${Strophe.NS.OMEMO_BUNDLES}:${store.get('device_id')}`
'node': `${Strophe.NS.OMEMO_BUNDLES}:${store.get('device_id')}`
}).c('item').c('bundle', {
}).c('item').c('bundle', {
'xmlns': Strophe.NS.OMEMO
'xmlns': Strophe.NS.OMEMO
}).c('signedPreKeyPublic', {
}).c('signedPreKeyPublic', {
'signedPreKeyId': signed_prekey.keyId
'signedPreKeyId': signed_prekey.keyId
}).t(u.arrayBufferToBase64(signed_prekey.keyPair.pubKey)).up().c('signedPreKeySignature').t(u.arrayBufferToBase64(signed_prekey.signature)).up().c('identityKey').t(u.arrayBufferToBase64(store.get('identity_keypair').pubKey)).up().c('prekeys');
}).t(u.arrayBufferToBase64(signed_prekey.keyPair.pubKey)).up().c('signedPreKeySignature').t(u.arrayBufferToBase64(signed_prekey.signature)).up().c('identityKey').t(u.arrayBufferToBase64(store.get('identity_keypair').pubKey)).up().c('prekeys');
_.forEach(store.get('prekeys').slice(0, _converse.NUM_PREKEYS), prekey => {
_.forEach(store.get('prekeys').slice(0, _converse.NUM_PREKEYS), prekey => {
stanza.c('preKeyPublic', {
stanza.c('preKeyPublic', {
'preKeyId': prekey.keyId
'preKeyId': prekey.keyId
}).t(u.arrayBufferToBase64(prekey.keyPair.pubKey)).up();
}).t(u.arrayBufferToBase64(prekey.keyPair.pubKey)).up();
});
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
});
});
return _converse.api.sendIQ(stanza);
}
}
};
};
...
@@ -74901,28 +74911,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74901,28 +74911,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
});
});
}
}
function updateOwnDeviceList() {
/* If our own device is not on the list, add it.
* Also, deduplicate devices if necessary.
*/
const devicelist = _converse.devicelists.get(_converse.bare_jid),
device_id = _converse.omemo_store.get('device_id').toString(),
own_device = devicelist.devices.findWhere({
'id': device_id
});
if (!own_device) {
return devicelist.addOwnDevice(device_id);
} else if (!own_device.get('active')) {
own_device.set('active', true, {
'silent': true
});
return devicelist.addOwnDevice(device_id);
} else {
return Promise.resolve();
}
}
function updateBundleFromStanza(stanza) {
function updateBundleFromStanza(stanza) {
const items_el = sizzle(`items`, stanza).pop();
const items_el = sizzle(`items`, stanza).pop();
...
@@ -74977,19 +74965,25 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -74977,19 +74965,25 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
'jid': jid
'jid': jid
});
});
}
}
}); // Make sure our own device is on the list (i.e. if it was
});
// removed, add it again.
updateOwnDeviceList();
if (Strophe.getBareJidFromJid(jid) === _converse.bare_jid) {
// Make sure our own device is on the list (i.e. if it was
// removed, add it again.
_converse.devicelists.get(_converse.bare_jid).publishCurrentDevice(device_ids);
}
}
}
function registerPEPPushHandler() {
function registerPEPPushHandler() {
// Add a handler for devices pushed from other connected clients
// Add a handler for devices pushed from other connected clients
_converse.connection.addHandler(message => {
_converse.connection.addHandler(message => {
if (message.querySelector('event[xmlns="' + Strophe.NS.PUBSUB + '#event"]')) {
try {
updateDevicesFromStanza(message);
if (sizzle(`event[xmlns="${Strophe.NS.PUBSUB}#event"]`, message).length) {
updateBundleFromStanza(message);
updateDevicesFromStanza(message);
updateBundleFromStanza(message);
}
} catch (e) {
_converse.log(e.message, Strophe.LogLevel.ERROR);
}
}
return true;
return true;
...
@@ -75012,10 +75006,14 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -75012,10 +75006,14 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
const id = `converse.devicelists-${_converse.bare_jid}`;
const id = `converse.devicelists-${_converse.bare_jid}`;
_converse.devicelists.id = id;
_converse.devicelists.id = id;
_converse.devicelists.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
_converse.devicelists.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
fetchOwnDevices().then(() => restoreOMEMOSession()).then(() =>
updateOwnDeviceList()).then(() =>
_converse.omemo.publishBundle()).then(() => _converse.emit('OMEMOInitialized')).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
fetchOwnDevices().then(() => restoreOMEMOSession()).then(() => _converse.omemo.publishBundle()).then(() => _converse.emit('OMEMOInitialized')).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
}
}
_converse.api.listen.on('afterTearDown', () => _converse.devicelists.reset());
_converse.api.listen.on('afterTearDown', () => {
_converse.devicelists.reset();
delete _converse.omemo_store;
});
_converse.api.listen.on('connected', registerPEPPushHandler);
_converse.api.listen.on('connected', registerPEPPushHandler);
...
@@ -75023,7 +75021,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
...
@@ -75023,7 +75021,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
_converse.api.listen.on('statusInitialized', initOMEMO);
_converse.api.listen.on('statusInitialized', initOMEMO);
_converse.api.listen.on('addClientFeatures', () => _converse.api.disco.own.features.add(
Strophe.NS.OMEMO_DEVICELIST + "notify"
));
_converse.api.listen.on('addClientFeatures', () => _converse.api.disco.own.features.add(
`${Strophe.NS.OMEMO_DEVICELIST}+notify`
));
_converse.api.listen.on('userDetailsModalInitialized', contact => {
_converse.api.listen.on('userDetailsModalInitialized', contact => {
const jid = contact.get('jid');
const jid = contact.get('jid');
spec/chatbox.js
View file @
fa0e7aef
...
@@ -621,10 +621,10 @@
...
@@ -621,10 +621,10 @@
expect
(
view
.
model
.
get
(
'
chat_state
'
)).
toBe
(
'
inactive
'
);
expect
(
view
.
model
.
get
(
'
chat_state
'
)).
toBe
(
'
inactive
'
);
spyOn
(
_converse
.
connection
,
'
send
'
);
spyOn
(
_converse
.
connection
,
'
send
'
);
view
.
model
.
maximize
();
view
.
model
.
maximize
();
return
test_utils
.
waitUntil
(()
=>
view
.
model
.
get
(
'
chat_state
'
)
===
'
active
'
,
7
00
);
return
test_utils
.
waitUntil
(()
=>
view
.
model
.
get
(
'
chat_state
'
)
===
'
active
'
,
10
00
);
}).
then
(()
=>
{
}).
then
(()
=>
{
expect
(
_converse
.
connection
.
send
).
toHaveBeenCalled
();
expect
(
_converse
.
connection
.
send
).
toHaveBeenCalled
();
var
calls
=
_
.
filter
(
_converse
.
connection
.
send
.
calls
.
all
(),
function
(
call
)
{
const
calls
=
_
.
filter
(
_converse
.
connection
.
send
.
calls
.
all
(),
function
(
call
)
{
return
call
.
args
[
0
]
instanceof
Strophe
.
Builder
;
return
call
.
args
[
0
]
instanceof
Strophe
.
Builder
;
});
});
expect
(
calls
.
length
).
toBe
(
1
);
expect
(
calls
.
length
).
toBe
(
1
);
...
@@ -635,7 +635,7 @@
...
@@ -635,7 +635,7 @@
expect
(
$stanza
.
children
().
get
(
1
).
tagName
).
toBe
(
'
no-store
'
);
expect
(
$stanza
.
children
().
get
(
1
).
tagName
).
toBe
(
'
no-store
'
);
expect
(
$stanza
.
children
().
get
(
2
).
tagName
).
toBe
(
'
no-permanent-store
'
);
expect
(
$stanza
.
children
().
get
(
2
).
tagName
).
toBe
(
'
no-permanent-store
'
);
done
();
done
();
})
;
})
.
catch
(
_
.
partial
(
_converse
.
log
,
_
,
Strophe
.
LogLevel
.
FATAL
))
}));
}));
});
});
...
...
spec/omemo.js
View file @
fa0e7aef
...
@@ -65,10 +65,41 @@
...
@@ -65,10 +65,41 @@
.
c
(
'
device
'
,
{
'
id
'
:
'
482886413b977930064a5888b92134fe
'
});
.
c
(
'
device
'
,
{
'
id
'
:
'
482886413b977930064a5888b92134fe
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
emit
(
'
OMEMOInitialized
'
);
// Check that own device was published
// Check that device list for contact is fetched when chat is opened.
return
test_utils
.
waitUntil
(()
=>
{
return
test_utils
.
openChatBoxFor
(
_converse
,
contact_jid
);
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
const
node
=
iq
.
nodeTree
.
querySelector
(
'
iq[from="
'
+
_converse
.
bare_jid
+
'
"] publish[node="eu.siacs.conversations.axolotl.devicelist"]
'
);
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
return
node
;
}).
length
;
});
}).
then
(()
=>
{
}).
then
(()
=>
{
const
stanza
=
$iq
({
'
from
'
:
_converse
.
bare_jid
,
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
to
'
:
_converse
.
bare_jid
,
'
type
'
:
'
result
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
function
(
iq
)
{
const
node
=
iq
.
nodeTree
.
querySelector
(
'
publish[node="eu.siacs.conversations.axolotl.bundles:123456789"]
'
);
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;
}
return
node
;
}).
length
;
});
}).
then
(()
=>
{
const
stanza
=
$iq
({
'
from
'
:
_converse
.
bare_jid
,
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
to
'
:
_converse
.
bare_jid
,
'
type
'
:
'
result
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
_converse
.
api
.
waitUntil
(
'
OMEMOInitialized
'
);
}).
then
(()
=>
test_utils
.
openChatBoxFor
(
_converse
,
contact_jid
))
.
then
(()
=>
{
return
test_utils
.
waitUntil
(()
=>
{
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
_converse
.
connection
.
IQ_stanzas
,
...
@@ -90,7 +121,8 @@
...
@@ -90,7 +121,8 @@
.
c
(
'
list
'
,
{
'
xmlns
'
:
"
eu.siacs.conversations.axolotl
"
})
.
c
(
'
list
'
,
{
'
xmlns
'
:
"
eu.siacs.conversations.axolotl
"
})
.
c
(
'
device
'
,
{
'
id
'
:
'
555
'
});
.
c
(
'
device
'
,
{
'
id
'
:
'
555
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
test_utils
.
waitUntil
(()
=>
_converse
.
omemo_store
);
}).
then
(()
=>
{
const
devicelist
=
_converse
.
devicelists
.
get
({
'
jid
'
:
contact_jid
});
const
devicelist
=
_converse
.
devicelists
.
get
({
'
jid
'
:
contact_jid
});
expect
(
devicelist
.
devices
.
length
).
toBe
(
1
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
1
);
...
@@ -233,7 +265,8 @@
...
@@ -233,7 +265,8 @@
test_utils
.
createContacts
(
_converse
,
'
current
'
,
1
);
test_utils
.
createContacts
(
_converse
,
'
current
'
,
1
);
const
contact_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
const
contact_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
test_utils
.
waitUntil
(
function
()
{
// Wait until own devices are fetched
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
(
iq
)
=>
{
...
@@ -241,7 +274,7 @@
...
@@ -241,7 +274,7 @@
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
return
node
;
return
node
;
}).
length
;
}).
length
;
}).
then
(
function
()
{
}).
then
(
()
=>
{
expect
(
iq_stanza
.
outerHTML
).
toBe
(
expect
(
iq_stanza
.
outerHTML
).
toBe
(
'
<iq type="get" from="dummy@localhost" to="dummy@localhost" xmlns="jabber:client" id="
'
+
iq_stanza
.
getAttribute
(
"
id
"
)
+
'
">
'
+
'
<iq type="get" from="dummy@localhost" to="dummy@localhost" xmlns="jabber:client" id="
'
+
iq_stanza
.
getAttribute
(
"
id
"
)
+
'
">
'
+
'
<pubsub xmlns="http://jabber.org/protocol/pubsub">
'
+
'
<pubsub xmlns="http://jabber.org/protocol/pubsub">
'
+
...
@@ -259,16 +292,48 @@
...
@@ -259,16 +292,48 @@
.
c
(
'
list
'
,
{
'
xmlns
'
:
"
eu.siacs.conversations.axolotl
"
})
.
c
(
'
list
'
,
{
'
xmlns
'
:
"
eu.siacs.conversations.axolotl
"
})
.
c
(
'
device
'
,
{
'
id
'
:
'
555
'
});
.
c
(
'
device
'
,
{
'
id
'
:
'
555
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
test_utils
.
waitUntil
(()
=>
_converse
.
omemo_store
);
}).
then
(()
=>
{
expect
(
_converse
.
devicelists
.
length
).
toBe
(
1
);
expect
(
_converse
.
devicelists
.
length
).
toBe
(
1
);
const
devicelist
=
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
);
const
devicelist
=
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
1
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
2
);
expect
(
devicelist
.
devices
.
at
(
0
).
get
(
'
id
'
)).
toBe
(
'
555
'
);
expect
(
devicelist
.
devices
.
at
(
0
).
get
(
'
id
'
)).
toBe
(
'
555
'
);
return
test_utils
.
waitUntil
(()
=>
_converse
.
devicelists
);
expect
(
devicelist
.
devices
.
at
(
1
).
get
(
'
id
'
)).
toBe
(
'
123456789
'
);
}).
then
(
function
()
{
// We simply emit, to avoid doing all the setup work
_converse
.
emit
(
'
OMEMOInitialized
'
);
// Check that own device was published
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
const
node
=
iq
.
nodeTree
.
querySelector
(
'
iq[from="
'
+
_converse
.
bare_jid
+
'
"] publish[node="eu.siacs.conversations.axolotl.devicelist"]
'
);
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
return
node
;
}).
length
;
});
}).
then
(()
=>
{
const
stanza
=
$iq
({
'
from
'
:
_converse
.
bare_jid
,
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
to
'
:
_converse
.
bare_jid
,
'
type
'
:
'
result
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
function
(
iq
)
{
const
node
=
iq
.
nodeTree
.
querySelector
(
'
publish[node="eu.siacs.conversations.axolotl.bundles:123456789"]
'
);
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;
}
return
node
;
}).
length
;
});
}).
then
(()
=>
{
const
stanza
=
$iq
({
'
from
'
:
_converse
.
bare_jid
,
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
to
'
:
_converse
.
bare_jid
,
'
type
'
:
'
result
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
_converse
.
api
.
waitUntil
(
'
OMEMOInitialized
'
);
}).
then
(()
=>
{
let
stanza
=
$msg
({
let
stanza
=
$msg
({
'
from
'
:
contact_jid
,
'
from
'
:
contact_jid
,
'
to
'
:
_converse
.
bare_jid
,
'
to
'
:
_converse
.
bare_jid
,
...
@@ -319,6 +384,7 @@
...
@@ -319,6 +384,7 @@
.
c
(
'
items
'
,
{
'
node
'
:
'
eu.siacs.conversations.axolotl.devicelist
'
})
.
c
(
'
items
'
,
{
'
node
'
:
'
eu.siacs.conversations.axolotl.devicelist
'
})
.
c
(
'
item
'
)
.
c
(
'
item
'
)
.
c
(
'
list
'
,
{
'
xmlns
'
:
'
eu.siacs.conversations.axolotl
'
})
.
c
(
'
list
'
,
{
'
xmlns
'
:
'
eu.siacs.conversations.axolotl
'
})
.
c
(
'
device
'
,
{
'
id
'
:
'
123456789
'
})
.
c
(
'
device
'
,
{
'
id
'
:
'
555
'
})
.
c
(
'
device
'
,
{
'
id
'
:
'
555
'
})
.
c
(
'
device
'
,
{
'
id
'
:
'
777
'
})
.
c
(
'
device
'
,
{
'
id
'
:
'
777
'
})
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
...
@@ -346,7 +412,8 @@
...
@@ -346,7 +412,8 @@
.
c
(
'
device
'
,
{
'
id
'
:
'
444
'
})
.
c
(
'
device
'
,
{
'
id
'
:
'
444
'
})
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
test_utils
.
waitUntil
(
function
()
{
// Check that own device was published
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
(
iq
)
=>
{
...
@@ -355,7 +422,7 @@
...
@@ -355,7 +422,7 @@
return
node
;
return
node
;
}).
length
;
}).
length
;
});
});
}).
then
(
function
()
{
}).
then
(
()
=>
{
// Check that our own device is added again, but that removed
// Check that our own device is added again, but that removed
// devices are not added.
// devices are not added.
expect
(
iq_stanza
.
outerHTML
).
toBe
(
expect
(
iq_stanza
.
outerHTML
).
toBe
(
...
@@ -394,7 +461,7 @@
...
@@ -394,7 +461,7 @@
test_utils
.
createContacts
(
_converse
,
'
current
'
);
test_utils
.
createContacts
(
_converse
,
'
current
'
);
const
contact_jid
=
mock
.
cur_names
[
3
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
const
contact_jid
=
mock
.
cur_names
[
3
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
test_utils
.
waitUntil
(
function
()
{
test_utils
.
waitUntil
(
()
=>
{
return
_
.
filter
(
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
(
iq
)
=>
{
...
@@ -402,7 +469,7 @@
...
@@ -402,7 +469,7 @@
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
return
node
;
return
node
;
}).
length
;
}).
length
;
}).
then
(
function
()
{
}).
then
(
()
=>
{
expect
(
iq_stanza
.
outerHTML
).
toBe
(
expect
(
iq_stanza
.
outerHTML
).
toBe
(
'
<iq type="get" from="dummy@localhost" to="dummy@localhost" xmlns="jabber:client" id="
'
+
iq_stanza
.
getAttribute
(
"
id
"
)
+
'
">
'
+
'
<iq type="get" from="dummy@localhost" to="dummy@localhost" xmlns="jabber:client" id="
'
+
iq_stanza
.
getAttribute
(
"
id
"
)
+
'
">
'
+
'
<pubsub xmlns="http://jabber.org/protocol/pubsub">
'
+
'
<pubsub xmlns="http://jabber.org/protocol/pubsub">
'
+
...
@@ -421,18 +488,49 @@
...
@@ -421,18 +488,49 @@
.
c
(
'
list
'
,
{
'
xmlns
'
:
"
eu.siacs.conversations.axolotl
"
})
.
c
(
'
list
'
,
{
'
xmlns
'
:
"
eu.siacs.conversations.axolotl
"
})
.
c
(
'
device
'
,
{
'
id
'
:
'
555
'
});
.
c
(
'
device
'
,
{
'
id
'
:
'
555
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
test_utils
.
waitUntil
(()
=>
_converse
.
omemo_store
);
expect
(
_converse
.
devicelists
.
length
).
toBe
(
1
);
return
test_utils
.
waitUntil
(()
=>
_converse
.
devicelists
);
}).
then
(
function
()
{
}).
then
(
function
()
{
// We simply emit, to avoid doing all the setup work
// We simply emit, to avoid doing all the setup work
expect
(
_converse
.
devicelists
.
length
).
toBe
(
1
);
expect
(
_converse
.
devicelists
.
length
).
toBe
(
1
);
le
t
devicelist
=
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
);
cons
t
devicelist
=
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
2
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
2
);
expect
(
devicelist
.
devices
.
at
(
0
).
get
(
'
id
'
)).
toBe
(
'
555
'
);
expect
(
devicelist
.
devices
.
at
(
0
).
get
(
'
id
'
)).
toBe
(
'
555
'
);
expect
(
devicelist
.
devices
.
at
(
1
).
get
(
'
id
'
)).
toBe
(
'
123456789
'
);
expect
(
devicelist
.
devices
.
at
(
1
).
get
(
'
id
'
)).
toBe
(
'
123456789
'
);
_converse
.
emit
(
'
OMEMOInitialized
'
);
// Check that own device was published
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
const
node
=
iq
.
nodeTree
.
querySelector
(
'
iq[from="
'
+
_converse
.
bare_jid
+
'
"] publish[node="eu.siacs.conversations.axolotl.devicelist"]
'
);
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
return
node
;
}).
length
;
});
}).
then
(()
=>
{
const
stanza
=
$iq
({
'
from
'
:
_converse
.
bare_jid
,
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
to
'
:
_converse
.
bare_jid
,
'
type
'
:
'
result
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
// Check that own bundle gets published
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
const
node
=
iq
.
nodeTree
.
querySelector
(
'
publish[node="eu.siacs.conversations.axolotl.bundles:123456789"]
'
);
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;
}
return
node
;
}).
length
;
});
}).
then
(()
=>
{
const
stanza
=
$iq
({
'
from
'
:
_converse
.
bare_jid
,
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
to
'
:
_converse
.
bare_jid
,
'
type
'
:
'
result
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
_converse
.
api
.
waitUntil
(
'
OMEMOInitialized
'
);
}).
then
(()
=>
{
let
stanza
=
$msg
({
let
stanza
=
$msg
({
'
from
'
:
contact_jid
,
'
from
'
:
contact_jid
,
'
to
'
:
_converse
.
bare_jid
,
'
to
'
:
_converse
.
bare_jid
,
...
@@ -452,7 +550,7 @@
...
@@ -452,7 +550,7 @@
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
expect
(
_converse
.
devicelists
.
length
).
toBe
(
2
);
expect
(
_converse
.
devicelists
.
length
).
toBe
(
2
);
devicelist
=
_converse
.
devicelists
.
get
(
contact_jid
);
let
devicelist
=
_converse
.
devicelists
.
get
(
contact_jid
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
1
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
1
);
let
device
=
devicelist
.
devices
.
at
(
0
);
let
device
=
devicelist
.
devices
.
at
(
0
);
expect
(
device
.
get
(
'
bundle
'
).
identity_key
).
toBe
(
'
3333
'
);
expect
(
device
.
get
(
'
bundle
'
).
identity_key
).
toBe
(
'
3333
'
);
...
@@ -543,7 +641,7 @@
...
@@ -543,7 +641,7 @@
_converse
.
emit
(
'
rosterContactsFetched
'
);
_converse
.
emit
(
'
rosterContactsFetched
'
);
const
contact_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
const
contact_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
test_utils
.
waitUntil
(
function
()
{
test_utils
.
waitUntil
(
()
=>
{
return
_
.
filter
(
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
(
iq
)
=>
{
...
@@ -551,7 +649,7 @@
...
@@ -551,7 +649,7 @@
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
return
node
;
return
node
;
}).
length
;
}).
length
;
}).
then
(
function
()
{
}).
then
(
()
=>
{
const
stanza
=
$iq
({
const
stanza
=
$iq
({
'
from
'
:
contact_jid
,
'
from
'
:
contact_jid
,
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
...
@@ -589,14 +687,14 @@
...
@@ -589,14 +687,14 @@
return
node
;
return
node
;
}).
length
;
}).
length
;
});
});
}).
then
(
function
()
{
}).
then
(
()
=>
{
expect
(
iq_stanza
.
outerHTML
).
toBe
(
expect
(
iq_stanza
.
outerHTML
).
toBe
(
`<iq from="dummy@localhost" type="set" xmlns="jabber:client" id="
${
iq_stanza
.
getAttribute
(
'
id
'
)}
">`
+
`<iq from="dummy@localhost" type="set" xmlns="jabber:client" id="
${
iq_stanza
.
getAttribute
(
'
id
'
)}
">`
+
`<pubsub xmlns="http://jabber.org/protocol/pubsub">`
+
`<pubsub xmlns="http://jabber.org/protocol/pubsub">`
+
`<publish node="eu.siacs.conversations.axolotl.bundles:123456789">`
+
`<publish node="eu.siacs.conversations.axolotl.bundles:123456789">`
+
`<item>`
+
`<item>`
+
`<bundle xmlns="eu.siacs.conversations.axolotl">`
+
`<bundle xmlns="eu.siacs.conversations.axolotl">`
+
`<signedPreKeyPublic signedPreKeyId="
0
">
${
btoa
(
'
1234
'
)}
</signedPreKeyPublic>`
+
`<signedPreKeyPublic signedPreKeyId="
1
">
${
btoa
(
'
1234
'
)}
</signedPreKeyPublic>`
+
`<signedPreKeySignature>
${
btoa
(
'
11112222333344445555
'
)}
</signedPreKeySignature>`
+
`<signedPreKeySignature>
${
btoa
(
'
11112222333344445555
'
)}
</signedPreKeySignature>`
+
`<identityKey>
${
btoa
(
'
1234
'
)}
</identityKey>`
+
`<identityKey>
${
btoa
(
'
1234
'
)}
</identityKey>`
+
`<prekeys>`
+
`<prekeys>`
+
...
@@ -646,7 +744,7 @@
...
@@ -646,7 +744,7 @@
'
</iq>
'
);
'
</iq>
'
);
const
stanza
=
$iq
({
const
stanza
=
$iq
({
'
from
'
:
contact
_jid
,
'
from
'
:
_converse
.
bare
_jid
,
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
id
'
:
iq_stanza
.
getAttribute
(
'
id
'
),
'
to
'
:
_converse
.
bare_jid
,
'
to
'
:
_converse
.
bare_jid
,
'
type
'
:
'
result
'
,
'
type
'
:
'
result
'
,
...
@@ -656,20 +754,22 @@
...
@@ -656,20 +754,22 @@
.
c
(
'
list
'
,
{
'
xmlns
'
:
"
eu.siacs.conversations.axolotl
"
})
.
c
(
'
list
'
,
{
'
xmlns
'
:
"
eu.siacs.conversations.axolotl
"
})
.
c
(
'
device
'
,
{
'
id
'
:
'
482886413b977930064a5888b92134fe
'
});
.
c
(
'
device
'
,
{
'
id
'
:
'
482886413b977930064a5888b92134fe
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
test_utils
.
waitUntil
(()
=>
_converse
.
omemo_store
);
}).
then
(()
=>
{
expect
(
_converse
.
devicelists
.
length
).
toBe
(
1
);
expect
(
_converse
.
devicelists
.
length
).
toBe
(
1
);
const
devicelist
=
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
);
const
devicelist
=
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
1
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
2
);
expect
(
devicelist
.
devices
.
at
(
0
).
get
(
'
id
'
)).
toBe
(
'
482886413b977930064a5888b92134fe
'
);
expect
(
devicelist
.
devices
.
at
(
0
).
get
(
'
id
'
)).
toBe
(
'
482886413b977930064a5888b92134fe
'
);
expect
(
devicelist
.
devices
.
at
(
1
).
get
(
'
id
'
)).
toBe
(
'
123456789
'
);
return
test_utils
.
openChatBoxFor
(
_converse
,
contact_jid
);
// Check that own device was published
}).
then
(()
=>
{
return
test_utils
.
waitUntil
(()
=>
{
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
function
(
iq
)
{
return
_
.
filter
(
const
node
=
iq
.
nodeTree
.
querySelector
(
'
publish[node="eu.siacs.conversations.axolotl.devicelist"]
'
);
_converse
.
connection
.
IQ_stanzas
,
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;
}
(
iq
)
=>
{
return
node
;
const
node
=
iq
.
nodeTree
.
querySelector
(
'
iq[from="
'
+
_converse
.
bare_jid
+
'
"] publish[node="eu.siacs.conversations.axolotl.devicelist"]
'
);
}).
length
;
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;}
return
node
;
}).
length
;
});
});
}).
then
(()
=>
{
}).
then
(()
=>
{
expect
(
iq_stanza
.
outerHTML
).
toBe
(
expect
(
iq_stanza
.
outerHTML
).
toBe
(
...
@@ -693,8 +793,9 @@
...
@@ -693,8 +793,9 @@
'
type
'
:
'
result
'
});
'
type
'
:
'
result
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
// Check that own bundle gets published
return
test_utils
.
waitUntil
(()
=>
{
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
function
(
iq
)
{
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
(
iq
)
=>
{
const
node
=
iq
.
nodeTree
.
querySelector
(
'
publish[node="eu.siacs.conversations.axolotl.bundles:123456789"]
'
);
const
node
=
iq
.
nodeTree
.
querySelector
(
'
publish[node="eu.siacs.conversations.axolotl.bundles:123456789"]
'
);
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;
}
if
(
node
)
{
iq_stanza
=
iq
.
nodeTree
;
}
return
node
;
return
node
;
...
@@ -707,7 +808,7 @@
...
@@ -707,7 +808,7 @@
const
signed_prekeys
=
iq_stanza
.
querySelectorAll
(
'
signedPreKeyPublic
'
);
const
signed_prekeys
=
iq_stanza
.
querySelectorAll
(
'
signedPreKeyPublic
'
);
expect
(
signed_prekeys
.
length
).
toBe
(
1
);
expect
(
signed_prekeys
.
length
).
toBe
(
1
);
const
signed_prekey
=
signed_prekeys
[
0
];
const
signed_prekey
=
signed_prekeys
[
0
];
expect
(
signed_prekey
.
getAttribute
(
'
signedPreKeyId
'
)).
toBe
(
'
0
'
)
expect
(
signed_prekey
.
getAttribute
(
'
signedPreKeyId
'
)).
toBe
(
'
1
'
)
expect
(
iq_stanza
.
querySelectorAll
(
'
signedPreKeySignature
'
).
length
).
toBe
(
1
);
expect
(
iq_stanza
.
querySelectorAll
(
'
signedPreKeySignature
'
).
length
).
toBe
(
1
);
expect
(
iq_stanza
.
querySelectorAll
(
'
identityKey
'
).
length
).
toBe
(
1
);
expect
(
iq_stanza
.
querySelectorAll
(
'
identityKey
'
).
length
).
toBe
(
1
);
...
@@ -717,7 +818,10 @@
...
@@ -717,7 +818,10 @@
'
to
'
:
_converse
.
bare_jid
,
'
to
'
:
_converse
.
bare_jid
,
'
type
'
:
'
result
'
});
'
type
'
:
'
result
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
return
_converse
.
api
.
waitUntil
(
'
OMEMOInitialized
'
,
1000
);
}).
then
(()
=>
{
return
test_utils
.
openChatBoxFor
(
_converse
,
contact_jid
);
}).
then
(()
=>
{
return
test_utils
.
waitUntil
(()
=>
{
return
test_utils
.
waitUntil
(()
=>
{
return
_
.
filter
(
return
_
.
filter
(
_converse
.
connection
.
IQ_stanzas
,
_converse
.
connection
.
IQ_stanzas
,
...
@@ -748,7 +852,9 @@
...
@@ -748,7 +852,9 @@
.
c
(
'
device
'
,
{
'
id
'
:
'
4e30f35051b7b8b42abe083742187228
'
}).
up
()
.
c
(
'
device
'
,
{
'
id
'
:
'
4e30f35051b7b8b42abe083742187228
'
}).
up
()
.
c
(
'
device
'
,
{
'
id
'
:
'
ae890ac52d0df67ed7cfdf51b644e901
'
});
.
c
(
'
device
'
,
{
'
id
'
:
'
ae890ac52d0df67ed7cfdf51b644e901
'
});
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
const
devicelist
=
_converse
.
devicelists
.
get
(
contact_jid
);
return
test_utils
.
waitUntil
(()
=>
devicelist
.
devices
.
length
);
}).
then
(()
=>
{
expect
(
_converse
.
devicelists
.
length
).
toBe
(
2
);
expect
(
_converse
.
devicelists
.
length
).
toBe
(
2
);
const
devicelist
=
_converse
.
devicelists
.
get
(
contact_jid
);
const
devicelist
=
_converse
.
devicelists
.
get
(
contact_jid
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
4
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
4
);
...
...
spec/presence.js
View file @
fa0e7aef
...
@@ -47,7 +47,7 @@
...
@@ -47,7 +47,7 @@
"
<presence xmlns='jabber:client'>
"
+
"
<presence xmlns='jabber:client'>
"
+
"
<status>Hello world</status>
"
+
"
<status>Hello world</status>
"
+
"
<priority>0</priority>
"
+
"
<priority>0</priority>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
nE765l4CRVrSUEIPAdtgCw4+5cc
='/>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
ggltNSI5YG/7dFKB57Bk2dRYRU0
='/>
"
+
"
</presence>
"
"
</presence>
"
);
);
_converse
.
priority
=
2
;
_converse
.
priority
=
2
;
...
@@ -57,7 +57,7 @@
...
@@ -57,7 +57,7 @@
"
<show>away</show>
"
+
"
<show>away</show>
"
+
"
<status>Going jogging</status>
"
+
"
<status>Going jogging</status>
"
+
"
<priority>2</priority>
"
+
"
<priority>2</priority>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
nE765l4CRVrSUEIPAdtgCw4+5cc
='/>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
ggltNSI5YG/7dFKB57Bk2dRYRU0
='/>
"
+
"
</presence>
"
"
</presence>
"
);
);
...
@@ -68,7 +68,7 @@
...
@@ -68,7 +68,7 @@
"
<show>dnd</show>
"
+
"
<show>dnd</show>
"
+
"
<status>Doing taxes</status>
"
+
"
<status>Doing taxes</status>
"
+
"
<priority>0</priority>
"
+
"
<priority>0</priority>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
nE765l4CRVrSUEIPAdtgCw4+5cc
='/>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
ggltNSI5YG/7dFKB57Bk2dRYRU0
='/>
"
+
"
</presence>
"
"
</presence>
"
);
);
}));
}));
...
@@ -97,7 +97,7 @@
...
@@ -97,7 +97,7 @@
.
toBe
(
"
<presence xmlns='jabber:client'>
"
+
.
toBe
(
"
<presence xmlns='jabber:client'>
"
+
"
<status>My custom status</status>
"
+
"
<status>My custom status</status>
"
+
"
<priority>0</priority>
"
+
"
<priority>0</priority>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
nE765l4CRVrSUEIPAdtgCw4+5cc
='/>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
ggltNSI5YG/7dFKB57Bk2dRYRU0
='/>
"
+
"
</presence>
"
)
"
</presence>
"
)
return
test_utils
.
waitUntil
(
function
()
{
return
test_utils
.
waitUntil
(
function
()
{
...
@@ -113,7 +113,7 @@
...
@@ -113,7 +113,7 @@
modal
.
el
.
querySelector
(
'
[type="submit"]
'
).
click
();
modal
.
el
.
querySelector
(
'
[type="submit"]
'
).
click
();
expect
(
_converse
.
connection
.
send
.
calls
.
mostRecent
().
args
[
0
].
toLocaleString
())
expect
(
_converse
.
connection
.
send
.
calls
.
mostRecent
().
args
[
0
].
toLocaleString
())
.
toBe
(
"
<presence xmlns='jabber:client'><show>dnd</show><status>My custom status</status><priority>0</priority>
"
+
.
toBe
(
"
<presence xmlns='jabber:client'><show>dnd</show><status>My custom status</status><priority>0</priority>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
nE765l4CRVrSUEIPAdtgCw4+5cc
='/>
"
+
"
<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='
ggltNSI5YG/7dFKB57Bk2dRYRU0
='/>
"
+
"
</presence>
"
)
"
</presence>
"
)
done
();
done
();
});
});
...
...
src/converse-omemo.js
View file @
fa0e7aef
...
@@ -177,7 +177,7 @@
...
@@ -177,7 +177,7 @@
try
{
try
{
return
sessionBuilder
.
processPreKey
({
return
sessionBuilder
.
processPreKey
({
'
registrationId
'
:
parseInt
(
_converse
.
omemo_store
.
get
(
'
device_id
'
),
10
),
'
registrationId
'
:
parseInt
(
_converse
.
omemo_store
.
get
(
'
device_id
'
),
10
),
'
identityKey
'
:
_converse
.
omemo_store
.
get
(
'
identity_key
pair
'
).
pubKey
,
'
identityKey
'
:
_converse
.
omemo_store
.
get
(
'
identity_key
'
)
,
'
signedPreKey
'
:
{
'
signedPreKey
'
:
{
'
keyId
'
:
bundle
.
signed_prekey
.
id
,
// <Number>
'
keyId
'
:
bundle
.
signed_prekey
.
id
,
// <Number>
'
publicKey
'
:
u
.
base64ToArrayBuffer
(
bundle
.
signed_prekey
.
public_key
),
'
publicKey
'
:
u
.
base64ToArrayBuffer
(
bundle
.
signed_prekey
.
public_key
),
...
@@ -478,16 +478,12 @@
...
@@ -478,16 +478,12 @@
}
}
_converse
.
getDevicesForContact
=
function
(
jid
)
{
_converse
.
getDevicesForContact
=
function
(
jid
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
let
devicelist
;
_converse
.
api
.
waitUntil
(
'
OMEMOInitialized
'
).
then
(()
=>
{
return
_converse
.
api
.
waitUntil
(
'
OMEMOInitialized
'
)
let
devicelist
=
_converse
.
devicelists
.
get
(
jid
);
.
then
(()
=>
{
if
(
_
.
isNil
(
devicelist
))
{
devicelist
=
_converse
.
devicelists
.
get
(
jid
)
||
_converse
.
devicelists
.
create
({
'
jid
'
:
jid
});
devicelist
=
_converse
.
devicelists
.
create
({
'
jid
'
:
jid
});
return
devicelist
.
fetchDevices
();
}
}).
then
(()
=>
devicelist
.
devices
);
devicelist
.
fetchDevices
().
then
(()
=>
resolve
(
devicelist
.
devices
));
}).
catch
(
_
.
partial
(
_converse
.
log
,
_
,
Strophe
.
LogLevel
.
ERROR
));
});
}
}
_converse
.
contactHasOMEMOSupport
=
function
(
jid
)
{
_converse
.
contactHasOMEMOSupport
=
function
(
jid
)
{
...
@@ -516,36 +512,6 @@
...
@@ -516,36 +512,6 @@
}
}
function
generateBundle
()
{
/* The first thing that needs to happen if a client wants to
* start using OMEMO is they need to generate an IdentityKey
* and a Device ID. The IdentityKey is a Curve25519 [6]
* public/private Key pair. The Device ID is a randomly
* generated integer between 1 and 2^31 - 1.
*/
return
new
Promise
((
resolve
,
reject
)
=>
{
libsignal
.
KeyHelper
.
generateIdentityKeyPair
().
then
((
identity_keypair
)
=>
{
const
data
=
{
'
device_id
'
:
generateDeviceID
(),
'
identity_keypair
'
:
identity_keypair
,
'
prekeys
'
:
{}
};
libsignal
.
KeyHelper
.
generateSignedPreKey
(
identity_keypair
,
1
)
.
then
((
signed_prekey
)
=>
{
_converse
.
omemo_store
.
storeSignedPreKey
(
signed_prekey
.
keyId
,
signed_prekey
.
keyPair
);
data
[
'
signed_prekey
'
]
=
signed_prekey
;
const
key_promises
=
_
.
map
(
_
.
range
(
0
,
_converse
.
NUM_PREKEYS
),
id
=>
libsignal
.
KeyHelper
.
generatePreKey
(
id
));
Promise
.
all
(
key_promises
).
then
(
keys
=>
{
_
.
forEach
(
keys
,
k
=>
_converse
.
omemo_store
.
storePreKey
(
k
.
keyId
,
k
.
keyPair
));
data
[
'
prekeys
'
]
=
keys
;
resolve
(
data
)
});
}).
catch
(
_
.
partial
(
_converse
.
log
,
_
,
Strophe
.
LogLevel
.
ERROR
));
});
}).
catch
(
_
.
partial
(
_converse
.
log
,
_
,
Strophe
.
LogLevel
.
ERROR
));
}
_converse
.
OMEMOStore
=
Backbone
.
Model
.
extend
({
_converse
.
OMEMOStore
=
Backbone
.
Model
.
extend
({
Direction
:
{
Direction
:
{
...
@@ -652,19 +618,49 @@
...
@@ -652,19 +618,49 @@
return
Promise
.
resolve
();
return
Promise
.
resolve
();
},
},
generateBundle
()
{
/* The first thing that needs to happen if a client wants to
* start using OMEMO is they need to generate an IdentityKey
* and a Device ID. The IdentityKey is a Curve25519 [6]
* public/private Key pair. The Device ID is a randomly
* generated integer between 1 and 2^31 - 1.
*/
const
data
=
{
'
device_id
'
:
generateDeviceID
()
};
return
libsignal
.
KeyHelper
.
generateIdentityKeyPair
()
.
then
(
identity_keypair
=>
{
data
[
'
identity_keypair
'
]
=
identity_keypair
;
data
[
'
identity_key
'
]
=
identity_keypair
.
pubKey
;
return
libsignal
.
KeyHelper
.
generateSignedPreKey
(
identity_keypair
,
1
);
}).
then
(
signed_prekey
=>
{
_converse
.
omemo_store
.
storeSignedPreKey
(
signed_prekey
.
keyId
,
signed_prekey
.
keyPair
);
data
[
'
signed_prekey
'
]
=
signed_prekey
;
return
Promise
.
all
(
_
.
map
(
_
.
range
(
0
,
_converse
.
NUM_PREKEYS
),
id
=>
libsignal
.
KeyHelper
.
generatePreKey
(
id
)));
}).
then
(
keys
=>
{
_
.
forEach
(
keys
,
k
=>
_converse
.
omemo_store
.
storePreKey
(
k
.
keyId
,
k
.
keyPair
));
data
[
'
prekeys
'
]
=
keys
;
this
.
save
(
data
)
// Save the bundle to the device
const
devicelist
=
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
),
device
=
devicelist
.
devices
.
create
({
'
id
'
:
data
.
device_id
,
'
jid
'
:
_converse
.
bare_jid
});
device
.
save
(
'
bundle
'
,
data
);
});
},
fetchSession
()
{
fetchSession
()
{
if
(
_
.
isUndefined
(
this
.
_setup_promise
))
{
if
(
_
.
isUndefined
(
this
.
_setup_promise
))
{
this
.
_setup_promise
=
new
Promise
((
resolve
,
reject
)
=>
{
this
.
_setup_promise
=
new
Promise
((
resolve
,
reject
)
=>
{
this
.
fetch
({
this
.
fetch
({
'
success
'
:
()
=>
{
'
success
'
:
()
=>
{
if
(
!
_converse
.
omemo_store
.
get
(
'
device_id
'
))
{
if
(
!
_converse
.
omemo_store
.
get
(
'
device_id
'
))
{
generateBundle
().
then
(
data
=>
resolve
(
this
.
save
(
data
))
).
catch
(
resolve
);
this
.
generateBundle
().
then
(
resolve
).
catch
(
resolve
);
}
else
{
}
else
{
resolve
();
resolve
();
}
}
},
},
'
error
'
:
()
=>
{
'
error
'
:
()
=>
{
generateBundle
().
then
(
data
=>
resolve
(
this
.
save
(
data
))
).
catch
(
resolve
);
this
.
generateBundle
().
then
(
resolve
).
catch
(
resolve
);
}
}
});
});
});
});
...
@@ -738,13 +734,19 @@
...
@@ -738,13 +734,19 @@
this
.
devices
.
fetch
({
this
.
devices
.
fetch
({
'
success
'
:
(
collection
)
=>
{
'
success
'
:
(
collection
)
=>
{
if
(
collection
.
length
===
0
)
{
if
(
collection
.
length
===
0
)
{
this
.
fetchDevicesFromServer
().
then
(
resolve
).
catch
(
reject
);
this
.
fetchDevicesFromServer
()
.
then
(
ids
=>
this
.
publishCurrentDevice
(
ids
))
.
then
(
resolve
)
.
catch
(
resolve
);
}
else
{
}
else
{
resolve
();
resolve
();
}
}
},
},
'
error
'
:
()
=>
{
'
error
'
:
()
=>
{
this
.
fetchDevicesFromServer
().
then
(
resolve
).
catch
(
reject
);
this
.
fetchDevicesFromServer
()
.
then
(
ids
=>
this
.
publishCurrentDevice
(
ids
))
.
then
(
resolve
)
.
catch
(
resolve
)
}
}
});
});
});
});
...
@@ -752,26 +754,39 @@
...
@@ -752,26 +754,39 @@
return
this
.
_devices_promise
;
return
this
.
_devices_promise
;
},
},
publishCurrentDevice
(
device_ids
)
{
if
(
this
.
get
(
'
jid
'
)
!==
_converse
.
bare_jid
)
{
// We only publish for ourselves.
return
Promise
.
resolve
();
}
return
restoreOMEMOSession
()
.
then
(()
=>
{
const
device_id
=
_converse
.
omemo_store
.
get
(
'
device_id
'
);
if
(
!
_
.
includes
(
device_ids
,
device_id
))
{
return
this
.
publishDevices
();
}
else
{
const
own_device
=
this
.
devices
.
findWhere
({
'
id
'
:
device_id
})
if
(
!
own_device
.
get
(
'
active
'
))
{
own_device
.
set
(
'
active
'
,
true
,
{
'
silent
'
:
true
});
return
this
.
publishDevices
();
}
}
});
},
fetchDevicesFromServer
()
{
fetchDevicesFromServer
()
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
stanza
=
$iq
({
const
stanza
=
$iq
({
'
type
'
:
'
get
'
,
'
type
'
:
'
get
'
,
'
from
'
:
_converse
.
bare_jid
,
'
from
'
:
_converse
.
bare_jid
,
'
to
'
:
this
.
get
(
'
jid
'
)
'
to
'
:
this
.
get
(
'
jid
'
)
}).
c
(
'
pubsub
'
,
{
'
xmlns
'
:
Strophe
.
NS
.
PUBSUB
})
}).
c
(
'
pubsub
'
,
{
'
xmlns
'
:
Strophe
.
NS
.
PUBSUB
})
.
c
(
'
items
'
,
{
'
node
'
:
Strophe
.
NS
.
OMEMO_DEVICELIST
});
.
c
(
'
items
'
,
{
'
node
'
:
Strophe
.
NS
.
OMEMO_DEVICELIST
});
return
_converse
.
api
.
sendIQ
(
stanza
)
_converse
.
connection
.
sendIQ
(
.
then
(
iq
=>
{
stanza
,
const
device_ids
=
_
.
map
(
sizzle
(
`list[xmlns="
${
Strophe
.
NS
.
OMEMO
}
"] device`
,
iq
),
dev
=>
dev
.
getAttribute
(
'
id
'
));
(
iq
)
=>
{
_
.
forEach
(
device_ids
,
id
=>
this
.
devices
.
create
({
'
id
'
:
id
,
'
jid
'
:
this
.
get
(
'
jid
'
)}));
_
.
forEach
(
return
device_ids
;
sizzle
(
`list[xmlns="
${
Strophe
.
NS
.
OMEMO
}
"] device`
,
iq
),
});
(
dev
)
=>
this
.
devices
.
create
({
'
id
'
:
dev
.
getAttribute
(
'
id
'
),
'
jid
'
:
this
.
get
(
'
jid
'
)})
);
resolve
();
},
reject
,
_converse
.
IQ_TIMEOUT
);
});
},
},
publishDevices
()
{
publishDevices
()
{
...
@@ -788,18 +803,6 @@
...
@@ -788,18 +803,6 @@
return
_converse
.
api
.
sendIQ
(
stanza
);
return
_converse
.
api
.
sendIQ
(
stanza
);
},
},
addOwnDevice
(
device_id
)
{
/* Add this device to our list of devices stored on the
* server.
* https://xmpp.org/extensions/xep-0384.html#usecases-announcing
*/
if
(
this
.
get
(
'
jid
'
)
!==
_converse
.
bare_jid
)
{
throw
new
Error
(
"
Cannot add device to someone else's device list
"
);
}
this
.
devices
.
create
({
'
id
'
:
device_id
.
toString
(),
'
jid
'
:
this
.
get
(
'
jid
'
)});
return
this
.
publishDevices
();
},
removeOwnDevices
(
device_ids
)
{
removeOwnDevices
(
device_ids
)
{
if
(
this
.
get
(
'
jid
'
)
!==
_converse
.
bare_jid
)
{
if
(
this
.
get
(
'
jid
'
)
!==
_converse
.
bare_jid
)
{
throw
new
Error
(
"
Cannot remove devices from someone else's device list
"
);
throw
new
Error
(
"
Cannot remove devices from someone else's device list
"
);
...
@@ -861,25 +864,6 @@
...
@@ -861,25 +864,6 @@
});
});
}
}
function
updateOwnDeviceList
()
{
/* If our own device is not on the list, add it.
* Also, deduplicate devices if necessary.
*/
const
devicelist
=
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
),
device_id
=
_converse
.
omemo_store
.
get
(
'
device_id
'
).
toString
(),
own_device
=
devicelist
.
devices
.
findWhere
({
'
id
'
:
device_id
});
if
(
!
own_device
)
{
return
devicelist
.
addOwnDevice
(
device_id
);
}
else
if
(
!
own_device
.
get
(
'
active
'
))
{
own_device
.
set
(
'
active
'
,
true
,
{
'
silent
'
:
true
});
return
devicelist
.
addOwnDevice
(
device_id
);
}
else
{
return
Promise
.
resolve
();
}
}
function
updateBundleFromStanza
(
stanza
)
{
function
updateBundleFromStanza
(
stanza
)
{
const
items_el
=
sizzle
(
`items`
,
stanza
).
pop
();
const
items_el
=
sizzle
(
`items`
,
stanza
).
pop
();
if
(
!
items_el
||
!
items_el
.
getAttribute
(
'
node
'
).
startsWith
(
Strophe
.
NS
.
OMEMO_BUNDLES
))
{
if
(
!
items_el
||
!
items_el
.
getAttribute
(
'
node
'
).
startsWith
(
Strophe
.
NS
.
OMEMO_BUNDLES
))
{
...
@@ -916,9 +900,11 @@
...
@@ -916,9 +900,11 @@
devices
.
create
({
'
id
'
:
device_id
,
'
jid
'
:
jid
})
devices
.
create
({
'
id
'
:
device_id
,
'
jid
'
:
jid
})
}
}
});
});
// Make sure our own device is on the list (i.e. if it was
if
(
Strophe
.
getBareJidFromJid
(
jid
)
===
_converse
.
bare_jid
)
{
// removed, add it again.
// Make sure our own device is on the list (i.e. if it was
updateOwnDeviceList
();
// removed, add it again.
_converse
.
devicelists
.
get
(
_converse
.
bare_jid
).
publishCurrentDevice
(
device_ids
);
}
}
}
function
registerPEPPushHandler
()
{
function
registerPEPPushHandler
()
{
...
@@ -954,13 +940,15 @@
...
@@ -954,13 +940,15 @@
fetchOwnDevices
()
fetchOwnDevices
()
.
then
(()
=>
restoreOMEMOSession
())
.
then
(()
=>
restoreOMEMOSession
())
.
then
(()
=>
updateOwnDeviceList
())
.
then
(()
=>
_converse
.
omemo
.
publishBundle
())
.
then
(()
=>
_converse
.
omemo
.
publishBundle
())
.
then
(()
=>
_converse
.
emit
(
'
OMEMOInitialized
'
))
.
then
(()
=>
_converse
.
emit
(
'
OMEMOInitialized
'
))
.
catch
(
_
.
partial
(
_converse
.
log
,
_
,
Strophe
.
LogLevel
.
ERROR
));
.
catch
(
_
.
partial
(
_converse
.
log
,
_
,
Strophe
.
LogLevel
.
ERROR
));
}
}
_converse
.
api
.
listen
.
on
(
'
afterTearDown
'
,
()
=>
_converse
.
devicelists
.
reset
());
_converse
.
api
.
listen
.
on
(
'
afterTearDown
'
,
()
=>
{
_converse
.
devicelists
.
reset
();
delete
_converse
.
omemo_store
;
});
_converse
.
api
.
listen
.
on
(
'
connected
'
,
registerPEPPushHandler
);
_converse
.
api
.
listen
.
on
(
'
connected
'
,
registerPEPPushHandler
);
_converse
.
api
.
listen
.
on
(
'
renderToolbar
'
,
(
view
)
=>
view
.
renderOMEMOToolbarButton
());
_converse
.
api
.
listen
.
on
(
'
renderToolbar
'
,
(
view
)
=>
view
.
renderOMEMOToolbarButton
());
_converse
.
api
.
listen
.
on
(
'
statusInitialized
'
,
initOMEMO
);
_converse
.
api
.
listen
.
on
(
'
statusInitialized
'
,
initOMEMO
);
...
...
tests/utils.js
View file @
fa0e7aef
...
@@ -100,7 +100,7 @@
...
@@ -100,7 +100,7 @@
utils
.
openChatBoxFor
=
function
(
_converse
,
jid
)
{
utils
.
openChatBoxFor
=
function
(
_converse
,
jid
)
{
_converse
.
roster
.
get
(
jid
).
trigger
(
"
open
"
);
_converse
.
roster
.
get
(
jid
).
trigger
(
"
open
"
);
return
utils
.
waitUntil
(()
=>
_converse
.
chatboxviews
.
get
(
jid
));
return
utils
.
waitUntil
(()
=>
_converse
.
chatboxviews
.
get
(
jid
)
,
1000
);
};
};
utils
.
openChatRoomViaModal
=
function
(
_converse
,
jid
,
nick
=
''
)
{
utils
.
openChatRoomViaModal
=
function
(
_converse
,
jid
,
nick
=
''
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment