Browse Source

Custom errors

JC Brand 1 year ago
parent
commit
507a1f0670

+ 1 - 1
src/plugins/chatview/tests/chatbox.js

@@ -248,7 +248,7 @@ describe("Chatboxes", function () {
 
         describe("A chat toolbar", function () {
 
-            fit("shows the remaining character count if a message_limit is configured",
+            it("shows the remaining character count if a message_limit is configured",
                     mock.initConverse(['chatBoxesFetched'], {'message_limit': 200}, async function (_converse) {
 
                 await mock.waitForRoster(_converse, 'current', 3);

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

@@ -1,4 +1,4 @@
-import { IQError } from './errors.js';
+import { IQError } from 'shared/errors.js';
 import { Model } from '@converse/skeletor';
 import { UNDECIDED } from './consts.js';
 import { _converse, api, converse, log } from '@converse/headless';

+ 0 - 7
src/plugins/omemo/errors.js

@@ -1,7 +0,0 @@
-export class IQError extends Error {
-    constructor (message, iq) {
-        super(message);
-        this.name = 'IQError';
-        this.iq = iq;
-    }
-}

+ 28 - 11
src/plugins/omemo/utils.js

@@ -1,5 +1,8 @@
 /**
  * @typedef {module:plugins-omemo-index.WindowWithLibsignal} WindowWithLibsignal
+ * @typedef {module:plugin-chat-parsers.MessageAttributes} MessageAttributes
+ * @typedef {module:plugin-muc-parsers.MUCMessageAttributes} MUCMessageAttributes
+ * @typedef {import('@converse/headless/plugins/chat/model.js').default} ChatBox
  */
 import tplAudio from 'templates/audio.js';
 import tplFile from 'templates/file.js';
@@ -24,6 +27,8 @@ import {
     hexToArrayBuffer,
     stringToArrayBuffer
 } from '@converse/headless/utils/arraybuffer.js';
+import MUC from 'headless/plugins/muc/muc.js';
+import {IQError, UserFacingError} from 'shared/errors.js';
 
 const { Strophe, URI, sizzle, u } = converse.env;
 
@@ -36,8 +41,12 @@ export function formatFingerprint (fp) {
     return fp;
 }
 
+/**
+ * @param {Error|IQError|UserFacingError} e
+ * @param {ChatBox} chat
+ */
 export function handleMessageSendError (e, chat) {
-    if (e.name === 'IQError') {
+    if (e instanceof IQError) {
         chat.save('omemo_supported', false);
 
         const err_msgs = [];
@@ -61,7 +70,7 @@ export function handleMessageSendError (e, chat) {
             err_msgs.push(e.iq.outerHTML);
         }
         api.alert('error', __('Error'), err_msgs);
-    } else if (e.user_facing) {
+    } else if (e instanceof UserFacingError) {
         api.alert('error', __('Error'), [e.message]);
     }
     throw e;
@@ -79,6 +88,9 @@ export function getOutgoingMessageAttributes (chat, attrs) {
     return attrs;
 }
 
+/**
+ * @param {string} plaintext
+ */
 async function encryptMessage (plaintext) {
     // The client MUST use fresh, randomly generated key/IV pairs
     // with AES-128 in Galois/Counter Mode (GCM).
@@ -122,13 +134,18 @@ async function decryptMessage (obj) {
     return arrayBufferToString(await crypto.subtle.decrypt(algo, key_obj, cipher));
 }
 
+/**
+ * @param {File} file
+ * @returns {Promise<File>}
+ */
 export async function encryptFile (file) {
     const iv = crypto.getRandomValues(new Uint8Array(12));
     const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256, }, true, ['encrypt', 'decrypt']);
     const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv, }, key, await file.arrayBuffer());
     const exported_key = await window.crypto.subtle.exportKey('raw', key);
     const encrypted_file = new File([encrypted], file.name, { type: file.type, lastModified: file.lastModified });
-    encrypted_file.xep454_ivkey = arrayBufferToHex(iv) + arrayBufferToHex(exported_key);
+
+    Object.assign(encrypted_file, { xep454_ivkey: arrayBufferToHex(iv) + arrayBufferToHex(exported_key) });
     return encrypted_file;
 }
 
@@ -327,8 +344,9 @@ export function onChatInitialized (el) {
 }
 
 export function getSessionCipher (jid, id) {
+    const { libsignal } = /** @type WindowWithLibsignal */(window);
     const address = new libsignal.SignalProtocolAddress(jid, id);
-    return new window.libsignal.SessionCipher(_converse.omemo_store, address);
+    return new libsignal.SessionCipher(_converse.omemo_store, address);
 }
 
 function getJIDForDecryption (attrs) {
@@ -780,18 +798,19 @@ export function getOMEMOToolbarButton (toolbar_el, buttons) {
 }
 
 
+/**
+ * @param {MUC|ChatBox} chatbox
+ */
 async function getBundlesAndBuildSessions (chatbox) {
     const no_devices_err = __('Sorry, no devices found to which we can send an OMEMO encrypted message.');
     let devices;
-    if (chatbox.get('type') === CHATROOMS_TYPE) {
+    if (chatbox instanceof MUC) {
         const collections = await Promise.all(chatbox.occupants.map(o => getDevicesForContact(o.get('jid'))));
         devices = collections.reduce((a, b) => a.concat(b.models), []);
     } else if (chatbox.get('type') === PRIVATE_CHAT_TYPE) {
         const their_devices = await getDevicesForContact(chatbox.get('jid'));
         if (their_devices.length === 0) {
-            const err = new Error(no_devices_err);
-            err.user_facing = true;
-            throw err;
+            throw new UserFacingError(no_devices_err);
         }
         const own_list = await api.omemo.devicelists.get(_converse.bare_jid)
         const own_devices = own_list.devices;
@@ -809,9 +828,7 @@ async function getBundlesAndBuildSessions (chatbox) {
         // We couldn't build a session for certain devices.
         devices = devices.filter(d => sessions[devices.indexOf(d)]);
         if (devices.length === 0) {
-            const err = new Error(no_devices_err);
-            err.user_facing = true;
-            throw err;
+            throw new UserFacingError(no_devices_err);
         }
     }
     return devices;

+ 23 - 0
src/shared/errors.js

@@ -0,0 +1,23 @@
+export class IQError extends Error {
+    /**
+     * @param {string} message
+     * @param {Element} iq
+     */
+    constructor (message, iq) {
+        super(message);
+        this.name = 'IQError';
+        this.iq = iq;
+    }
+}
+
+export class UserFacingError extends Error {
+
+    /**
+     * @param {string} message
+     */
+    constructor (message) {
+        super(message);
+        this.name = 'UserFacingError';
+        this.user_facing = true;
+    }
+}