Explorar el Código

fix(ChatRoom) filter out bogus reaction emojis

master
Saúl Ibarra Corretgé hace 4 meses
padre
commit
b67e3d3fff
Se han modificado 4 ficheros con 185 adiciones y 12 borrados
  1. 21
    3
      modules/xmpp/ChatRoom.js
  2. 140
    1
      modules/xmpp/ChatRoom.spec.js
  3. 23
    8
      package-lock.json
  4. 1
    0
      package.json

+ 21
- 3
modules/xmpp/ChatRoom.js Ver fichero

@@ -1,4 +1,5 @@
1 1
 import { getLogger } from '@jitsi/logger';
2
+import emojiRegex from 'emoji-regex';
2 3
 import $ from 'jquery';
3 4
 import { isEqual } from 'lodash-es';
4 5
 import { $iq, $msg, $pres, Strophe } from 'strophe.js';
@@ -24,6 +25,11 @@ import { FEATURE_TRANSCRIBER } from './xmpp';
24 25
 
25 26
 const logger = getLogger('modules/xmpp/ChatRoom');
26 27
 
28
+/**
29
+ * Regex that matches all emojis.
30
+ */
31
+const EMOJI_REGEX = emojiRegex();
32
+
27 33
 /**
28 34
  * How long we're going to wait for IQ response, before timeout error is triggered.
29 35
  * @type {number}
@@ -981,6 +987,12 @@ export default class ChatRoom extends Listenable {
981 987
      * @param {string} receiverId - The receiver of the message if it is private.
982 988
      */
983 989
     sendReaction(reaction, messageId, receiverId) {
990
+        const m = reaction.match(EMOJI_REGEX);
991
+
992
+        if (!m || !m[0]) {
993
+            throw new Error(`Invalid reaction: ${reaction}`);
994
+        }
995
+
984 996
         // Adds the 'to' attribute depending on if the message is private or not.
985 997
         const msg = receiverId ? $msg({ to: `${this.roomjid}/${receiverId}`,
986 998
             type: 'chat' }) : $msg({ to: this.roomjid,
@@ -988,7 +1000,7 @@ export default class ChatRoom extends Listenable {
988 1000
 
989 1001
         msg.c('reactions', { id: messageId,
990 1002
             xmlns: 'urn:xmpp:reactions:0' })
991
-            .c('reaction', {}, reaction)
1003
+            .c('reaction', {}, m[0])
992 1004
             .up().c('store', { xmlns: 'urn:xmpp:hints' });
993 1005
 
994 1006
         this.connection.send(msg);
@@ -1203,11 +1215,17 @@ export default class ChatRoom extends Listenable {
1203 1215
 
1204 1216
             reactions.each((_, reactionElem) => {
1205 1217
                 const reaction = $(reactionElem).text();
1218
+                const m = reaction.match(EMOJI_REGEX);
1206 1219
 
1207
-                reactionList.push(reaction);
1220
+                // Only allow one reaction per <reaction> element.
1221
+                if (m && m[0]) {
1222
+                    reactionList.push(m[0]);
1223
+                }
1208 1224
             });
1209 1225
 
1210
-            this.eventEmitter.emit(XMPPEvents.REACTION_RECEIVED, from, reactionList, messageId);
1226
+            if (reactionList.length > 0) {
1227
+                this.eventEmitter.emit(XMPPEvents.REACTION_RECEIVED, from, reactionList, messageId);
1228
+            }
1211 1229
 
1212 1230
             return true;
1213 1231
         }

+ 140
- 1
modules/xmpp/ChatRoom.spec.js Ver fichero

@@ -404,5 +404,144 @@ describe('ChatRoom', () => {
404 404
                 '</message>');
405 405
         });
406 406
     });
407
-});
408 407
 
408
+    describe('onMessage - reaction', () => {
409
+        let room;
410
+        let emitterSpy;
411
+
412
+        beforeEach(() => {
413
+            const xmpp = {
414
+                moderator: new Moderator({
415
+                    options: {}
416
+                }),
417
+                options: {},
418
+                addListener: () => {} // eslint-disable-line no-empty-function
419
+            };
420
+
421
+            room = new ChatRoom(
422
+                {} /* connection */,
423
+                'jid',
424
+                'password',
425
+                xmpp,
426
+                {} /* options */);
427
+            emitterSpy = spyOn(room.eventEmitter, 'emit');
428
+        });
429
+
430
+        it('parses reactions correctly', () => {
431
+            const msgStr = '' +
432
+                '<message to="jid" type="groupchat" xmlns="jabber:client">' +
433
+                    '<reactions id="mdgId123" xmlns="urn:xmpp:reactions:0">' +
434
+                        '<reaction>👍</reaction>' +
435
+                    '</reactions>' +
436
+                    '<store xmlns="urn:xmpp:hints"/>' +
437
+                '</message>';
438
+            const msg = new DOMParser().parseFromString(msgStr, 'text/xml').documentElement;
439
+
440
+            room.onMessage(msg, 'fromjid');
441
+            expect(emitterSpy.calls.count()).toEqual(1);
442
+            expect(emitterSpy).toHaveBeenCalledWith(
443
+                XMPPEvents.REACTION_RECEIVED,
444
+                'fromjid',
445
+                ['👍'],
446
+                'mdgId123');
447
+        });
448
+        it('parses multiple reactions correctly', () => {
449
+            const msgStr = '' +
450
+                '<message to="jid" type="groupchat" xmlns="jabber:client">' +
451
+                    '<reactions id="mdgId123" xmlns="urn:xmpp:reactions:0">' +
452
+                        '<reaction>👍</reaction>' +
453
+                        '<reaction>👎</reaction>' +
454
+                    '</reactions>' +
455
+                    '<store xmlns="urn:xmpp:hints"/>' +
456
+                '</message>';
457
+            const msg = new DOMParser().parseFromString(msgStr, 'text/xml').documentElement;
458
+
459
+            room.onMessage(msg, 'fromjid');
460
+            expect(emitterSpy.calls.count()).toEqual(1);
461
+            expect(emitterSpy).toHaveBeenCalledWith(
462
+                XMPPEvents.REACTION_RECEIVED,
463
+                'fromjid',
464
+                ['👍', '👎'],
465
+                'mdgId123');
466
+        });
467
+        it('parses partially bogus reactions correctly', () => {
468
+            const msgStr = '' +
469
+                '<message to="jid" type="groupchat" xmlns="jabber:client">' +
470
+                    '<reactions id="mdgId123" xmlns="urn:xmpp:reactions:0">' +
471
+                        '<reaction>👍 foo bar baz</reaction>' +
472
+                    '</reactions>' +
473
+                    '<store xmlns="urn:xmpp:hints"/>' +
474
+                '</message>';
475
+            const msg = new DOMParser().parseFromString(msgStr, 'text/xml').documentElement;
476
+
477
+            room.onMessage(msg, 'fromjid');
478
+            expect(emitterSpy.calls.count()).toEqual(1);
479
+            expect(emitterSpy).toHaveBeenCalledWith(
480
+                XMPPEvents.REACTION_RECEIVED,
481
+                'fromjid',
482
+                ['👍'],
483
+                'mdgId123');
484
+        });
485
+        it('parses bogus reactions correctly', () => {
486
+            const msgStr = '' +
487
+                '<message to="jid" type="groupchat" xmlns="jabber:client">' +
488
+                    '<reactions id="mdgId123" xmlns="urn:xmpp:reactions:0">' +
489
+                        '<reaction>foo bar baz</reaction>' +
490
+                    '</reactions>' +
491
+                    '<store xmlns="urn:xmpp:hints"/>' +
492
+                '</message>';
493
+            const msg = new DOMParser().parseFromString(msgStr, 'text/xml').documentElement;
494
+
495
+            room.onMessage(msg, 'fromjid');
496
+            expect(emitterSpy.calls.count()).toEqual(0);
497
+        });
498
+    });
499
+
500
+    describe('sendReaction', () => {
501
+        let room;
502
+        let connectionSpy;
503
+
504
+        beforeEach(() => {
505
+            const xmpp = {
506
+                moderator: new Moderator({
507
+                    options: {}
508
+                }),
509
+                options: {},
510
+                addListener: () => {} // eslint-disable-line no-empty-function
511
+            };
512
+
513
+            room = new ChatRoom(
514
+                // eslint-disable-next-line no-empty-function
515
+                { send: () => {} } /* connection */,
516
+                'jid',
517
+                'password',
518
+                xmpp,
519
+                {} /* options */);
520
+            connectionSpy = spyOn(room.connection, 'send');
521
+        });
522
+        it('sends a valid emoji reaction message', () => {
523
+            room.sendReaction('👍', 'mdgId123', 'participant1');
524
+            expect(connectionSpy.calls.argsFor(0).toString()).toBe(
525
+                '<message to="jid/participant1" type="chat" xmlns="jabber:client">' +
526
+                '<reactions id="mdgId123" xmlns="urn:xmpp:reactions:0"><reaction>👍</reaction></reactions>' +
527
+                '<store xmlns="urn:xmpp:hints"/></message>');
528
+        });
529
+        it('sends only valid emoji reaction message', () => {
530
+            room.sendReaction('I like this 👍', 'mdgId123', 'participant1');
531
+            expect(connectionSpy.calls.argsFor(0).toString()).toBe(
532
+                '<message to="jid/participant1" type="chat" xmlns="jabber:client">' +
533
+                '<reactions id="mdgId123" xmlns="urn:xmpp:reactions:0"><reaction>👍</reaction></reactions>' +
534
+                '<store xmlns="urn:xmpp:hints"/></message>');
535
+        });
536
+        it('sends only the first valid emoji reaction message', () => {
537
+            room.sendReaction('👍👎', 'mdgId123', 'participant1');
538
+            expect(connectionSpy.calls.argsFor(0).toString()).toBe(
539
+                '<message to="jid/participant1" type="chat" xmlns="jabber:client">' +
540
+                '<reactions id="mdgId123" xmlns="urn:xmpp:reactions:0"><reaction>👍</reaction></reactions>' +
541
+                '<store xmlns="urn:xmpp:hints"/></message>');
542
+        });
543
+        it('throws in case of invalid or no emoji', () => {
544
+            expect(() => room.sendReaction('foo bar baz', 'mdgId123', 'participant1')).toThrowError(/Invalid reaction/);
545
+        });
546
+    });
547
+});

+ 23
- 8
package-lock.json Ver fichero

@@ -17,6 +17,7 @@
17 17
         "async-es": "3.2.4",
18 18
         "base64-js": "1.5.1",
19 19
         "current-executing-script": "0.1.3",
20
+        "emoji-regex": "10.4.0",
20 21
         "jquery": "3.6.1",
21 22
         "lodash-es": "4.17.21",
22 23
         "sdp-transform": "2.3.0",
@@ -3905,10 +3906,10 @@
3905 3906
       "license": "ISC"
3906 3907
     },
3907 3908
     "node_modules/emoji-regex": {
3908
-      "version": "8.0.0",
3909
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
3910
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
3911
-      "dev": true
3909
+      "version": "10.4.0",
3910
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
3911
+      "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
3912
+      "license": "MIT"
3912 3913
     },
3913 3914
     "node_modules/emojis-list": {
3914 3915
       "version": "3.0.0",
@@ -7816,6 +7817,13 @@
7816 7817
         "node": ">=8"
7817 7818
       }
7818 7819
     },
7820
+    "node_modules/string-width/node_modules/emoji-regex": {
7821
+      "version": "8.0.0",
7822
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
7823
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
7824
+      "dev": true,
7825
+      "license": "MIT"
7826
+    },
7819 7827
     "node_modules/string.prototype.trim": {
7820 7828
       "version": "1.2.10",
7821 7829
       "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
@@ -11796,10 +11804,9 @@
11796 11804
       "dev": true
11797 11805
     },
11798 11806
     "emoji-regex": {
11799
-      "version": "8.0.0",
11800
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
11801
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
11802
-      "dev": true
11807
+      "version": "10.4.0",
11808
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
11809
+      "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="
11803 11810
     },
11804 11811
     "emojis-list": {
11805 11812
       "version": "3.0.0",
@@ -14510,6 +14517,14 @@
14510 14517
         "emoji-regex": "^8.0.0",
14511 14518
         "is-fullwidth-code-point": "^3.0.0",
14512 14519
         "strip-ansi": "^6.0.1"
14520
+      },
14521
+      "dependencies": {
14522
+        "emoji-regex": {
14523
+          "version": "8.0.0",
14524
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
14525
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
14526
+          "dev": true
14527
+        }
14513 14528
       }
14514 14529
     },
14515 14530
     "string.prototype.trim": {

+ 1
- 0
package.json Ver fichero

@@ -24,6 +24,7 @@
24 24
     "async-es": "3.2.4",
25 25
     "base64-js": "1.5.1",
26 26
     "current-executing-script": "0.1.3",
27
+    "emoji-regex": "10.4.0",
27 28
     "jquery": "3.6.1",
28 29
     "lodash-es": "4.17.21",
29 30
     "sdp-transform": "2.3.0",

Loading…
Cancelar
Guardar