2021-11-19 11:44:48 -05:00
import { strict as assert } from "assert" ;
import config from "../../src/config" ;
2022-02-15 08:51:20 -05:00
import { newTestUser , noticeListener } from "./clientHelper" ;
import { LogService , MatrixClient , Permalinks , UserID } from "matrix-bot-sdk" ;
2022-02-21 11:51:14 -05:00
import BanList , { ALL_RULE_TYPES , ChangeType , ListRuleChange , RULE_SERVER , RULE_USER , SERVER_RULE_TYPES } from "../../src/models/BanList" ;
2022-02-07 12:02:06 -05:00
import { ServerAcl , ServerAclContent } from "../../src/models/ServerAcl" ;
2022-02-21 11:51:14 -05:00
import { createBanList , getFirstReaction } from "./commands/commandUtils" ;
2022-02-15 08:51:20 -05:00
import { getMessagesByUserIn } from "../../src/utils" ;
2021-11-19 11:44:48 -05:00
/ * *
* Create a policy rule in a policy room .
* @param client A matrix client that is logged in
* @param policyRoomId The room id to add the policy to .
* @param policyType The type of policy to add e . g . m . policy . rule . user . ( Use RULE_USER though ) .
* @param entity The entity to ban e . g . @foo : example . org
* @param reason A reason for the rule e . g . 'Wouldn' t stop posting spam links '
2022-02-07 12:02:06 -05:00
* @param template The template to use for the policy rule event .
2021-11-19 11:44:48 -05:00
* @returns The event id of the newly created policy rule .
* /
2022-02-07 12:02:06 -05:00
async function createPolicyRule ( client : MatrixClient , policyRoomId : string , policyType : string , entity : string , reason : string , template = { recommendation : 'm.ban' } ) {
2021-11-19 11:44:48 -05:00
return await client . sendStateEvent ( policyRoomId , policyType , ` rule: ${ entity } ` , {
entity ,
reason ,
2022-02-07 12:02:06 -05:00
. . . template ,
2021-11-19 11:44:48 -05:00
} ) ;
}
describe ( "Test: Updating the BanList" , function ( ) {
it ( "Calculates what has changed correctly." , async function ( ) {
this . timeout ( 10000 ) ;
const mjolnir = config . RUNTIME . client !
2022-01-25 07:19:44 -05:00
const moderator = await newTestUser ( { name : { contains : "moderator" } } ) ;
2021-11-19 11:44:48 -05:00
const banListId = await mjolnir . createRoom ( { invite : [ await moderator . getUserId ( ) ] } ) ;
const banList = new BanList ( banListId , banListId , mjolnir ) ;
mjolnir . setUserPowerLevel ( await moderator . getUserId ( ) , banListId , 100 ) ;
2021-11-22 10:41:12 -05:00
assert . equal ( banList . allRules . length , 0 ) ;
2021-11-19 11:44:48 -05:00
// Test adding a new rule
await createPolicyRule ( mjolnir , banListId , RULE_USER , '@added:localhost:9999' , '' ) ;
let changes : ListRuleChange [ ] = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 , 'There should only be one change' ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Added ) ;
assert . equal ( changes [ 0 ] . sender , await mjolnir . getUserId ( ) ) ;
2021-11-22 10:41:12 -05:00
assert . equal ( banList . userRules . length , 1 ) ;
assert . equal ( banList . allRules . length , 1 ) ;
2021-11-19 11:44:48 -05:00
// Test modifiying a rule
let originalEventId = await createPolicyRule ( mjolnir , banListId , RULE_USER , '@modified:localhost:9999' , '' ) ;
await banList . updateList ( ) ;
2021-11-22 10:41:12 -05:00
let modifyingEventId = await createPolicyRule ( mjolnir , banListId , RULE_USER , '@modified:localhost:9999' , 'modified reason' ) ;
2021-11-19 11:44:48 -05:00
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Modified ) ;
assert . equal ( changes [ 0 ] . previousState [ 'event_id' ] , originalEventId , 'There should be a previous state event for a modified rule' ) ;
2021-11-22 10:41:12 -05:00
assert . equal ( changes [ 0 ] . event [ 'event_id' ] , modifyingEventId ) ;
let modifyingAgainEventId = await createPolicyRule ( mjolnir , banListId , RULE_USER , '@modified:localhost:9999' , 'modified again' ) ;
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Modified ) ;
assert . equal ( changes [ 0 ] . previousState [ 'event_id' ] , modifyingEventId , 'There should be a previous state event for a modified rule' ) ;
assert . equal ( changes [ 0 ] . event [ 'event_id' ] , modifyingAgainEventId ) ;
assert . equal ( banList . userRules . length , 2 , 'There should be two rules, one for @modified:localhost:9999 and one for @added:localhost:9999' ) ;
2021-11-19 11:44:48 -05:00
// Test redacting a rule
const redactThis = await createPolicyRule ( mjolnir , banListId , RULE_USER , '@redacted:localhost:9999' , '' ) ;
await banList . updateList ( ) ;
2021-11-22 10:41:12 -05:00
assert . equal ( banList . userRules . filter ( r = > r . entity === '@redacted:localhost:9999' ) . length , 1 ) ;
2021-11-19 11:44:48 -05:00
await mjolnir . redactEvent ( banListId , redactThis ) ;
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Removed ) ;
assert . equal ( changes [ 0 ] . event [ 'event_id' ] , redactThis , 'Should show the new version of the event with redacted content' ) ;
assert . equal ( Object . keys ( changes [ 0 ] . event [ 'content' ] ) . length , 0 , 'Should show the new version of the event with redacted content' ) ;
assert . notEqual ( Object . keys ( changes [ 0 ] . previousState [ 'content' ] ) , 0 , 'Should have a copy of the unredacted state' ) ;
assert . notEqual ( changes [ 0 ] . rule , undefined , 'The previous rule should be present' ) ;
2021-11-22 10:41:12 -05:00
assert . equal ( banList . userRules . filter ( r = > r . entity === '@redacted:localhost:9999' ) . length , 0 , 'The rule should be removed.' ) ;
2021-11-19 11:44:48 -05:00
// Test soft redaction of a rule
const softRedactedEntity = '@softredacted:localhost:9999'
await createPolicyRule ( mjolnir , banListId , RULE_USER , softRedactedEntity , '' ) ;
await banList . updateList ( ) ;
2021-11-22 10:41:12 -05:00
assert . equal ( banList . userRules . filter ( r = > r . entity === softRedactedEntity ) . length , 1 ) ;
await mjolnir . sendStateEvent ( banListId , RULE_USER , ` rule: ${ softRedactedEntity } ` , { } ) ;
2021-11-19 11:44:48 -05:00
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Removed ) ;
assert . equal ( Object . keys ( changes [ 0 ] . event [ 'content' ] ) . length , 0 , 'Should show the new version of the event with redacted content' ) ;
assert . notEqual ( Object . keys ( changes [ 0 ] . previousState [ 'content' ] ) , 0 , 'Should have a copy of the unredacted state' ) ;
assert . notEqual ( changes [ 0 ] . rule , undefined , 'The previous rule should be present' ) ;
2021-11-22 10:41:12 -05:00
assert . equal ( banList . userRules . filter ( r = > r . entity === softRedactedEntity ) . length , 0 , 'The rule should have been removed' ) ;
2021-11-19 11:44:48 -05:00
// Now test a double soft redaction just to make sure stuff doesn't explode
2021-11-22 10:41:12 -05:00
await mjolnir . sendStateEvent ( banListId , RULE_USER , ` rule: ${ softRedactedEntity } ` , { } ) ;
2021-11-19 11:44:48 -05:00
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 0 , "It shouldn't detect a double soft redaction as a change, it should be seen as adding an invalid rule." ) ;
2021-11-22 10:41:12 -05:00
assert . equal ( banList . userRules . filter ( r = > r . entity === softRedactedEntity ) . length , 0 , 'The rule should have been removed' ) ;
// Test that different (old) rule types will be modelled as the latest event type.
originalEventId = await createPolicyRule ( mjolnir , banListId , 'org.matrix.mjolnir.rule.user' , '@old:localhost:9999' , '' ) ;
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Added ) ;
assert . equal ( banList . userRules . filter ( r = > r . entity === '@old:localhost:9999' ) . length , 1 ) ;
modifyingEventId = await createPolicyRule ( mjolnir , banListId , 'm.room.rule.user' , '@old:localhost:9999' , 'modified reason' ) ;
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Modified ) ;
assert . equal ( changes [ 0 ] . event [ 'event_id' ] , modifyingEventId ) ;
assert . equal ( changes [ 0 ] . previousState [ 'event_id' ] , originalEventId , 'There should be a previous state event for a modified rule' ) ;
assert . equal ( banList . userRules . filter ( r = > r . entity === '@old:localhost:9999' ) . length , 1 ) ;
modifyingAgainEventId = await createPolicyRule ( mjolnir , banListId , RULE_USER , '@old:localhost:9999' , 'changes again' ) ;
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Modified ) ;
assert . equal ( changes [ 0 ] . event [ 'event_id' ] , modifyingAgainEventId ) ;
assert . equal ( changes [ 0 ] . previousState [ 'event_id' ] , modifyingEventId , 'There should be a previous state event for a modified rule' ) ;
assert . equal ( banList . userRules . filter ( r = > r . entity === '@old:localhost:9999' ) . length , 1 ) ;
} )
it ( "Will remove rules with old types when they are 'soft redacted' with a different but more recent event type." , async function ( ) {
this . timeout ( 3000 ) ;
const mjolnir = config . RUNTIME . client !
2022-01-25 07:19:44 -05:00
const moderator = await newTestUser ( { name : { contains : "moderator" } } ) ;
2021-11-22 10:41:12 -05:00
const banListId = await mjolnir . createRoom ( { invite : [ await moderator . getUserId ( ) ] } ) ;
const banList = new BanList ( banListId , banListId , mjolnir ) ;
mjolnir . setUserPowerLevel ( await moderator . getUserId ( ) , banListId , 100 ) ;
const entity = '@old:localhost:9999' ;
let originalEventId = await createPolicyRule ( mjolnir , banListId , 'm.room.rule.user' , entity , '' ) ;
let changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Added ) ;
assert . equal ( banList . userRules . filter ( rule = > rule . entity === entity ) . length , 1 , 'There should be a rule stored that we just added...' )
let softRedactingEventId = await mjolnir . sendStateEvent ( banListId , RULE_USER , ` rule: ${ entity } ` , { } ) ;
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Removed ) ;
assert . equal ( changes [ 0 ] . event [ 'event_id' ] , softRedactingEventId ) ;
assert . equal ( changes [ 0 ] . previousState [ 'event_id' ] , originalEventId , 'There should be a previous state event for a modified rule' ) ;
assert . equal ( banList . userRules . filter ( rule = > rule . entity === entity ) . length , 0 , 'The rule should no longer be stored.' ) ;
} )
it ( "A rule of the most recent type won't be deleted when an old rule is deleted for the same entity." , async function ( ) {
this . timeout ( 3000 ) ;
const mjolnir = config . RUNTIME . client !
2022-01-25 07:19:44 -05:00
const moderator = await newTestUser ( { name : { contains : "moderator" } } ) ;
2021-11-22 10:41:12 -05:00
const banListId = await mjolnir . createRoom ( { invite : [ await moderator . getUserId ( ) ] } ) ;
const banList = new BanList ( banListId , banListId , mjolnir ) ;
mjolnir . setUserPowerLevel ( await moderator . getUserId ( ) , banListId , 100 ) ;
const entity = '@old:localhost:9999' ;
let originalEventId = await createPolicyRule ( mjolnir , banListId , 'm.room.rule.user' , entity , '' ) ;
let changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Added ) ;
assert . equal ( banList . userRules . filter ( rule = > rule . entity === entity ) . length , 1 , 'There should be a rule stored that we just added...' )
let updatedEventId = await createPolicyRule ( mjolnir , banListId , RULE_USER , entity , '' ) ;
changes = await banList . updateList ( ) ;
// If in the future you change this and it fails, it's really subjective whether this constitutes a modification, since the only thing that has changed
// is the rule type. The actual content is identical.
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Modified ) ;
assert . equal ( changes [ 0 ] . event [ 'event_id' ] , updatedEventId ) ;
assert . equal ( changes [ 0 ] . previousState [ 'event_id' ] , originalEventId , 'There should be a previous state event for a modified rule' ) ;
assert . equal ( banList . userRules . filter ( rule = > rule . entity === entity ) . length , 1 , 'Only the latest version of the rule gets returned.' ) ;
// Now we delete the old version of the rule without consequence.
await mjolnir . sendStateEvent ( banListId , 'm.room.rule.user' , ` rule: ${ entity } ` , { } ) ;
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 0 ) ;
assert . equal ( banList . userRules . filter ( rule = > rule . entity === entity ) . length , 1 , 'The rule should still be active.' ) ;
// And we can still delete the new version of the rule.
let softRedactingEventId = await mjolnir . sendStateEvent ( banListId , RULE_USER , ` rule: ${ entity } ` , { } ) ;
changes = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Removed ) ;
assert . equal ( changes [ 0 ] . event [ 'event_id' ] , softRedactingEventId ) ;
assert . equal ( changes [ 0 ] . previousState [ 'event_id' ] , updatedEventId , 'There should be a previous state event for a modified rule' ) ;
assert . equal ( banList . userRules . filter ( rule = > rule . entity === entity ) . length , 0 , 'The rule should no longer be stored.' ) ;
2021-11-19 11:44:48 -05:00
} )
2022-02-07 12:02:06 -05:00
it ( 'Test: BanList Supports all entity types.' , async function ( ) {
const mjolnir = config . RUNTIME . client !
const banListId = await mjolnir . createRoom ( ) ;
const banList = new BanList ( banListId , banListId , mjolnir ) ;
for ( let i = 0 ; i < ALL_RULE_TYPES . length ; i ++ ) {
await createPolicyRule ( mjolnir , banListId , ALL_RULE_TYPES [ i ] , ` * ${ i } * ` , '' ) ;
}
let changes : ListRuleChange [ ] = await banList . updateList ( ) ;
assert . equal ( changes . length , ALL_RULE_TYPES . length ) ;
assert . equal ( banList . allRules . length , ALL_RULE_TYPES . length ) ;
} )
2021-11-19 11:44:48 -05:00
} ) ;
2022-02-07 12:02:06 -05:00
describe ( 'Test: We do not respond to recommendations other than m.ban in the banlist' , function ( ) {
it ( 'Will not respond to a rule that has a different recommendation to m.ban (or the unstable equivalent).' , async function ( ) {
const mjolnir = config . RUNTIME . client !
const banListId = await mjolnir . createRoom ( ) ;
const banList = new BanList ( banListId , banListId , mjolnir ) ;
await createPolicyRule ( mjolnir , banListId , RULE_SERVER , 'exmaple.org' , '' , { recommendation : 'something that is not m.ban' } ) ;
let changes : ListRuleChange [ ] = await banList . updateList ( ) ;
assert . equal ( changes . length , 1 , 'There should only be one change' ) ;
assert . equal ( changes [ 0 ] . changeType , ChangeType . Added ) ;
assert . equal ( changes [ 0 ] . sender , await mjolnir . getUserId ( ) ) ;
// We really don't want things that aren't m.ban to end up being accessible in these APIs.
assert . equal ( banList . serverRules . length , 0 ) ;
assert . equal ( banList . allRules . length , 0 ) ;
} )
} )
describe ( 'Test: We will not be able to ban ourselves via ACL.' , function ( ) {
it ( 'We do not ban ourselves when we put ourselves into the policy list.' , async function ( ) {
const mjolnir = config . RUNTIME . client !
const serverName = new UserID ( await mjolnir . getUserId ( ) ) . domain ;
const banListId = await mjolnir . createRoom ( ) ;
const banList = new BanList ( banListId , banListId , mjolnir ) ;
await createPolicyRule ( mjolnir , banListId , RULE_SERVER , serverName , '' ) ;
await createPolicyRule ( mjolnir , banListId , RULE_SERVER , 'evil.com' , '' ) ;
await createPolicyRule ( mjolnir , banListId , RULE_SERVER , '*' , '' ) ;
// We should still intern the matching rules rule.
let changes : ListRuleChange [ ] = await banList . updateList ( ) ;
assert . equal ( banList . serverRules . length , 3 ) ;
// But when we construct an ACL, we should be safe.
const acl = new ServerAcl ( serverName )
changes . forEach ( change = > acl . denyServer ( change . rule . entity ) ) ;
assert . equal ( acl . safeAclContent ( ) . deny . length , 1 ) ;
assert . equal ( acl . literalAclContent ( ) . deny . length , 3 ) ;
} )
} )
2022-02-15 08:51:20 -05:00
describe ( 'Test: ACL updates will batch when rules are added in succession.' , function ( ) {
it ( 'Will batch ACL updates if we spam rules into a BanList' , async function ( ) {
this . timeout ( 180000 )
const mjolnir = config . RUNTIME . client !
const serverName : string = new UserID ( await mjolnir . getUserId ( ) ) . domain
const moderator = await newTestUser ( { name : { contains : "moderator" } } ) ;
moderator . joinRoom ( this . mjolnir . managementRoomId ) ;
const mjolnirId = await mjolnir . getUserId ( ) ;
// Setup some protected rooms so we can check their ACL state later.
const protectedRooms : string [ ] = [ ] ;
for ( let i = 0 ; i < 10 ; i ++ ) {
const room = await moderator . createRoom ( { invite : [ mjolnirId ] } ) ;
await mjolnir . joinRoom ( room ) ;
await moderator . setUserPowerLevel ( mjolnirId , room , 100 ) ;
await this . mjolnir ! . addProtectedRoom ( room ) ;
protectedRooms . push ( room ) ;
}
// If a previous test hasn't cleaned up properly, these rooms will be populated by bogus ACLs at this point.
await this . mjolnir ! . syncLists ( ) ;
await Promise . all ( protectedRooms . map ( async room = > {
// We're going to need timeline pagination I'm afraid.
const roomAcl = await mjolnir . getRoomStateEvent ( room , "m.room.server_acl" , "" ) ;
assert . equal ( roomAcl ? . deny ? . length ? ? 0 , 0 , 'There should be no entries in the deny ACL.' ) ;
} ) ) ;
// Flood the watched list with banned servers, which should prompt Mjolnir to update server ACL in protected rooms.
const banListId = await moderator . createRoom ( { invite : [ mjolnirId ] } ) ;
mjolnir . joinRoom ( banListId ) ;
this . mjolnir ! . watchList ( Permalinks . forRoom ( banListId ) ) ;
const acl = new ServerAcl ( serverName ) . denyIpAddresses ( ) . allowServer ( "*" ) ;
for ( let i = 0 ; i < 200 ; i ++ ) {
const badServer = ` ${ i } .evil.com ` ;
acl . denyServer ( badServer ) ;
await createPolicyRule ( moderator , banListId , RULE_SERVER , badServer , ` Rule # ${ i } ` ) ;
// Give them a bit of a spread over time.
await new Promise ( resolve = > setTimeout ( resolve , 5 ) ) ;
}
// We do this because it should force us to wait until all the ACL events have been applied.
// Even if that does mean the last few events will not go through batching...
await this . mjolnir ! . syncLists ( ) ;
// Check each of the protected rooms for ACL events and make sure they were batched and are correct.
await Promise . all ( protectedRooms . map ( async room = > {
const roomAcl = await mjolnir . getRoomStateEvent ( room , "m.room.server_acl" , "" ) ;
if ( ! acl . matches ( roomAcl ) ) {
assert . fail ( ` Room ${ room } doesn't have the correct ACL: ${ JSON . stringify ( roomAcl , null , 2 ) } ` )
}
let aclEventCount = 0 ;
await getMessagesByUserIn ( mjolnir , mjolnirId , room , 100 , events = > {
events . forEach ( event = > event . type === 'm.room.server_acl' ? aclEventCount += 1 : null ) ;
} ) ;
LogService . debug ( 'BanListTest' , ` aclEventCount: ${ aclEventCount } ` ) ;
// If there's less than two then it means the ACL was updated by this test calling `this.mjolnir!.syncLists()`
// and not the listener that detects changes to ban lists (that we want to test!).
2022-02-24 09:27:53 -05:00
// It used to be 10, but it was too low, 30 seems better for CI.
assert . equal ( aclEventCount < 30 && aclEventCount > 2 , true , 'We should have sent less than 30 ACL events to each room because they should be batched' )
2022-02-15 08:51:20 -05:00
} ) ) ;
} )
} )
2022-02-21 11:51:14 -05:00
describe ( 'Test: unbaning entities via the BanList.' , function ( ) {
afterEach ( function ( ) { this . moderator ? . stop ( ) ; } ) ;
it ( 'Will remove rules that have legacy types' , async function ( ) {
this . timeout ( 20000 )
const mjolnir = config . RUNTIME . client !
const serverName : string = new UserID ( await mjolnir . getUserId ( ) ) . domain
const moderator = await newTestUser ( { name : { contains : "moderator" } } ) ;
this . moderator = moderator ;
moderator . joinRoom ( this . mjolnir . managementRoomId ) ;
const mjolnirId = await mjolnir . getUserId ( ) ;
// We'll make 1 protected room to test ACLs in.
const protectedRoom = await moderator . createRoom ( { invite : [ mjolnirId ] } ) ;
await mjolnir . joinRoom ( protectedRoom ) ;
await moderator . setUserPowerLevel ( mjolnirId , protectedRoom , 100 ) ;
await this . mjolnir ! . addProtectedRoom ( protectedRoom ) ;
// If a previous test hasn't cleaned up properly, these rooms will be populated by bogus ACLs at this point.
await this . mjolnir ! . syncLists ( ) ;
const roomAcl = await mjolnir . getRoomStateEvent ( protectedRoom , "m.room.server_acl" , "" ) ;
assert . equal ( roomAcl ? . deny ? . length ? ? 0 , 0 , 'There should be no entries in the deny ACL.' ) ;
// Create some legacy rules on a BanList.
const banListId = await moderator . createRoom ( { invite : [ mjolnirId ] } ) ;
await moderator . setUserPowerLevel ( await mjolnir . getUserId ( ) , banListId , 100 ) ;
await moderator . sendStateEvent ( banListId , 'org.matrix.mjolnir.shortcode' , '' , { shortcode : "unban-test" } ) ;
await mjolnir . joinRoom ( banListId ) ;
this . mjolnir ! . watchList ( Permalinks . forRoom ( banListId ) ) ;
// we use this to compare changes.
const banList = new BanList ( banListId , banListId , moderator ) ;
// we need two because we need to test the case where an entity has all rule types in the list
// and another one that only has one (so that we would hit 404 while looking up state)
const olderBadServer = "old.evil.com"
const newerBadServer = "new.evil.com"
await Promise . all ( SERVER_RULE_TYPES . map ( type = > createPolicyRule ( moderator , banListId , type , olderBadServer , 'gregg rulz ok' ) ) ) ;
await createPolicyRule ( moderator , banListId , RULE_SERVER , newerBadServer , 'this is bad sort it out.' ) ;
// Wait for the ACL event to be applied to our protected room.
await this . mjolnir ! . syncLists ( ) ;
await banList . updateList ( ) ;
// rules are normalized, that's why there should only be 2.
assert . equal ( banList . allRules . length , 2 ) ;
// Check that we have setup our test properly and therefore evil.com is banned.
const acl = new ServerAcl ( serverName ) . denyIpAddresses ( ) . allowServer ( "*" ) . denyServer ( olderBadServer ) . denyServer ( newerBadServer ) ;
const protectedAcl = await mjolnir . getRoomStateEvent ( protectedRoom , "m.room.server_acl" , "" ) ;
if ( ! acl . matches ( protectedAcl ) ) {
assert . fail ( ` Room ${ protectedRoom } doesn't have the correct ACL: ${ JSON . stringify ( roomAcl , null , 2 ) } ` ) ;
}
// Now unban the servers, we will go via the unban command for completeness sake.
try {
await moderator . start ( ) ;
for ( const server of [ olderBadServer , newerBadServer ] ) {
await getFirstReaction ( moderator , this . mjolnir . managementRoomId , '✅' , async ( ) = > {
return await moderator . sendMessage ( this . mjolnir . managementRoomId , { msgtype : 'm.text' , body : ` !mjolnir unban unban-test server ${ server } ` } ) ;
} ) ;
}
} finally {
moderator . stop ( ) ;
}
// Wait for mjolnir to sync protected rooms to update ACL.
await this . mjolnir ! . syncLists ( ) ;
// Confirm that the server is unbanned.
await banList . updateList ( ) ;
assert . equal ( banList . allRules . length , 0 ) ;
const aclAfter = await mjolnir . getRoomStateEvent ( protectedRoom , "m.room.server_acl" , "" ) ;
assert . equal ( aclAfter . deny . length , 0 , 'Should be no servers denied anymore' ) ;
} )
} )