Ver Fonte

Ran prettier on the OMEMO plugin files

JC Brand há 6 meses atrás
pai
commit
8f63e048b7

+ 25 - 25
src/plugins/omemo/api.js

@@ -1,6 +1,6 @@
-import { _converse, api, u } from '@converse/headless';
-import { generateFingerprint } from './utils.js';
-import OMEMOStore from './store.js';
+import { _converse, api, u } from "@converse/headless";
+import { generateFingerprint } from "./utils.js";
+import OMEMOStore from "./store.js";
 
 export default {
     /**
@@ -14,22 +14,22 @@ export default {
         /**
          * Returns the device ID of the current device.
          */
-        async getDeviceID () {
-            await api.waitUntil('OMEMOInitialized');
-            return _converse.state.omemo_store.get('device_id');
+        async getDeviceID() {
+            await api.waitUntil("OMEMOInitialized");
+            return _converse.state.omemo_store.get("device_id");
         },
 
         session: {
-            async restore () {
+            async restore() {
                 const { state } = _converse;
                 if (state.omemo_store === undefined) {
-                    const bare_jid = _converse.session.get('bare_jid');
+                    const bare_jid = _converse.session.get("bare_jid");
                     const id = `converse.omemosession-${bare_jid}`;
                     state.omemo_store = new OMEMOStore({ id });
                     u.initStorage(state.omemo_store, id);
                 }
                 await state.omemo_store.fetchSession();
-            }
+            },
         },
 
         /**
@@ -40,19 +40,19 @@ export default {
          */
         devicelists: {
             /**
-             * Returns the {@link _converse.DeviceList} for a particular JID.
+             * Returns the {@link DeviceList} for a particular JID.
              * The device list will be created if it doesn't exist already.
              * @method _converse.api.omemo.devicelists.get
              * @param {String} jid - The Jabber ID for which the device list will be returned.
              * @param {boolean} create=false - Set to `true` if the device list
              *      should be created if it cannot be found.
              */
-            async get (jid, create=false) {
-                const list = _converse.state.devicelists.get(jid) ||
-                    (create ? _converse.state.devicelists.create({ jid }) : null);
+            async get(jid, create = false) {
+                const { devicelists } = _converse.state;
+                const list = devicelists.get(jid) || (create ? devicelists.create({ jid }) : null);
                 await list?.initialized;
                 return list;
-            }
+            },
         },
 
         /**
@@ -69,31 +69,31 @@ export default {
              * @method _converse.api.omemo.bundle.generate
              * @returns {promise} Promise which resolves once we have a result from the server.
              */
-            async generate () {
-                await api.waitUntil('OMEMOInitialized');
+            async generate() {
+                await api.waitUntil("OMEMOInitialized");
                 // Remove current device
-                const bare_jid = _converse.session.get('bare_jid');
+                const bare_jid = _converse.session.get("bare_jid");
                 const devicelist = await api.omemo.devicelists.get(bare_jid);
 
                 const { omemo_store } = _converse.state;
-                const device_id = omemo_store.get('device_id');
+                const device_id = omemo_store.get("device_id");
                 if (device_id) {
                     const device = devicelist.devices.get(device_id);
                     omemo_store.unset(device_id);
                     if (device) {
-                        await new Promise(done => device.destroy({ 'success': done, 'error': done }));
+                        await new Promise((done) => device.destroy({ "success": done, "error": done }));
                     }
-                    devicelist.devices.trigger('remove');
+                    devicelist.devices.trigger("remove");
                 }
                 // Generate new device bundle and publish
                 // https://xmpp.org/extensions/attic/xep-0384-0.3.0.html#usecases-announcing
                 await omemo_store.generateBundle();
                 await devicelist.publishDevices();
-                const device = devicelist.devices.get(omemo_store.get('device_id'));
+                const device = devicelist.devices.get(omemo_store.get("device_id"));
                 const fp = generateFingerprint(device);
                 await omemo_store.publishBundle();
                 return fp;
-            }
-        }
-    }
-}
+            },
+        },
+    },
+};

+ 22 - 22
src/plugins/omemo/device.js

@@ -1,25 +1,25 @@
-import { Model } from '@converse/skeletor';
-import { _converse, api, converse, log, u } from '@converse/headless';
-import { IQError } from 'shared/errors.js';
-import { UNDECIDED } from './consts.js';
-import { parseBundle } from './utils.js';
+import { Model } from "@converse/skeletor";
+import { _converse, api, converse, log, u } from "@converse/headless";
+import { IQError } from "shared/errors.js";
+import { UNDECIDED } from "./consts.js";
+import { parseBundle } from "./utils.js";
 
 const { Strophe, sizzle, stx } = converse.env;
 
 class Device extends Model {
-    defaults () {
+    defaults() {
         return {
             trusted: UNDECIDED,
-            active: true
-        }
+            active: true,
+        };
     }
 
     /**
      * @returns {import('./types').PreKey}
      */
-    getRandomPreKey () {
+    getRandomPreKey() {
         // XXX: assumes that the bundle has already been fetched
-        const bundle = this.get('bundle');
+        const bundle = this.get("bundle");
         return bundle.prekeys[u.getRandomInt(bundle.prekeys.length)];
     }
 
@@ -30,12 +30,12 @@ class Device extends Model {
      * a signed PreKey with corresponding signature, and a list of (single use) PreKeys.
      * @returns {Promise<import('./types').Bundle>}
      */
-    async fetchBundleFromServer () {
-        const bare_jid = _converse.session.get('bare_jid');
+    async fetchBundleFromServer() {
+        const bare_jid = _converse.session.get("bare_jid");
         const stanza = stx`
-            <iq type="get" from="${bare_jid}" to="${this.get('jid')}" xmlns="jabber:client">
+            <iq type="get" from="${bare_jid}" to="${this.get("jid")}" xmlns="jabber:client">
                 <pubsub xmlns="${Strophe.NS.PUBSUB}">
-                    <items node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"/>
+                    <items node="${Strophe.NS.OMEMO_BUNDLES}:${this.get("id")}"/>
                 </pubsub>
             </iq>`;
 
@@ -43,17 +43,17 @@ class Device extends Model {
         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(`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);
+        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 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);
+        this.save("bundle", bundle);
         return bundle;
     }
 
@@ -62,9 +62,9 @@ class Device extends Model {
      * this device, if the information is not cached already.
      * @returns {Promise<import('./types').Bundle>}
      */
-    getBundle () {
-        if (this.get('bundle')) {
-            return Promise.resolve(this.get('bundle'));
+    getBundle() {
+        if (this.get("bundle")) {
+            return Promise.resolve(this.get("bundle"));
         } else {
             return this.fetchBundleFromServer();
         }

+ 55 - 42
src/plugins/omemo/devicelist.js

@@ -1,59 +1,62 @@
-import { Model } from '@converse/skeletor';
-import { getOpenPromise } from '@converse/openpromise';
-import { _converse, api, converse, log, u } from '@converse/headless';
+import { Model } from "@converse/skeletor";
+import { getOpenPromise } from "@converse/openpromise";
+import { _converse, api, converse, log, u } from "@converse/headless";
 
 const { Strophe, stx, sizzle } = converse.env;
 
 class DeviceList extends Model {
-    get idAttribute () {
-        return 'jid';
+    get idAttribute() {
+        return "jid";
     }
 
-    async initialize () {
+    async initialize() {
         super.initialize();
         this.initialized = getOpenPromise();
         await this.initDevices();
         this.initialized.resolve();
     }
 
-    initDevices () {
+    initDevices() {
         this.devices = new _converse.exports.Devices();
-        const bare_jid = _converse.session.get('bare_jid');
-        const id = `converse.devicelist-${bare_jid}-${this.get('jid')}`;
+        const bare_jid = _converse.session.get("bare_jid");
+        const id = `converse.devicelist-${bare_jid}-${this.get("jid")}`;
         u.initStorage(this.devices, id);
         return this.fetchDevices();
     }
 
-    async onDevicesFound (collection) {
+    /**
+     * @param {import('./devices').default} collection
+     */
+    async onDevicesFound(collection) {
         if (collection.length === 0) {
             let ids = [];
             try {
                 ids = await this.fetchDevicesFromServer();
             } catch (e) {
                 if (e === null) {
-                    log.error(`Timeout error while fetching devices for ${this.get('jid')}`);
+                    log.error(`Timeout error while fetching devices for ${this.get("jid")}`);
                 } else {
-                    log.error(`Could not fetch devices for ${this.get('jid')}`);
+                    log.error(`Could not fetch devices for ${this.get("jid")}`);
                     log.error(e);
                 }
                 this.destroy();
             }
-            const bare_jid = _converse.session.get('bare_jid');
-            if (this.get('jid') === bare_jid) {
+            const bare_jid = _converse.session.get("bare_jid");
+            if (this.get("jid") === bare_jid) {
                 this.publishCurrentDevice(ids);
             }
         }
     }
 
-    fetchDevices () {
+    fetchDevices() {
         if (this._devices_promise === undefined) {
-            this._devices_promise = new Promise(resolve => {
+            this._devices_promise = new Promise((resolve) => {
                 this.devices.fetch({
-                    success: c => resolve(this.onDevicesFound(c)),
+                    success: (c) => resolve(this.onDevicesFound(c)),
                     error: (_, e) => {
                         log.error(e);
                         resolve();
-                    }
+                    },
                 });
             });
         }
@@ -63,13 +66,13 @@ class DeviceList extends Model {
     /**
      * @returns {Promise<string>}
      */
-    async getOwnDeviceId () {
+    async getOwnDeviceId() {
         const { omemo_store } = _converse.state;
-        let device_id = omemo_store.get('device_id');
+        let device_id = omemo_store.get("device_id");
         if (!this.devices.get(device_id)) {
             // Generate a new bundle if we cannot find our device
             await omemo_store.generateBundle();
-            device_id = omemo_store.get('device_id');
+            device_id = omemo_store.get("device_id");
         }
         return device_id;
     }
@@ -77,9 +80,9 @@ class DeviceList extends Model {
     /**
      * @param {string[]} device_ids
      */
-    async publishCurrentDevice (device_ids) {
-        const bare_jid = _converse.session.get('bare_jid');
-        if (this.get('jid') !== bare_jid) {
+    async publishCurrentDevice(device_ids) {
+        const bare_jid = _converse.session.get("bare_jid");
+        if (this.get("jid") !== bare_jid) {
             return; // We only publish for ourselves.
         }
         await api.omemo.session.restore();
@@ -87,7 +90,7 @@ class DeviceList extends Model {
         if (!_converse.state.omemo_store) {
             // Happens during tests. The connection gets torn down
             // before publishCurrentDevice has time to finish.
-            log.debug('publishCurrentDevice: omemo_store is not defined, likely a timing issue');
+            log.debug("publishCurrentDevice: omemo_store is not defined, likely a timing issue");
             return;
         }
         if (!device_ids.includes(await this.getOwnDeviceId())) {
@@ -98,10 +101,10 @@ class DeviceList extends Model {
     /**
      * @returns {Promise<import('./device').default[]>}
      */
-    async fetchDevicesFromServer () {
-        const bare_jid = _converse.session.get('bare_jid');
+    async fetchDevicesFromServer() {
+        const bare_jid = _converse.session.get("bare_jid");
         const stanza = stx`
-            <iq type='get' from='${bare_jid}' to='${this.get('jid')}'>
+            <iq type='get' from='${bare_jid}' to='${this.get("jid")}' xmlns="jabber:client">
                 <pubsub xmlns='${Strophe.NS.PUBSUB}'>
                     <items node='${Strophe.NS.OMEMO_DEVICELIST}'/>
                 </pubsub>
@@ -109,8 +112,8 @@ class DeviceList extends Model {
 
         const iq = await api.sendIQ(stanza);
         const selector = `list[xmlns="${Strophe.NS.OMEMO}"] device`;
-        const device_ids = sizzle(selector, iq).map(d => d.getAttribute('id'));
-        const jid = this.get('jid');
+        const device_ids = sizzle(selector, iq).map((d) => d.getAttribute("id"));
+        const jid = this.get("jid");
         return Promise.all(device_ids.map((id) => this.devices.create({ id, jid }, { promise: true })));
     }
 
@@ -119,31 +122,41 @@ class DeviceList extends Model {
      * ensure that all devices are published for potential chat partners to see.
      * See: https://xmpp.org/extensions/attic/xep-0384-0.3.0.html#usecases-announcing
      */
-    publishDevices () {
+    publishDevices() {
         const item = stx`
             <item id='current'>
                 <list xmlns='${Strophe.NS.OMEMO}'>
-                    ${this.devices.filter((d) => d.get('active')).map((d) => stx`<device id='${d.get('id')}'/>`)}
+                    ${this.devices.filter((d) => d.get("active")).map((d) => stx`<device id='${d.get("id")}'/>`)}
                 </list>
             </item>`;
-        const options = { access_model: 'open' };
+        const options = { access_model: "open" };
         return api.pubsub.publish(null, Strophe.NS.OMEMO_DEVICELIST, item, options, false);
     }
 
     /**
      * @param {string[]} device_ids
      */
-    async removeOwnDevices (device_ids) {
-        const bare_jid = _converse.session.get('bare_jid');
-        if (this.get('jid') !== bare_jid) {
+    async removeOwnDevices(device_ids) {
+        const bare_jid = _converse.session.get("bare_jid");
+        if (this.get("jid") !== bare_jid) {
             throw new Error("Cannot remove devices from someone else's device list");
         }
-        await Promise.all(device_ids.map(id => this.devices.get(id)).map(d =>
-            new Promise(resolve => d.destroy({
-                success: resolve,
-                error: (_, e) => { log.error(e); resolve(); }
-            }))
-        ));
+        await Promise.all(
+            device_ids
+                .map((id) => this.devices.get(id))
+                .map(
+                    (d) =>
+                        new Promise((resolve) =>
+                            d.destroy({
+                                success: resolve,
+                                error: (_, e) => {
+                                    log.error(e);
+                                    resolve();
+                                },
+                            })
+                        )
+                )
+        );
         return this.publishDevices();
     }
 }

+ 3 - 5
src/plugins/omemo/devicelists.js

@@ -1,13 +1,11 @@
-import DeviceList from './devicelist.js';
-import { Collection } from '@converse/skeletor';
+import DeviceList from "./devicelist.js";
+import { Collection } from "@converse/skeletor";
 
 class DeviceLists extends Collection {
-
-    constructor () {
+    constructor() {
         super();
         this.model = DeviceList;
     }
-
 }
 
 export default DeviceLists;

+ 3 - 4
src/plugins/omemo/devices.js

@@ -1,9 +1,8 @@
-import { Collection } from '@converse/skeletor';
-import Device from './device.js';
+import { Collection } from "@converse/skeletor";
+import Device from "./device.js";
 
 class Devices extends Collection {
-
-    constructor () {
+    constructor() {
         super();
         this.model = Device;
     }

+ 18 - 19
src/plugins/omemo/fingerprints.js

@@ -1,39 +1,38 @@
 import { api } from "@converse/headless";
-import { CustomElement } from 'shared/components/element.js';
-import tplFingerprints from './templates/fingerprints.js';
+import { CustomElement } from "shared/components/element.js";
+import tplFingerprints from "./templates/fingerprints.js";
 
 export class Fingerprints extends CustomElement {
-
-    constructor () {
+    constructor() {
         super();
         this.jid = null;
     }
 
-    static get properties () {
+    static get properties() {
         return {
-            'jid': { type: String }
-        }
+            "jid": { type: String },
+        };
     }
 
-    async initialize () {
+    async initialize() {
         this.devicelist = await api.omemo.devicelists.get(this.jid, true);
-        this.listenTo(this.devicelist.devices, 'change:bundle', () => this.requestUpdate());
-        this.listenTo(this.devicelist.devices, 'change:trusted', () => this.requestUpdate());
-        this.listenTo(this.devicelist.devices, 'remove', () => this.requestUpdate());
-        this.listenTo(this.devicelist.devices, 'add', () => this.requestUpdate());
-        this.listenTo(this.devicelist.devices, 'reset', () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "change:bundle", () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "change:trusted", () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "remove", () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "add", () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "reset", () => this.requestUpdate());
         this.requestUpdate();
     }
 
-    render () {
-        return this.devicelist ? tplFingerprints(this) : '';
+    render() {
+        return this.devicelist ? tplFingerprints(this) : "";
     }
 
-    toggleDeviceTrust (ev) {
+    toggleDeviceTrust(ev) {
         const radio = ev.target;
-        const device = this.devicelist.devices.get(radio.getAttribute('name'));
-        device.save('trusted', parseInt(radio.value, 10));
+        const device = this.devicelist.devices.get(radio.getAttribute("name"));
+        device.save("trusted", parseInt(radio.value, 10));
     }
 }
 
-api.elements.define('converse-omemo-fingerprints', Fingerprints);
+api.elements.define("converse-omemo-fingerprints", Fingerprints);

+ 50 - 49
src/plugins/omemo/index.js

@@ -4,16 +4,16 @@
  * @module plugins-omemo-index
  * @typedef {Window & globalThis & {libsignal: any} } WindowWithLibsignal
  */
-import { _converse, api, converse, log, u } from '@converse/headless';
-import './fingerprints.js';
-import './profile.js';
-import 'shared/modals/user-details.js';
-import Device from './device.js';
-import DeviceList from './devicelist.js';
-import DeviceLists from './devicelists.js';
-import Devices from './devices.js';
-import OMEMOStore from './store.js';
-import omemo_api from './api.js';
+import { _converse, api, converse, log, u } from "@converse/headless";
+import "./fingerprints.js";
+import "./profile.js";
+import "shared/modals/user-details.js";
+import Device from "./device.js";
+import DeviceList from "./devicelist.js";
+import DeviceLists from "./devicelists.js";
+import Devices from "./devices.js";
+import OMEMOStore from "./store.js";
+import omemo_api from "./api.js";
 import {
     createOMEMOMessageStanza,
     encryptFile,
@@ -29,36 +29,35 @@ import {
     parseEncryptedMessage,
     registerPEPPushHandler,
     setEncryptedFileURL,
-} from './utils.js';
+} from "./utils.js";
 
-import  './styles/omemo.scss';
+import "./styles/omemo.scss";
 
 const { Strophe } = converse.env;
 const { shouldClearCache } = u;
 
 converse.env.omemo = omemo;
 
-Strophe.addNamespace('OMEMO_DEVICELIST', Strophe.NS.OMEMO + '.devicelist');
-Strophe.addNamespace('OMEMO_VERIFICATION', Strophe.NS.OMEMO + '.verification');
-Strophe.addNamespace('OMEMO_WHITELISTED', Strophe.NS.OMEMO + '.whitelisted');
-Strophe.addNamespace('OMEMO_BUNDLES', Strophe.NS.OMEMO + '.bundles');
+Strophe.addNamespace("OMEMO_DEVICELIST", Strophe.NS.OMEMO + ".devicelist");
+Strophe.addNamespace("OMEMO_VERIFICATION", Strophe.NS.OMEMO + ".verification");
+Strophe.addNamespace("OMEMO_WHITELISTED", Strophe.NS.OMEMO + ".whitelisted");
+Strophe.addNamespace("OMEMO_BUNDLES", Strophe.NS.OMEMO + ".bundles");
 
-
-converse.plugins.add('converse-omemo', {
-    enabled (_converse) {
+converse.plugins.add("converse-omemo", {
+    enabled(_converse) {
         return (
-            /** @type WindowWithLibsignal */(window).libsignal &&
-            _converse.config.get('trusted') &&
-            !api.settings.get('clear_cache_on_logout') &&
-            !_converse.api.settings.get('blacklisted_plugins').includes('converse-omemo')
+            /** @type WindowWithLibsignal */ (window).libsignal &&
+            _converse.config.get("trusted") &&
+            !api.settings.get("clear_cache_on_logout") &&
+            !_converse.api.settings.get("blacklisted_plugins").includes("converse-omemo")
         );
     },
 
-    dependencies: ['converse-chatview', 'converse-pubsub', 'converse-profile'],
+    dependencies: ["converse-chatview", "converse-pubsub", "converse-profile"],
 
-    initialize () {
+    initialize() {
         api.settings.extend({ omemo_default: false });
-        api.promises.add(['OMEMOInitialized']);
+        api.promises.add(["OMEMOInitialized"]);
 
         Object.assign(_converse.api, omemo_api);
 
@@ -74,11 +73,11 @@ converse.plugins.add('converse-omemo', {
         Object.assign(_converse.exports, exports);
 
         /******************** Event Handlers ********************/
-        api.waitUntil('chatBoxesInitialized').then(onChatBoxesInitialized);
+        api.waitUntil("chatBoxesInitialized").then(onChatBoxesInitialized);
 
-        api.listen.on('getOutgoingMessageAttributes', getOutgoingMessageAttributes);
+        api.listen.on("getOutgoingMessageAttributes", getOutgoingMessageAttributes);
 
-        api.listen.on('createMessageStanza', async (chat, data) => {
+        api.listen.on("createMessageStanza", async (chat, data) => {
             try {
                 data = await createOMEMOMessageStanza(chat, data);
             } catch (e) {
@@ -87,39 +86,41 @@ converse.plugins.add('converse-omemo', {
             return data;
         });
 
-        api.listen.on('afterFileUploaded', (msg, attrs) => msg.file.xep454_ivkey ? setEncryptedFileURL(msg, attrs) : attrs);
-        api.listen.on('beforeFileUpload', (chat, file) => chat.get('omemo_active') ? encryptFile(file) : file);
+        api.listen.on("afterFileUploaded", (msg, attrs) =>
+            msg.file.xep454_ivkey ? setEncryptedFileURL(msg, attrs) : attrs
+        );
+        api.listen.on("beforeFileUpload", (chat, file) => (chat.get("omemo_active") ? encryptFile(file) : file));
 
-        api.listen.on('parseMessage', parseEncryptedMessage);
-        api.listen.on('parseMUCMessage', parseEncryptedMessage);
+        api.listen.on("parseMessage", parseEncryptedMessage);
+        api.listen.on("parseMUCMessage", parseEncryptedMessage);
 
-        api.listen.on('chatBoxViewInitialized', onChatInitialized);
-        api.listen.on('chatRoomViewInitialized', onChatInitialized);
+        api.listen.on("chatBoxViewInitialized", onChatInitialized);
+        api.listen.on("chatRoomViewInitialized", onChatInitialized);
 
-        api.listen.on('connected', registerPEPPushHandler);
-        api.listen.on('getToolbarButtons', getOMEMOToolbarButton);
+        api.listen.on("connected", registerPEPPushHandler);
+        api.listen.on("getToolbarButtons", getOMEMOToolbarButton);
 
-        api.listen.on('statusInitialized', initOMEMO);
-        api.listen.on('addClientFeatures', () => api.disco.own.features.add(`${Strophe.NS.OMEMO_DEVICELIST}+notify`));
+        api.listen.on("statusInitialized", initOMEMO);
+        api.listen.on("addClientFeatures", () => api.disco.own.features.add(`${Strophe.NS.OMEMO_DEVICELIST}+notify`));
 
-        api.listen.on('afterMessageBodyTransformed', handleEncryptedFiles);
+        api.listen.on("afterMessageBodyTransformed", handleEncryptedFiles);
 
-        api.listen.on('userDetailsModalInitialized', contact => {
-            const jid = contact.get('jid');
-            generateFingerprints(jid).catch(e => log.error(e));
+        api.listen.on("userDetailsModalInitialized", (contact) => {
+            const jid = contact.get("jid");
+            generateFingerprints(jid).catch((e) => log.error(e));
         });
 
-        api.listen.on('profileModalInitialized', () => {
-            const bare_jid = _converse.session.get('bare_jid');
-            generateFingerprints(bare_jid).catch(e => log.error(e));
+        api.listen.on("profileModalInitialized", () => {
+            const bare_jid = _converse.session.get("bare_jid");
+            generateFingerprints(bare_jid).catch((e) => log.error(e));
         });
 
-        api.listen.on('clearSession', () => {
-            delete _converse.state.omemo_store
+        api.listen.on("clearSession", () => {
+            delete _converse.state.omemo_store;
             if (shouldClearCache(_converse) && _converse.state.devicelists) {
                 _converse.state.devicelists.clearStore();
                 delete _converse.state.devicelists;
             }
         });
-    }
+    },
 });

+ 30 - 28
src/plugins/omemo/profile.js

@@ -1,71 +1,73 @@
-import tplProfile from './templates/profile.js';
+import tplProfile from "./templates/profile.js";
 import tplSpinner from "templates/spinner.js";
-import { CustomElement } from 'shared/components/element.js';
-import { __ } from 'i18n';
+import { CustomElement } from "shared/components/element.js";
+import { __ } from "i18n";
 import { _converse, api, converse, log } from "@converse/headless";
 
 const { Strophe, sizzle, u } = converse.env;
 
-
 export class Profile extends CustomElement {
-
-    async initialize () {
-        const bare_jid = _converse.session.get('bare_jid');
+    async initialize() {
+        const bare_jid = _converse.session.get("bare_jid");
         this.devicelist = await api.omemo.devicelists.get(bare_jid, true);
         await this.setAttributes();
-        this.listenTo(this.devicelist.devices, 'change:bundle', () => this.requestUpdate());
-        this.listenTo(this.devicelist.devices, 'reset', () => this.requestUpdate());
-        this.listenTo(this.devicelist.devices, 'reset', () => this.requestUpdate());
-        this.listenTo(this.devicelist.devices, 'remove', () => this.requestUpdate());
-        this.listenTo(this.devicelist.devices, 'add', () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "change:bundle", () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "reset", () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "reset", () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "remove", () => this.requestUpdate());
+        this.listenTo(this.devicelist.devices, "add", () => this.requestUpdate());
         this.requestUpdate();
     }
 
-    async setAttributes () {
+    async setAttributes() {
         this.device_id = await api.omemo.getDeviceID();
         this.current_device = this.devicelist.devices.get(this.device_id);
-        this.other_devices = this.devicelist.devices.filter(d => d.get('id') !== this.device_id);
+        this.other_devices = this.devicelist.devices.filter((d) => d.get("id") !== this.device_id);
     }
 
-    render () {
+    render() {
         return this.devicelist ? tplProfile(this) : tplSpinner();
     }
 
-    selectAll (ev) {  // eslint-disable-line class-methods-use-this
-        let sibling = u.ancestor(ev.target, 'li');
+    selectAll(ev) {
+        // eslint-disable-line class-methods-use-this
+        let sibling = u.ancestor(ev.target, "li");
         while (sibling) {
             sibling.querySelector('input[type="checkbox"]').checked = ev.target.checked;
             sibling = sibling.nextElementSibling;
         }
     }
 
-    async removeSelectedFingerprints (ev) {
+    async removeSelectedFingerprints(ev) {
         ev.preventDefault();
         ev.stopPropagation();
-        ev.target.querySelector('.select-all').checked = false;
+        ev.target.querySelector(".select-all").checked = false;
         const device_ids = sizzle('.fingerprint-removal-item input[type="checkbox"]:checked', ev.target).map(
-            c => c.value
+            (c) => c.value
         );
 
         try {
             await this.devicelist.removeOwnDevices(device_ids);
         } catch (err) {
             log.error(err);
-            _converse.api.alert(Strophe.LogLevel.ERROR, __('Error'), [
-                __('Sorry, an error occurred while trying to remove the devices.')
+            _converse.api.alert(Strophe.LogLevel.ERROR, __("Error"), [
+                __("Sorry, an error occurred while trying to remove the devices."),
             ]);
         }
         await this.setAttributes();
         this.requestUpdate();
     }
 
-    async generateOMEMODeviceBundle (ev) {
+    async generateOMEMODeviceBundle(ev) {
         ev.preventDefault();
 
-        const result = await api.confirm(__(
-            'Are you sure you want to generate new OMEMO keys? ' +
-            'This will remove your old keys and all previously ' +
-            'encrypted messages will no longer be decryptable on this device.'));
+        const result = await api.confirm(
+            __(
+                "Are you sure you want to generate new OMEMO keys? " +
+                    "This will remove your old keys and all previously " +
+                    "encrypted messages will no longer be decryptable on this device."
+            )
+        );
 
         if (result) {
             await api.omemo.bundle.generate();
@@ -75,4 +77,4 @@ export class Profile extends CustomElement {
     }
 }
 
-api.elements.define('converse-omemo-profile', Profile);
+api.elements.define("converse-omemo-profile", Profile);

+ 116 - 120
src/plugins/omemo/store.js

@@ -1,65 +1,63 @@
 /**
  * @typedef {module:plugins-omemo-index.WindowWithLibsignal} WindowWithLibsignal
  */
-import range from 'lodash-es/range';
-import { Model } from '@converse/skeletor';
-import { generateDeviceID } from './utils.js';
-import { _converse, api, converse, log } from '@converse/headless';
+import range from "lodash-es/range";
+import { Model } from "@converse/skeletor";
+import { generateDeviceID } from "./utils.js";
+import { _converse, api, converse, log } from "@converse/headless";
 
 const { Strophe, $build, u } = converse.env;
 
-
 class OMEMOStore extends Model {
-
-    get Direction () {
+    get Direction() {
         return {
             SENDING: 1,
-            RECEIVING: 2
-        }
+            RECEIVING: 2,
+        };
     }
 
-    getIdentityKeyPair () {
-        const keypair = this.get('identity_keypair');
+    getIdentityKeyPair() {
+        const keypair = this.get("identity_keypair");
         return Promise.resolve({
-            'privKey': u.base64ToArrayBuffer(keypair.privKey),
-            'pubKey': u.base64ToArrayBuffer(keypair.pubKey)
+            "privKey": u.base64ToArrayBuffer(keypair.privKey),
+            "pubKey": u.base64ToArrayBuffer(keypair.pubKey),
         });
     }
 
-    getLocalRegistrationId () {
-        return Promise.resolve(parseInt(this.get('device_id'), 10));
+    getLocalRegistrationId() {
+        return Promise.resolve(parseInt(this.get("device_id"), 10));
     }
 
-    isTrustedIdentity (identifier, identity_key, _direction) {
+    isTrustedIdentity(identifier, identity_key, _direction) {
         if (identifier === null || identifier === undefined) {
             throw new Error("Can't check identity key for invalid key");
         }
         if (!(identity_key instanceof ArrayBuffer)) {
-            throw new Error('Expected identity_key to be an ArrayBuffer');
+            throw new Error("Expected identity_key to be an ArrayBuffer");
         }
-        const trusted = this.get('identity_key' + identifier);
+        const trusted = this.get("identity_key" + identifier);
         if (trusted === undefined) {
             return Promise.resolve(true);
         }
         return Promise.resolve(u.arrayBufferToBase64(identity_key) === trusted);
     }
 
-    loadIdentityKey (identifier) {
+    loadIdentityKey(identifier) {
         if (identifier === null || identifier === undefined) {
             throw new Error("Can't load identity_key for invalid identifier");
         }
-        return Promise.resolve(u.base64ToArrayBuffer(this.get('identity_key' + identifier)));
+        return Promise.resolve(u.base64ToArrayBuffer(this.get("identity_key" + identifier)));
     }
 
-    saveIdentity (identifier, identity_key) {
+    saveIdentity(identifier, identity_key) {
         if (identifier === null || identifier === undefined) {
             throw new Error("Can't save identity_key for invalid identifier");
         }
-        const { libsignal } = /** @type WindowWithLibsignal */(window);
+        const { libsignal } = /** @type WindowWithLibsignal */ (window);
         const address = new libsignal.SignalProtocolAddress.fromString(identifier);
-        const existing = this.get('identity_key' + address.getName());
+        const existing = this.get("identity_key" + address.getName());
         const b64_idkey = u.arrayBufferToBase64(identity_key);
-        this.save('identity_key' + address.getName(), b64_idkey);
+        this.save("identity_key" + address.getName(), b64_idkey);
 
         if (existing && b64_idkey !== existing) {
             return Promise.resolve(true);
@@ -68,154 +66,154 @@ class OMEMOStore extends Model {
         }
     }
 
-    getPreKeys () {
-        return this.get('prekeys') || {};
+    getPreKeys() {
+        return this.get("prekeys") || {};
     }
 
-    loadPreKey (key_id) {
+    loadPreKey(key_id) {
         const res = this.getPreKeys()[key_id];
         if (res) {
             return Promise.resolve({
-                'privKey': u.base64ToArrayBuffer(res.privKey),
-                'pubKey': u.base64ToArrayBuffer(res.pubKey)
+                "privKey": u.base64ToArrayBuffer(res.privKey),
+                "pubKey": u.base64ToArrayBuffer(res.pubKey),
             });
         }
         return Promise.resolve();
     }
 
-    storePreKey (key_id, key_pair) {
+    storePreKey(key_id, key_pair) {
         const prekey = {};
         prekey[key_id] = {
-            'pubKey': u.arrayBufferToBase64(key_pair.pubKey),
-            'privKey': u.arrayBufferToBase64(key_pair.privKey)
+            "pubKey": u.arrayBufferToBase64(key_pair.pubKey),
+            "privKey": u.arrayBufferToBase64(key_pair.privKey),
         };
-        this.save('prekeys', Object.assign(this.getPreKeys(), prekey));
+        this.save("prekeys", Object.assign(this.getPreKeys(), prekey));
         return Promise.resolve();
     }
 
-    removePreKey (key_id) {
+    removePreKey(key_id) {
         const prekeys = { ...this.getPreKeys() };
         delete prekeys[key_id];
-        this.save('prekeys', prekeys);
+        this.save("prekeys", prekeys);
         return Promise.resolve();
     }
 
-    loadSignedPreKey (_keyId) {
-        const res = this.get('signed_prekey');
+    loadSignedPreKey(_keyId) {
+        const res = this.get("signed_prekey");
         if (res) {
             return Promise.resolve({
-                'privKey': u.base64ToArrayBuffer(res.privKey),
-                'pubKey': u.base64ToArrayBuffer(res.pubKey)
+                "privKey": u.base64ToArrayBuffer(res.privKey),
+                "pubKey": u.base64ToArrayBuffer(res.pubKey),
             });
         }
         return Promise.resolve();
     }
 
-    storeSignedPreKey (spk) {
-        if (typeof spk !== 'object') {
+    storeSignedPreKey(spk) {
+        if (typeof spk !== "object") {
             // XXX: We've changed the signature of this method from the
             // example given in InMemorySignalProtocolStore.
             // Should be fine because the libsignal code doesn't
             // actually call this method.
-            throw new Error('storeSignedPreKey: expected an object');
+            throw new Error("storeSignedPreKey: expected an object");
         }
-        this.save('signed_prekey', {
-            'id': spk.keyId,
-            'privKey': u.arrayBufferToBase64(spk.keyPair.privKey),
-            'pubKey': u.arrayBufferToBase64(spk.keyPair.pubKey),
+        this.save("signed_prekey", {
+            "id": spk.keyId,
+            "privKey": u.arrayBufferToBase64(spk.keyPair.privKey),
+            "pubKey": u.arrayBufferToBase64(spk.keyPair.pubKey),
             // XXX: The InMemorySignalProtocolStore does not pass
             // in or store the signature, but we need it when we
             // publish our bundle and this method isn't called from
             // within libsignal code, so we modify it to also store
             // the signature.
-            'signature': u.arrayBufferToBase64(spk.signature)
+            "signature": u.arrayBufferToBase64(spk.signature),
         });
         return Promise.resolve();
     }
 
-    removeSignedPreKey (key_id) {
-        if (this.get('signed_prekey')['id'] === key_id) {
-            this.unset('signed_prekey');
+    removeSignedPreKey(key_id) {
+        if (this.get("signed_prekey")["id"] === key_id) {
+            this.unset("signed_prekey");
             this.save();
         }
         return Promise.resolve();
     }
 
-    loadSession (identifier) {
-        return Promise.resolve(this.get('session' + identifier));
+    loadSession(identifier) {
+        return Promise.resolve(this.get("session" + identifier));
     }
 
-    storeSession (identifier, record) {
-        return Promise.resolve(this.save('session' + identifier, record));
+    storeSession(identifier, record) {
+        return Promise.resolve(this.save("session" + identifier, record));
     }
 
-    removeSession (identifier) {
-        return Promise.resolve(this.unset('session' + identifier));
+    removeSession(identifier) {
+        return Promise.resolve(this.unset("session" + identifier));
     }
 
-    removeAllSessions (identifier) {
-        const keys = Object.keys(this.attributes).filter(key =>
-            key.startsWith('session' + identifier) ? key : false
+    removeAllSessions(identifier) {
+        const keys = Object.keys(this.attributes).filter((key) =>
+            key.startsWith("session" + identifier) ? key : false
         );
         const attrs = {};
-        keys.forEach(key => { attrs[key] = undefined; });
+        keys.forEach((key) => {
+            attrs[key] = undefined;
+        });
         this.save(attrs);
         return Promise.resolve();
     }
 
-    publishBundle () {
-        const signed_prekey = this.get('signed_prekey');
-        const node = `${Strophe.NS.OMEMO_BUNDLES}:${this.get('device_id')}`;
-        const item = $build('item')
-            .c('bundle', { 'xmlns': Strophe.NS.OMEMO })
-                .c('signedPreKeyPublic', { 'signedPreKeyId': signed_prekey.id })
-                    .t(signed_prekey.pubKey).up()
-                .c('signedPreKeySignature')
-                    .t(signed_prekey.signature).up()
-                .c('identityKey')
-                    .t(this.get('identity_keypair').pubKey).up()
-                .c('prekeys');
-
-        Object.values(this.get('prekeys')).forEach((prekey, id) =>
-            item
-                .c('preKeyPublic', { 'preKeyId': id })
-                .t(prekey.pubKey)
-                .up()
+    publishBundle() {
+        const signed_prekey = this.get("signed_prekey");
+        const node = `${Strophe.NS.OMEMO_BUNDLES}:${this.get("device_id")}`;
+        const item = $build("item")
+            .c("bundle", { "xmlns": Strophe.NS.OMEMO })
+            .c("signedPreKeyPublic", { "signedPreKeyId": signed_prekey.id })
+            .t(signed_prekey.pubKey)
+            .up()
+            .c("signedPreKeySignature")
+            .t(signed_prekey.signature)
+            .up()
+            .c("identityKey")
+            .t(this.get("identity_keypair").pubKey)
+            .up()
+            .c("prekeys");
+
+        Object.values(this.get("prekeys")).forEach((prekey, id) =>
+            item.c("preKeyPublic", { "preKeyId": id }).t(prekey.pubKey).up()
         );
-        const options = { access_model: 'open' };
+        const options = { access_model: "open" };
         return api.pubsub.publish(null, node, item, options, false);
     }
 
-    async generateMissingPreKeys () {
-        const { libsignal } = /** @type WindowWithLibsignal */(window);
+    async generateMissingPreKeys() {
+        const { libsignal } = /** @type WindowWithLibsignal */ (window);
         const { KeyHelper } = libsignal;
 
         const prekeyIds = Object.keys(this.getPreKeys());
         const missing_keys = range(0, _converse.NUM_PREKEYS)
-            .map(id => id.toString())
-            .filter(id => !prekeyIds.includes(id));
+            .map((id) => id.toString())
+            .filter((id) => !prekeyIds.includes(id));
 
         if (missing_keys.length < 1) {
-            log.debug('No missing prekeys to generate for our own device');
+            log.debug("No missing prekeys to generate for our own device");
             return Promise.resolve();
         }
 
-        const keys = await Promise.all(
-            missing_keys.map(id => KeyHelper.generatePreKey(parseInt(id, 10)))
-        );
+        const keys = await Promise.all(missing_keys.map((id) => KeyHelper.generatePreKey(parseInt(id, 10))));
         keys.forEach((k) => this.storePreKey(k.keyId, k.keyPair));
 
         const prekeys = this.getPreKeys();
         const marshalled_keys = Object.keys(prekeys).map((id) => ({
             id,
-            key: prekeys[id].pubKey
+            key: prekeys[id].pubKey,
         }));
 
-        const bare_jid = _converse.session.get('bare_jid');
+        const bare_jid = _converse.session.get("bare_jid");
         const devicelist = await api.omemo.devicelists.get(bare_jid);
-        const device = devicelist.devices.get(this.get('device_id'));
+        const device = devicelist.devices.get(this.get("device_id"));
         const bundle = await device.getBundle();
-        device.save('bundle', Object.assign(bundle, { 'prekeys': marshalled_keys }));
+        device.save("bundle", Object.assign(bundle, { "prekeys": marshalled_keys }));
     }
 
     /**
@@ -228,19 +226,17 @@ class OMEMOStore extends Model {
      * to use a pre-key, which it chooses randomly from the list of available
      * ones.
      */
-    async generatePreKeys () {
+    async generatePreKeys() {
         const amount = _converse.NUM_PREKEYS;
-        const { libsignal } = /** @type WindowWithLibsignal */(window);
+        const { libsignal } = /** @type WindowWithLibsignal */ (window);
         const { KeyHelper } = libsignal;
-        const keys = await Promise.all(
-            range(0, amount).map(id => KeyHelper.generatePreKey(id))
-        );
+        const keys = await Promise.all(range(0, amount).map((id) => KeyHelper.generatePreKey(id)));
 
-        keys.forEach(k => this.storePreKey(k.keyId, k.keyPair));
+        keys.forEach((k) => this.storePreKey(k.keyId, k.keyPair));
 
-        return keys.map(k => ({
-            'id': k.keyId,
-            'key': u.arrayBufferToBase64(k.keyPair.pubKey)
+        return keys.map((k) => ({
+            "id": k.keyId,
+            "key": u.arrayBufferToBase64(k.keyPair.pubKey),
         }));
     }
 
@@ -252,8 +248,8 @@ class OMEMOStore extends Model {
      * clients to download it and start asynchronous encrypted sessions with us,
      * even if we're offline at that time.
      */
-    async generateBundle () {
-        const { libsignal } = /** @type WindowWithLibsignal */(window);
+    async generateBundle() {
+        const { libsignal } = /** @type WindowWithLibsignal */ (window);
 
         // The first thing that needs to happen if a client wants to
         // start using OMEMO is they need to generate an IdentityKey
@@ -267,12 +263,12 @@ class OMEMOStore extends Model {
         const device_id = await generateDeviceID();
 
         this.save({
-            'device_id': device_id,
-            'identity_keypair': {
-                'privKey': u.arrayBufferToBase64(identity_keypair.privKey),
-                'pubKey': identity_key
+            "device_id": device_id,
+            "identity_keypair": {
+                "privKey": u.arrayBufferToBase64(identity_keypair.privKey),
+                "pubKey": identity_key,
             },
-            'identity_key': identity_key
+            "identity_key": identity_key,
         });
 
         const signed_prekey = await libsignal.KeyHelper.generateSignedPreKey(identity_keypair, 0);
@@ -281,37 +277,37 @@ class OMEMOStore extends Model {
         const prekeys = await this.generatePreKeys();
 
         const bundle = { identity_key, device_id, prekeys };
-        bundle['signed_prekey'] = {
-            'id': signed_prekey.keyId,
-            'public_key': u.arrayBufferToBase64(signed_prekey.keyPair.pubKey),
-            'signature': u.arrayBufferToBase64(signed_prekey.signature)
+        bundle["signed_prekey"] = {
+            "id": signed_prekey.keyId,
+            "public_key": u.arrayBufferToBase64(signed_prekey.keyPair.pubKey),
+            "signature": u.arrayBufferToBase64(signed_prekey.signature),
         };
 
-        const bare_jid = _converse.session.get('bare_jid');
+        const bare_jid = _converse.session.get("bare_jid");
         const devicelist = await api.omemo.devicelists.get(bare_jid);
         const device = await devicelist.devices.create(
-            { 'id': bundle.device_id, 'jid': bare_jid },
-            { 'promise': true }
+            { "id": bundle.device_id, "jid": bare_jid },
+            { "promise": true }
         );
-        device.save('bundle', bundle);
+        device.save("bundle", bundle);
     }
 
-    fetchSession () {
+    fetchSession() {
         if (this._setup_promise === undefined) {
             this._setup_promise = new Promise((resolve, reject) => {
                 this.fetch({
-                    'success': () => {
-                        if (!this.get('device_id')) {
+                    "success": () => {
+                        if (!this.get("device_id")) {
                             this.generateBundle().then(resolve).catch(reject);
                         } else {
                             resolve();
                         }
                     },
-                    'error': (model, resp) => {
+                    "error": (model, resp) => {
                         log.warn("Could not fetch OMEMO session from cache, we'll generate a new one.");
                         log.warn(resp);
                         this.generateBundle().then(resolve).catch(reject);
-                    }
+                    },
                 });
             });
         }

+ 43 - 25
src/plugins/omemo/templates/fingerprints.js

@@ -1,7 +1,7 @@
-import { __ } from 'i18n';
-import { html } from 'lit';
-import { formatFingerprint } from '../utils.js';
-import { converse } from '@converse/headless';
+import { __ } from "i18n";
+import { html } from "lit";
+import { formatFingerprint } from "../utils.js";
+import { converse } from "@converse/headless";
 
 const { u } = converse.env;
 
@@ -10,51 +10,69 @@ const { u } = converse.env;
  * @param {import('../device').default} device
  */
 const device_fingerprint = (el, device) => {
-    const i18n_trusted = __('Trusted');
-    const i18n_untrusted = __('Untrusted');
-    const i18n_toggle_trusted_devices = __('Choose which devices you trust for OMEMO encrypted communication');
+    const i18n_trusted = __("Trusted");
+    const i18n_untrusted = __("Untrusted");
+    const i18n_toggle_trusted_devices = __("Choose which devices you trust for OMEMO encrypted communication");
 
     const id1 = u.getUniqueId();
     const id2 = u.getUniqueId();
-    const is_trusted = device.get('trusted') !== -1;
+    const is_trusted = device.get("trusted") !== -1;
 
-    if (device.get('bundle') && device.get('bundle').fingerprint) {
+    if (device.get("bundle") && device.get("bundle").fingerprint) {
         return html`
             <li class="list-group-item">
                 <form class="fingerprint-trust">
                     <div class="btn-group btn-group-toggle" role="group" aria-label="${i18n_toggle_trusted_devices}">
-                        <input type="radio" class="btn-check" name="${device.get('id')}" id="${id1}" autocomplete="off" value="1"
-                                @click=${el.toggleDeviceTrust}
-                                ?checked=${is_trusted}>
-                        <label class="btn ${is_trusted ? 'btn-primary active' : 'btn-outline-secondary'}" for="${id1}">${i18n_trusted}</label>
+                        <input
+                            type="radio"
+                            class="btn-check"
+                            name="${device.get("id")}"
+                            id="${id1}"
+                            autocomplete="off"
+                            value="1"
+                            @click=${el.toggleDeviceTrust}
+                            ?checked=${is_trusted}
+                        />
+                        <label class="btn ${is_trusted ? "btn-primary active" : "btn-outline-secondary"}" for="${id1}"
+                            >${i18n_trusted}</label
+                        >
 
-                        <input type="radio" class="btn-check" name="${device.get('id')}" id="${id2}" autocomplete="off" value="-1"
-                                @click=${el.toggleDeviceTrust}
-                                ?checked=${!is_trusted}>
-                        <label class="btn ${!is_trusted ? 'btn-primary active' : 'btn-outline-secondary'}" for="${id2}">${i18n_untrusted}</label>
+                        <input
+                            type="radio"
+                            class="btn-check"
+                            name="${device.get("id")}"
+                            id="${id2}"
+                            autocomplete="off"
+                            value="-1"
+                            @click=${el.toggleDeviceTrust}
+                            ?checked=${!is_trusted}
+                        />
+                        <label class="btn ${!is_trusted ? "btn-primary active" : "btn-outline-secondary"}" for="${id2}"
+                            >${i18n_untrusted}</label
+                        >
                     </div>
-                    <code class="fingerprint">${formatFingerprint(device.get('bundle').fingerprint)}</code>
+                    <code class="fingerprint">${formatFingerprint(device.get("bundle").fingerprint)}</code>
                 </form>
             </li>
         `;
     } else {
-        return ''
+        return "";
     }
-}
+};
 
 /**
  * @param {import('../fingerprints').Fingerprints} el
  */
 export default (el) => {
-    const i18n_fingerprints = __('OMEMO Fingerprints');
+    const i18n_fingerprints = __("OMEMO Fingerprints");
     const i18n_no_devices = __("No OMEMO-enabled devices found");
     const devices = el.devicelist.devices;
     return html`
         <ul class="list-group fingerprints">
             <li class="list-group-item active">${i18n_fingerprints}</li>
-            ${ devices.length ?
-                devices.map(device => device_fingerprint(el, device)) :
-                html`<li class="list-group-item"> ${i18n_no_devices} </li>` }
+            ${devices.length
+                ? devices.map((device) => device_fingerprint(el, device))
+                : html`<li class="list-group-item">${i18n_no_devices}</li>`}
         </ul>
     `;
-}
+};

+ 104 - 69
src/plugins/omemo/tests/omemo.js

@@ -493,62 +493,83 @@ describe("The OMEMO module", function() {
 
         // Wait until own devices are fetched
         let iq_stanza = await u.waitUntil(() => mock.deviceListFetched(_converse, _converse.bare_jid));
-        expect(iq_stanza).toEqualStanza(
-            stx`<iq from="romeo@montague.lit" id="${iq_stanza.getAttribute("id")}" to="romeo@montague.lit" type="get" xmlns="jabber:client">
+        expect(iq_stanza).toEqualStanza(stx`
+            <iq from="romeo@montague.lit"
+                    id="${iq_stanza.getAttribute("id")}"
+                    to="romeo@montague.lit"
+                    type="get"
+                    xmlns="jabber:client">
                 <pubsub xmlns="http://jabber.org/protocol/pubsub">
                     <items node="eu.siacs.conversations.axolotl.devicelist"/>
                 </pubsub>
             </iq>`);
 
-        let stanza = $iq({
-            'from': _converse.bare_jid,
-            'id': iq_stanza.getAttribute('id'),
-            'to': _converse.bare_jid,
-            'type': 'result',
-        }).c('pubsub', {'xmlns': "http://jabber.org/protocol/pubsub"})
-            .c('items', {'node': "eu.siacs.conversations.axolotl.devicelist"})
-                .c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
-                    .c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
-                        .c('device', {'id': '555'});
+        let stanza = stx`
+            <iq from="${_converse.bare_jid}"
+                id="${iq_stanza.getAttribute('id')}"
+                to="${_converse.bare_jid}"
+                type="result"
+                xmlns="jabber:client">
+            <pubsub xmlns="http://jabber.org/protocol/pubsub">
+                <items node="eu.siacs.conversations.axolotl.devicelist">
+                    <item xmlns="http://jabber.org/protocol/pubsub"> <!-- TODO: must have an id attribute -->
+                        <list xmlns="eu.siacs.conversations.axolotl">
+                            <device id="555"/>
+                        </list>
+                    </item>
+                </items>
+            </pubsub>
+        </iq>`;
         _converse.api.connection.get()._dataRecv(mock.createRequest(stanza));
         await u.waitUntil(() => _converse.state.omemo_store);
+
         expect(_converse.chatboxes.length).toBe(1);
         expect(_converse.state.devicelists.length).toBe(1);
+
         const devicelist = _converse.state.devicelists.get(_converse.bare_jid);
         expect(devicelist.devices.length).toBe(2);
         expect(devicelist.devices.at(0).get('id')).toBe('555');
         expect(devicelist.devices.at(1).get('id')).toBe('123456789');
         iq_stanza = await u.waitUntil(() => mock.ownDeviceHasBeenPublished(_converse));
-        stanza = $iq({
-            'from': _converse.bare_jid,
-            'id': iq_stanza.getAttribute('id'),
-            'to': _converse.bare_jid,
-            'type': 'result'});
+
+        stanza = stx`
+            <iq xmlns="jabber:client"
+                from="${_converse.bare_jid}"
+                id="${iq_stanza.getAttribute('id')}"
+                to="${_converse.bare_jid}"
+                type="result"/>`;
         _converse.api.connection.get()._dataRecv(mock.createRequest(stanza));
+
         iq_stanza = await u.waitUntil(() => mock.bundleHasBeenPublished(_converse));
 
-        stanza = $iq({
-            'from': _converse.bare_jid,
-            'id': iq_stanza.getAttribute('id'),
-            'to': _converse.bare_jid,
-            'type': 'result'});
+        stanza = stx`
+            <iq xmlns="jabber:client"
+                from="${_converse.bare_jid}"
+                id="${iq_stanza.getAttribute('id')}"
+                to="${_converse.bare_jid}"
+                type="result"/>`;
         _converse.api.connection.get()._dataRecv(mock.createRequest(stanza));
         await _converse.api.waitUntil('OMEMOInitialized');
 
 
         // A PEP message is received with a device list.
-        _converse.api.connection.get()._dataRecv(mock.createRequest($msg({
-            'from': contact_jid,
-            'to': _converse.bare_jid,
-            'type': 'headline',
-            'id': 'update_01',
-        }).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
-            .c('items', {'node': 'eu.siacs.conversations.axolotl.devicelist'})
-                .c('item')
-                    .c('list', {'xmlns': 'eu.siacs.conversations.axolotl'})
-                        .c('device', {'id': '1234'}).up()
-                        .c('device', {'id': '4223'})
-        ));
+        _converse.api.connection.get()._dataRecv(mock.createRequest(stx`
+            <message xmlns="jabber:client"
+                    from="${contact_jid}"
+                    to="${_converse.bare_jid}"
+                    type="headline"
+                    id="update_01">
+                <event xmlns="http://jabber.org/protocol/pubsub#event">
+                    <items node="eu.siacs.conversations.axolotl.devicelist">
+                        <item id="current">
+                            <list xmlns="eu.siacs.conversations.axolotl">
+                                <device id="1234"/>
+                                <device id="4223"/>
+                            </list>
+                        </item>
+                    </items>
+                </event>
+            </message>`));
 
         // Since we haven't yet fetched any devices for this user, the
         // devicelist model for them isn't yet initialized.
@@ -679,7 +700,6 @@ describe("The OMEMO module", function() {
         expect(devices.get('777').get('active')).toBe(false);
     }));
 
-
     it("updates device bundles based on PEP messages",
             mock.initConverse([], {}, async function (_converse) {
 
@@ -693,24 +713,33 @@ describe("The OMEMO module", function() {
 
         const contact_jid = mock.cur_names[3].replace(/ /g,'.').toLowerCase() + '@montague.lit';
         let iq_stanza = await u.waitUntil(() => mock.deviceListFetched(_converse, _converse.bare_jid));
-        expect(Strophe.serialize(iq_stanza)).toBe(
-            `<iq from="romeo@montague.lit" id="${iq_stanza.getAttribute("id")}" to="romeo@montague.lit" type="get" xmlns="jabber:client">`+
-                `<pubsub xmlns="http://jabber.org/protocol/pubsub">`+
-                    `<items node="eu.siacs.conversations.axolotl.devicelist"/>`+
-                `</pubsub>`+
-            `</iq>`);
+        expect(iq_stanza).toEqualStanza(stx`
+            <iq from="romeo@montague.lit"
+                    id="${iq_stanza.getAttribute("id")}"
+                    to="romeo@montague.lit"
+                    type="get"
+                    xmlns="jabber:client">
+                <pubsub xmlns="http://jabber.org/protocol/pubsub">
+                    <items node="eu.siacs.conversations.axolotl.devicelist"/>
+                </pubsub>
+            </iq>`);
 
-        _converse.api.connection.get()._dataRecv(mock.createRequest($iq({
-            'from': contact_jid,
-            'id': iq_stanza.getAttribute('id'),
-            'to': _converse.bare_jid,
-            'type': 'result',
-        }).c('pubsub', {'xmlns': "http://jabber.org/protocol/pubsub"})
-            .c('items', {'node': "eu.siacs.conversations.axolotl.devicelist"})
-                .c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
-                    .c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
-                        .c('device', {'id': '555'})
-        ));
+        _converse.api.connection.get()._dataRecv(mock.createRequest(stx`
+            <iq from="${contact_jid}"
+                id="${iq_stanza.getAttribute('id')}"
+                to="${_converse.bare_jid}"
+                xmlns="jabber:client"
+                type="result">
+                <pubsub xmlns="http://jabber.org/protocol/pubsub">
+                    <items node="eu.siacs.conversations.axolotl.devicelist">
+                        <item xmlns="http://jabber.org/protocol/pubsub"> <!-- TODO: must have an id attribute -->
+                            <list xmlns="eu.siacs.conversations.axolotl">
+                                <device id="555"/>
+                            </list>
+                        </item>
+                    </items>
+                </pubsub>
+            </iq>`));
 
         await await u.waitUntil(() => _converse.state.omemo_store);
         expect(_converse.state.devicelists.length).toBe(1);
@@ -734,23 +763,29 @@ describe("The OMEMO module", function() {
         _converse.api.connection.get()._dataRecv(mock.createRequest(stanza));
         await _converse.api.waitUntil('OMEMOInitialized');
 
-        _converse.api.connection.get()._dataRecv(mock.createRequest($msg({
-            'from': contact_jid,
-            'to': _converse.bare_jid,
-            'type': 'headline',
-            'id': 'update_01',
-        }).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
-            .c('items', {'node': 'eu.siacs.conversations.axolotl.bundles:1234'})
-                .c('item')
-                    .c('bundle', {'xmlns': 'eu.siacs.conversations.axolotl'})
-                        .c('signedPreKeyPublic', {'signedPreKeyId': '4223'}).t('1111').up()
-                        .c('signedPreKeySignature').t('2222').up()
-                        .c('identityKey').t('3333').up()
-                        .c('prekeys')
-                            .c('preKeyPublic', {'preKeyId': '1001'}).up()
-                            .c('preKeyPublic', {'preKeyId': '1002'}).up()
-                            .c('preKeyPublic', {'preKeyId': '1003'})
-        ));
+        _converse.api.connection.get()._dataRecv(mock.createRequest(stx`
+            <message from="${contact_jid}"
+                    to="${_converse.bare_jid}"
+                    type="headline"
+                    id="update_01"
+                    xmlns="jabber:client">
+                <event xmlns="http://jabber.org/protocol/pubsub#event">
+                    <items node="eu.siacs.conversations.axolotl.bundles:1234">
+                        <item>
+                            <bundle xmlns="eu.siacs.conversations.axolotl">
+                                <signedPreKeyPublic signedPreKeyId="4223">1111</signedPreKeyPublic>
+                                <signedPreKeySignature>2222</signedPreKeySignature>
+                                <identityKey>3333</identityKey>
+                                <prekeys>
+                                    <preKeyPublic preKeyId="1001"/>
+                                    <preKeyPublic preKeyId="1002"/>
+                                    <preKeyPublic preKeyId="1003"/>
+                                </prekeys>
+                            </bundle>
+                        </item>
+                    </items>
+                </event>
+            </message>`));
 
         // Since we haven't yet fetched any devices for this user, the
         // devicelist model for them isn't yet initialized.

Diff do ficheiro suprimidas por serem muito extensas
+ 267 - 255
src/plugins/omemo/utils.js


+ 1 - 1
src/types/plugins/omemo/api.d.ts

@@ -9,7 +9,7 @@ declare namespace _default {
         }
         namespace devicelists {
             /**
-             * Returns the {@link _converse.DeviceList} for a particular JID.
+             * Returns the {@link DeviceList} for a particular JID.
              * The device list will be created if it doesn't exist already.
              * @method _converse.api.omemo.devicelists.get
              * @param {String} jid - The Jabber ID for which the device list will be returned.

+ 1 - 1
src/types/plugins/omemo/device.d.ts

@@ -23,5 +23,5 @@ declare class Device extends Model {
      */
     getBundle(): Promise<import("./types").Bundle>;
 }
-import { Model } from '@converse/skeletor';
+import { Model } from "@converse/skeletor";
 //# sourceMappingURL=device.d.ts.map

+ 5 - 2
src/types/plugins/omemo/devicelist.d.ts

@@ -4,7 +4,10 @@ declare class DeviceList extends Model {
     initialized: any;
     initDevices(): Promise<any>;
     devices: any;
-    onDevicesFound(collection: any): Promise<void>;
+    /**
+     * @param {import('./devices').default} collection
+     */
+    onDevicesFound(collection: import("./devices").default): Promise<void>;
     fetchDevices(): Promise<any>;
     _devices_promise: Promise<any>;
     /**
@@ -30,5 +33,5 @@ declare class DeviceList extends Model {
      */
     removeOwnDevices(device_ids: string[]): Promise<any>;
 }
-import { Model } from '@converse/skeletor';
+import { Model } from "@converse/skeletor";
 //# sourceMappingURL=devicelist.d.ts.map

+ 2 - 2
src/types/plugins/omemo/devicelists.d.ts

@@ -3,6 +3,6 @@ declare class DeviceLists extends Collection {
     constructor();
     model: typeof DeviceList;
 }
-import { Collection } from '@converse/skeletor';
-import DeviceList from './devicelist.js';
+import { Collection } from "@converse/skeletor";
+import DeviceList from "./devicelist.js";
 //# sourceMappingURL=devicelists.d.ts.map

+ 2 - 2
src/types/plugins/omemo/devices.d.ts

@@ -3,6 +3,6 @@ declare class Devices extends Collection {
     constructor();
     model: typeof Device;
 }
-import { Collection } from '@converse/skeletor';
-import Device from './device.js';
+import { Collection } from "@converse/skeletor";
+import Device from "./device.js";
 //# sourceMappingURL=devices.d.ts.map

+ 1 - 1
src/types/plugins/omemo/fingerprints.d.ts

@@ -10,5 +10,5 @@ export class Fingerprints extends CustomElement {
     render(): import("lit").TemplateResult<1> | "";
     toggleDeviceTrust(ev: any): void;
 }
-import { CustomElement } from 'shared/components/element.js';
+import { CustomElement } from "shared/components/element.js";
 //# sourceMappingURL=fingerprints.d.ts.map

+ 1 - 1
src/types/plugins/omemo/profile.d.ts

@@ -10,5 +10,5 @@ export class Profile extends CustomElement {
     removeSelectedFingerprints(ev: any): Promise<void>;
     generateOMEMODeviceBundle(ev: any): Promise<void>;
 }
-import { CustomElement } from 'shared/components/element.js';
+import { CustomElement } from "shared/components/element.js";
 //# sourceMappingURL=profile.d.ts.map

+ 1 - 1
src/types/plugins/omemo/store.d.ts

@@ -55,5 +55,5 @@ declare class OMEMOStore extends Model {
     fetchSession(): Promise<any>;
     _setup_promise: Promise<any>;
 }
-import { Model } from '@converse/skeletor';
+import { Model } from "@converse/skeletor";
 //# sourceMappingURL=store.d.ts.map

+ 6 - 3
src/types/plugins/omemo/utils.d.ts

@@ -87,6 +87,9 @@ export function generateDeviceID(): Promise<any>;
  * @param {import('./device.js').default} device
  */
 export function getSession(device: import("./device.js").default): Promise<any>;
+/**
+ * Register a pubsub handler for devices pushed from other connected clients
+ */
 export function registerPEPPushHandler(): void;
 export function restoreOMEMOSession(): Promise<void>;
 /**
@@ -120,9 +123,9 @@ export type MessageAttributes = import("@converse/headless/shared/types").Messag
 export type MUCMessageAttributes = import("@converse/headless/plugins/muc/types").MUCMessageAttributes;
 export type ChatBox = import("@converse/headless").ChatBox;
 export type BaseMessage = import("@converse/headless").BaseMessage<any>;
-import { IQError } from 'shared/errors.js';
-import { UserFacingError } from 'shared/errors.js';
-import { MUC } from '@converse/headless';
+import { IQError } from "shared/errors.js";
+import { UserFacingError } from "shared/errors.js";
+import { MUC } from "@converse/headless";
 /**
  * @param {import('./types').EncryptedMessage} obj
  * @returns {Promise<string>}

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff