import log from '@converse/headless/log'; import { IQError } from './errors.js'; import { Model } from '@converse/skeletor/src/model.js'; import { UNDECIDED } from './consts.js'; import { _converse, api, converse } from '@converse/headless/core.js'; import { getRandomInt } from '@converse/headless/utils/core.js'; import { parseBundle } from './utils.js'; const { Strophe, sizzle, $iq } = converse.env; /** * @class * @namespace _converse.Device * @memberOf _converse */ const Device = Model.extend({ defaults: { 'trusted': UNDECIDED, 'active': true }, getRandomPreKey () { // XXX: assumes that the bundle has already been fetched const bundle = this.get('bundle'); return bundle.prekeys[getRandomInt(bundle.prekeys.length)]; }, async fetchBundleFromServer () { const stanza = $iq({ 'type': 'get', 'from': _converse.bare_jid, 'to': this.get('jid') }).c('pubsub', { 'xmlns': Strophe.NS.PUBSUB }) .c('items', { 'node': `${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}` }); let iq; try { iq = await api.sendIQ(stanza); } catch (iq) { log.error(`Could not fetch bundle for device ${this.get('id')} from ${this.get('jid')}`); log.error(iq); return null; } if (iq.querySelector('error')) { throw new IQError('Could not fetch bundle', iq); } const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"]`, iq).pop(); const bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop(); const bundle = parseBundle(bundle_el); this.save('bundle', bundle); return bundle; }, /** * Fetch and save the bundle information associated with * this device, if the information is not cached already. * @method _converse.Device#getBundle */ getBundle () { if (this.get('bundle')) { return Promise.resolve(this.get('bundle'), this); } else { return this.fetchBundleFromServer(); } } }); export default Device;