Merge branch 'hotfix/21.56.9' into master
[gitter.git] / modules / rooms / test / room-with-policy-service-test.js
blobd958d717790c038fa8173102085814f57f0d7b52
1 'use strict';
3 var proxyquireNoCallThru = require('proxyquire').noCallThru();
4 var assert = require('assert');
5 const sinon = require('sinon');
6 const mongoUtils = require('gitter-web-persistence-utils/lib/mongo-utils');
7 var fixtureLoader = require('gitter-web-test-utils/lib/test-fixtures');
8 var Promise = require('bluebird');
9 var StatusError = require('statuserror');
10 var persistence = require('gitter-web-persistence');
11 var RoomWithPolicyService = require('../lib/room-with-policy-service');
12 const roomService = require('../lib/room-service');
13 const troupeService = require('gitter-web-rooms/lib/troupe-service');
14 const policyFactory = require('gitter-web-permissions/lib/policy-factory');
16 describe('room-with-policy-service', function() {
17   var fixture = fixtureLoader.setup({
18     user1: {},
19     userStaff: {
20       staff: true
21     },
22     troupe1: {
23       users: ['user1']
24     },
25     troupeWithReservedTags: {
26       tags: ['foo:bar', 'foo']
27     },
28     troupeBan: {
29       security: 'PUBLIC',
30       githubType: 'REPO',
31       users: ['userBan', 'userBanAdmin']
32     },
33     troupeBan2: {
34       security: 'PUBLIC',
35       githubType: 'REPO',
36       users: ['userBan', 'userBanAdmin']
37     },
38     userBan: {},
39     userBanAdmin: {},
40     troupeForDeletion: {}
41   });
43   var isAdminPolicy = {
44     canAdmin: function() {
45       return Promise.resolve(true);
46     },
47     canJoin: function() {
48       return Promise.resolve(true);
49     }
50   };
52   var notAdminPolicy = {
53     canAdmin: function() {
54       return Promise.resolve(false);
55     }
56   };
58   const canWritePolicy = {
59     canWrite: async () => {
60       return true;
61     }
62   };
64   describe('updateTags #slow', function() {
65     it('should update tags', function() {
66       var rawTags = 'js, open source,    looooooooooooooooooooooooooooongtag,,,,';
67       var cleanTags = ['js', 'open source', 'looooooooooooooooooo'];
68       var r = new RoomWithPolicyService(fixture.troupe1, fixture.user1, isAdminPolicy);
69       return r.updateTags(rawTags).then(function(troupe) {
70         assert.deepEqual(troupe.tags.toObject(), cleanTags);
71       });
72     });
74     it('should not save reserved-word tags(colons) with normal-user', function() {
75       var rawTags = 'hey, foo:bar, there';
76       var cleanTags = ['hey', 'there'];
78       var r = new RoomWithPolicyService(fixture.troupe1, fixture.user1, isAdminPolicy);
79       return r.updateTags(rawTags).then(function(troupe) {
80         assert.deepEqual(troupe.tags.toObject(), cleanTags);
81       });
82     });
84     it('should deny a non-admin', function() {
85       var rawTags = 'hey, foo:bar, there';
87       var r = new RoomWithPolicyService(fixture.troupe1, fixture.user1, notAdminPolicy);
88       return r
89         .updateTags(rawTags)
90         .then(function() {
91           assert.ok(false);
92         })
93         .catch(StatusError, function(err) {
94           assert.strictEqual(err.status, 403);
95         });
96     });
98     it('should save reserved-word tags with staff-user', function() {
99       var rawTags = 'hey, foo:bar, there';
100       var cleanTags = ['hey', 'foo:bar', 'there'];
102       var r = new RoomWithPolicyService(fixture.troupe1, fixture.userStaff, notAdminPolicy);
103       return r.updateTags(rawTags).then(function(troupe) {
104         assert.deepEqual(troupe.tags.toObject(), cleanTags);
105       });
106     });
108     it('should retain reserved-word tags with normal-user', function() {
109       var fixtureTags = 'foo:bar, foo';
110       var userTags = 'hey, there';
111       var userActualTags = ['hey', 'there', 'foo:bar'];
113       var r1 = new RoomWithPolicyService(
114         fixture.troupeWithReservedTags,
115         fixture.userStaff,
116         notAdminPolicy
117       );
118       var r2 = new RoomWithPolicyService(
119         fixture.troupeWithReservedTags,
120         fixture.user1,
121         isAdminPolicy
122       );
124       return r1
125         .updateTags(fixtureTags)
126         .then(function() {
127           return r2.updateTags(userTags);
128         })
129         .then(function(troupe) {
130           assert.deepEqual(troupe.tags.toObject(), userActualTags);
131         });
132     });
133   });
135   describe('bans #slow', function() {
136     it('should ban users from rooms #slow', function() {
137       var roomMembershipService = require('../lib/room-membership-service');
139       var r = new RoomWithPolicyService(fixture.troupeBan, fixture.userBanAdmin, isAdminPolicy);
141       return roomService
142         .findBanByUsername(fixture.troupeBan._id, fixture.userBan.username)
143         .then(function(banned) {
144           assert(!banned);
146           return r
147             .banUserFromRoom(fixture.userBan.username, {})
148             .then(function(ban) {
149               assert.equal(ban.userId, fixture.userBan.id);
150               assert.equal(ban.bannedBy, fixture.userBanAdmin.id);
151               assert(ban.dateBanned);
153               return roomMembershipService.checkRoomMembership(
154                 fixture.troupeBan._id,
155                 fixture.userBan.id
156               );
157             })
158             .then(function(bannedUserIsInRoom) {
159               assert(!bannedUserIsInRoom);
161               return roomService.findBanByUsername(fixture.troupeBan.id, fixture.userBan.username);
162             })
163             .then(function(ban) {
164               assert(ban);
165               assert(ban.userId);
167               return roomService
168                 .findBanByUsername(fixture.troupeBan._id, fixture.userBan.username)
169                 .then(function(banned) {
170                   assert(banned);
172                   return r.unbanUserFromRoom(ban.userId).then(function() {
173                     return roomService
174                       .findBanByUsername(fixture.troupeBan._id, fixture.userBan.username)
175                       .then(function(banned) {
176                         assert(!banned);
178                         return roomService.findBanByUsername(
179                           fixture.troupeBan.id,
180                           fixture.userBan.username
181                         );
182                       })
183                       .then(function(ban) {
184                         assert(!ban);
185                       });
186                   });
187                 });
188             });
189         });
190     });
192     it('should not allow admins to be banned', function() {
193       var RoomWithPolicyService = proxyquireNoCallThru('../lib/room-with-policy-service', {
194         'gitter-web-permissions/lib/policy-factory': {
195           createPolicyForRoom: function(user, room) {
196             assert.strictEqual(user.id, fixture.userBan.id);
197             assert.strictEqual(room.id, fixture.troupeBan2.id);
198             return Promise.resolve({
199               canAdmin: function() {
200                 return Promise.resolve(true);
201               }
202             });
203           }
204         }
205       });
207       var r = new RoomWithPolicyService(fixture.troupeBan2, fixture.userBanAdmin, isAdminPolicy);
209       return r
210         .banUserFromRoom(fixture.userBan.username, {})
211         .then(function() {
212           assert(false, 'Expected to fail as banned user is an admin');
213         })
214         .catch(StatusError, function(err) {
215           assert.equal(err.status, 403);
216         });
217     });
219     it('should not allow non-admins to ban', function() {
220       var r = new RoomWithPolicyService(fixture.troupeBan2, fixture.userBanAdmin, notAdminPolicy);
222       return r
223         .banUserFromRoom(fixture.userBan.username, {})
224         .then(function() {
225           assert(false, 'Expected to fail');
226         })
227         .catch(StatusError, function(err) {
228           assert.equal(err.status, 403);
229         });
230     });
231   });
233   describe('virtualUser bans #slow', () => {
234     describe('banVirtualUserFromRoom', () => {
235       const virtualUserBanfixtures = fixtureLoader.setup({
236         user1: {},
237         userBanAdmin: {},
238         troupe1: {},
239         troupeWithBannedVirtualUsers1: {
240           bans: [
241             {
242               virtualUser: {
243                 type: 'matrix',
244                 externalId: 'banned-user:matrix.org'
245               },
246               dateBanned: new Date('1995-12-17T03:24:00+00:00'),
247               bannedBy: 'userBanAdmin'
248             }
249           ]
250         }
251       });
253       it('should not allow non-admins to ban', async () => {
254         const roomWithPolicyService = new RoomWithPolicyService(
255           virtualUserBanfixtures.troupe1,
256           virtualUserBanfixtures.user1,
257           notAdminPolicy
258         );
260         try {
261           await roomWithPolicyService.banVirtualUserFromRoom({
262             type: 'matrix',
263             externalId: 'bad-guy:matrix.org'
264           });
265           assert(false, 'Expected to fail');
266         } catch (err) {
267           assert.equal(err.status, 403);
268         }
269       });
271       it('bans virtualUser', async () => {
272         const roomWithPolicyService = new RoomWithPolicyService(
273           virtualUserBanfixtures.troupe1,
274           virtualUserBanfixtures.userBanAdmin,
275           isAdminPolicy
276         );
278         const ban = await roomWithPolicyService.banVirtualUserFromRoom({
279           type: 'matrix',
280           externalId: 'bad-guy:matrix.org'
281         });
283         assert.strictEqual(ban.userId, undefined);
284         assert.strictEqual(ban.virtualUser.type, 'matrix');
285         assert.strictEqual(ban.virtualUser.externalId, 'bad-guy:matrix.org');
286         assert.strictEqual(
287           mongoUtils.objectIDsEqual(ban.bannedBy, virtualUserBanfixtures.userBanAdmin._id),
288           true
289         );
290       });
292       it('unable to ban virtualUser with invalid properties', async () => {
293         const roomWithPolicyService = new RoomWithPolicyService(
294           virtualUserBanfixtures.troupe1,
295           virtualUserBanfixtures.userBanAdmin,
296           isAdminPolicy
297         );
299         try {
300           await roomWithPolicyService.banVirtualUserFromRoom({
301             type: 'matrix',
302             // This is invalid because the max length is 255
303             externalId: 'x'.repeat(1000)
304           });
305           assert(false, 'Expected to fail');
306         } catch (err) {
307           assert.equal(err.status, 400);
308         }
309       });
311       it('returns existing ban', async () => {
312         const roomWithPolicyService = new RoomWithPolicyService(
313           virtualUserBanfixtures.troupeWithBannedVirtualUsers1,
314           virtualUserBanfixtures.userBanAdmin,
315           isAdminPolicy
316         );
318         const ban = await roomWithPolicyService.banVirtualUserFromRoom({
319           type: 'matrix',
320           externalId: 'banned-user:matrix.org'
321         });
323         assert.strictEqual(ban.dateBanned.toISOString(), '1995-12-17T03:24:00.000Z');
324       });
326       it('removes messages when option passed', async () => {
327         const removeAllMessagesForVirtualUserInRoomIdStub = sinon.stub();
328         const stubbedRoomWithPolicyService = proxyquireNoCallThru(
329           '../lib/room-with-policy-service',
330           {
331             'gitter-web-chats': {
332               removeAllMessagesForVirtualUserInRoomId: removeAllMessagesForVirtualUserInRoomIdStub
333             }
334           }
335         );
337         const roomWithPolicyService = new stubbedRoomWithPolicyService(
338           virtualUserBanfixtures.troupe1,
339           virtualUserBanfixtures.userBanAdmin,
340           isAdminPolicy
341         );
343         await roomWithPolicyService.banVirtualUserFromRoom(
344           {
345             type: 'matrix',
346             externalId: 'spammer:matrix.org'
347           },
348           {
349             removeMessages: true
350           }
351         );
353         assert(removeAllMessagesForVirtualUserInRoomIdStub.calledOnce);
354       });
355     });
357     describe('unbanVirtualUserFromRoom', () => {
358       const virtualUserBanfixtures = fixtureLoader.setup({
359         user1: {},
360         userBanAdmin: {},
361         troupeWithBannedVirtualUsers1: {
362           bans: [
363             {
364               virtualUser: {
365                 type: 'matrix',
366                 externalId: 'banned-user:matrix.org'
367               },
368               dateBanned: new Date('1995-12-17T03:24:00+00:00'),
369               bannedBy: 'userBanAdmin'
370             }
371           ]
372         }
373       });
375       it('should not allow non-admins to unban', async () => {
376         const roomWithPolicyService = new RoomWithPolicyService(
377           virtualUserBanfixtures.troupeWithBannedVirtualUsers1,
378           virtualUserBanfixtures.user1,
379           notAdminPolicy
380         );
382         try {
383           await roomWithPolicyService.unbanVirtualUserFromRoom({
384             type: 'matrix',
385             externalId: 'banned-user:matrix.org'
386           });
387           assert(false, 'Expected to fail');
388         } catch (err) {
389           assert.equal(err.status, 403);
390         }
391       });
393       it('unbans user', async () => {
394         const roomWithPolicyService = new RoomWithPolicyService(
395           virtualUserBanfixtures.troupeWithBannedVirtualUsers1,
396           virtualUserBanfixtures.userBanAdmin,
397           isAdminPolicy
398         );
400         await roomWithPolicyService.unbanVirtualUserFromRoom({
401           type: 'matrix',
402           externalId: 'banned-user:matrix.org'
403         });
405         const updatedRoom = await troupeService.findById(
406           virtualUserBanfixtures.troupeWithBannedVirtualUsers1._id
407         );
408         assert.strictEqual(updatedRoom.bans.length, 0);
409       });
410     });
411   });
413   describe('meta', function() {
414     it('should allow you to set a welcome message', async function() {
415       const welcomeMessageText = 'this is a test';
416       const r = new RoomWithPolicyService(fixture.troupe1, fixture.user1, isAdminPolicy);
417       await r.updateRoomMeta({ welcomeMessage: welcomeMessageText });
419       const { welcomeMessage } = await r.getMeta();
420       assert(welcomeMessage.text);
421       assert(welcomeMessage.html);
422       assert.equal(welcomeMessage.text, welcomeMessageText);
423     });
425     it('should retrieve room metadata', async () => {
426       const r = new RoomWithPolicyService(fixture.troupe1, fixture.user1, isAdminPolicy);
427       await r.updateRoomMeta({ welcomeMessage: 'hello' });
428       const result = await r.getMeta();
429       assert.deepStrictEqual(result, {
430         welcomeMessage: { text: 'hello', html: 'hello' }
431       });
432     });
433   });
435   describe('delete room', function() {
436     it('should allow an admin to delete a room', function() {
437       var r = new RoomWithPolicyService(fixture.troupeForDeletion, fixture.user1, isAdminPolicy);
438       return r.deleteRoom().then(function() {
439         return persistence.Troupe.findById(fixture.troupeForDeletion._id).then(function(troupe) {
440           assert(!troupe);
441         });
442       });
443     });
445     it('should not allow a non-admin to delete a room', function() {
446       var r = new RoomWithPolicyService(fixture.troupeForDeletion, fixture.user1, notAdminPolicy);
447       return r.deleteRoom().catch(StatusError, function(err) {
448         assert.equal(err.status, 403);
449       });
450     });
451   });
453   describe('sendMessage', () => {
454     const banFixtures = fixtureLoader.setup({
455       userAdmin1: {},
456       userBridge1: {},
457       userBanned1: {},
458       troupeWithBannedUsers1: {
459         bans: [
460           {
461             user: 'userBanned1',
462             dateBanned: Date.now(),
463             bannedBy: 'userAdmin1'
464           }
465         ]
466       },
467       troupeWithBannedVirtualUsers1: {
468         bans: [
469           {
470             virtualUser: {
471               type: 'matrix',
472               externalId: 'banned-user:matrix.org'
473             },
474             dateBanned: Date.now(),
475             bannedBy: 'userAdmin1'
476           }
477         ]
478       }
479     });
481     it('normal user can send message', async () => {
482       const roomWithPolicyService = new RoomWithPolicyService(
483         fixture.troupe1,
484         fixture.user1,
485         canWritePolicy
486       );
488       const chatMessage = await roomWithPolicyService.sendMessage({ text: 'heya' });
490       assert(chatMessage);
491     });
493     it('virtualUser can send message', async () => {
494       const roomWithPolicyService = new RoomWithPolicyService(
495         fixture.troupe1,
496         fixture.user1,
497         canWritePolicy
498       );
500       const chatMessage = await roomWithPolicyService.sendMessage({
501         text: 'heya',
502         virtualUser: {
503           type: 'matrix',
504           externalId: 'test-person:matrix.org',
505           displayName: 'Tessa'
506         }
507       });
509       assert(chatMessage);
510       assert(chatMessage.virtualUser);
511     });
513     it('banned user can not send message', async () => {
514       const policy = await policyFactory.createPolicyForRoomId(
515         banFixtures.userBanned1,
516         banFixtures.troupeWithBannedUsers1._id
517       );
519       const roomWithPolicyService = new RoomWithPolicyService(
520         banFixtures.troupeWithBannedUsers1,
521         banFixtures.userBanned1,
522         policy
523       );
525       try {
526         await roomWithPolicyService.sendMessage({
527           text: 'heya'
528         });
529         assert(false, 'Expected to fail');
530       } catch (err) {
531         assert.equal(err.status, 403);
532       }
533     });
535     it('banned virtualUser can not send message', async () => {
536       const policy = await policyFactory.createPolicyForRoomId(
537         banFixtures.userBanned1,
538         banFixtures.troupeWithBannedVirtualUsers1._id
539       );
541       const roomWithPolicyService = new RoomWithPolicyService(
542         banFixtures.troupeWithBannedVirtualUsers1,
543         banFixtures.userBridge1,
544         policy
545       );
547       try {
548         await roomWithPolicyService.sendMessage({
549           text: 'heya',
550           virtualUser: {
551             type: 'matrix',
552             externalId: 'banned-user:matrix.org'
553           }
554         });
555         assert(false, 'Expected to fail');
556       } catch (err) {
557         assert.equal(err.status, 403);
558       }
559     });
560   });
562   describe('editMessage', () => {
563     const editFixtures = fixtureLoader.setup({
564       user1: {},
565       userAdmin1: {},
566       userBridge1: {},
567       userBanned1: {},
568       troupe1: {},
569       troupeWithBannedUsers1: {
570         bans: [
571           {
572             user: 'userBanned1',
573             dateBanned: Date.now(),
574             bannedBy: 'userAdmin1'
575           }
576         ]
577       },
578       troupeWithBannedVirtualUsers1: {
579         bans: [
580           {
581             virtualUser: {
582               type: 'matrix',
583               externalId: 'banned-user:matrix.org'
584             },
585             dateBanned: Date.now(),
586             bannedBy: 'userAdmin1'
587           }
588         ]
589       },
590       message1: {
591         user: 'user1',
592         troupe: 'troupe1',
593         text: 'my message'
594       },
595       messageFromVirtualUser1: {
596         user: 'userBridge1',
597         virtualUser: {
598           type: 'matrix',
599           externalId: 'test-person:matrix.org',
600           displayName: 'Tessa'
601         },
602         troupe: 'troupe1',
603         text: 'my message'
604       },
605       messageFromBannedUser1: {
606         user: 'userBanned1',
607         troupe: 'troupeWithBannedUsers1',
608         text: 'my message'
609       },
610       messageFromBannedVirtualUser1: {
611         user: 'userBridge1',
612         virtualUser: {
613           type: 'matrix',
614           externalId: 'banned-user:matrix.org',
615           displayName: 'bad-person'
616         },
617         troupe: 'troupeWithBannedVirtualUsers1',
618         text: 'my message'
619       }
620     });
622     it('normal user can edit message', async () => {
623       const roomWithPolicyService = new RoomWithPolicyService(
624         editFixtures.troupe1,
625         editFixtures.user1,
626         canWritePolicy
627       );
629       const chatMessage = await roomWithPolicyService.editMessage(editFixtures.message1, 'heya');
631       assert(chatMessage);
632       assert.strictEqual(chatMessage.text, 'heya');
633     });
635     it('admin user not allowed edit another users message', async () => {
636       const roomWithPolicyService = new RoomWithPolicyService(
637         editFixtures.troupe1,
638         editFixtures.userAdmin1,
639         canWritePolicy
640       );
642       try {
643         await roomWithPolicyService.editMessage(editFixtures.message1, 'heya');
644         assert(false, 'Expected to fail');
645       } catch (err) {
646         assert.equal(err.status, 403);
647       }
648     });
650     it('virtualUser can edit message', async () => {
651       const roomWithPolicyService = new RoomWithPolicyService(
652         editFixtures.troupe1,
653         editFixtures.userBridge1,
654         canWritePolicy
655       );
657       const chatMessage = await roomWithPolicyService.editMessage(
658         editFixtures.messageFromVirtualUser1,
659         'aliens'
660       );
662       assert(chatMessage);
663       assert(chatMessage.virtualUser);
664       assert.strictEqual(chatMessage.text, 'aliens');
665     });
667     it('banned user can not edit message', async () => {
668       const policy = await policyFactory.createPolicyForRoomId(
669         editFixtures.userBanned1,
670         editFixtures.troupeWithBannedUsers1._id
671       );
673       const roomWithPolicyService = new RoomWithPolicyService(
674         editFixtures.troupeWithBannedUsers1,
675         editFixtures.userBanned1,
676         policy
677       );
679       try {
680         await roomWithPolicyService.editMessage(editFixtures.messageFromBannedUser1, 'heya');
681         assert(false, 'Expected to fail');
682       } catch (err) {
683         assert.equal(err.status, 403);
684       }
685     });
687     it('banned virtualUser can not edit message', async () => {
688       const policy = await policyFactory.createPolicyForRoomId(
689         editFixtures.userBanned1,
690         editFixtures.troupeWithBannedVirtualUsers1._id
691       );
693       const roomWithPolicyService = new RoomWithPolicyService(
694         editFixtures.troupeWithBannedVirtualUsers1,
695         editFixtures.userBridge1,
696         policy
697       );
699       try {
700         await roomWithPolicyService.editMessage(editFixtures.messageFromBannedVirtualUser1, 'heya');
701         assert(false, 'Expected to fail');
702       } catch (err) {
703         assert.equal(err.status, 403);
704       }
705     });
706   });
708   describe('deleteMessageFromRoom', () => {
709     const deleteFixtures = fixtureLoader.setup({
710       user1: {},
711       userAdmin1: {},
712       troupe1: {},
713       troupe2: {},
714       message1: {
715         user: 'user1',
716         troupe: 'troupe1',
717         text: 'my message'
718       },
719       message2: {
720         user: 'user1',
721         troupe: 'troupe1',
722         text: 'my message'
723       },
724       messageInAnotherRoom1: {
725         user: 'user1',
726         troupe: 'troupe2',
727         text: 'another rooms message'
728       }
729     });
731     it('sender can delete message', async () => {
732       const roomWithPolicyService = new RoomWithPolicyService(
733         deleteFixtures.troupe1,
734         deleteFixtures.user1,
735         notAdminPolicy
736       );
738       await roomWithPolicyService.deleteMessageFromRoom(deleteFixtures.message1);
740       assert(true);
741     });
743     it('admin can delete message', async () => {
744       const roomWithPolicyService = new RoomWithPolicyService(
745         deleteFixtures.troupe1,
746         deleteFixtures.userAdmin1,
747         isAdminPolicy
748       );
750       await roomWithPolicyService.deleteMessageFromRoom(deleteFixtures.message2);
752       assert(true);
753     });
755     it('room admin can not delete message from another room', async () => {
756       const roomWithPolicyService = new RoomWithPolicyService(
757         deleteFixtures.troupe1,
758         deleteFixtures.userAdmin1,
759         isAdminPolicy
760       );
762       try {
763         await roomWithPolicyService.deleteMessageFromRoom(deleteFixtures.messageInAnotherRoom1);
764         assert(false, 'Expected to fail');
765       } catch (err) {
766         assert.equal(err.status, 404);
767       }
768     });
769   });