diff --git a/config.sample.yaml b/config.sample.yaml index d079a5393..7fdf70af4 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -422,6 +422,11 @@ ircService: # allotted time period, the provisioning request will fail. # Default: 300 seconds (5 mins) requestTimeoutSeconds: 300 + # A file defining the provisioning rules for rooms. Format is documented + # in rules.sample.yaml. Leave undefined to not specify any rules. + ruleFile: "./provisioning.rules.yaml" + # Watch the file for changes, and apply the rules. Default: false + enableReload: true # WARNING: The bridge needs to send plaintext passwords to the IRC server, it cannot # send a password hash. As a result, passwords (NOT hashes) are stored encrypted in diff --git a/lib/bridge/IrcBridge.js b/lib/bridge/IrcBridge.js index 86fc6f920..cb8100d9c 100644 --- a/lib/bridge/IrcBridge.js +++ b/lib/bridge/IrcBridge.js @@ -52,6 +52,16 @@ function IrcBridge(config, registration) { this.ircHandler = new IrcHandler(this, this.config.ircHandler); this._clientPool = new ClientPool(this); var dirPath = this.config.ircService.databaseUri.substring("nedb://".length); + let roomLinkValidation = undefined; + let provisioning = config.ircService.provisioning; + if (provisioning && provisioning.enabled && + typeof (provisioning.ruleFile) === "string") { + roomLinkValidation = { + ruleFile: provisioning.ruleFile, + triggerEndpoint: provisioning.enableReload + }; + } + this._bridge = new Bridge({ registration: this.registration, homeserverUrl: this.config.homeserver.url, @@ -89,7 +99,8 @@ function IrcBridge(config, registration) { dontCheckPowerLevel: true, enablePresence: this.config.homeserver.enablePresence, } - } + }, + roomLinkValidation, }); this._timers = null; // lazy map of Histogram instances used as metrics diff --git a/lib/config/schema.yml b/lib/config/schema.yml index 76738790d..fa5592ba1 100644 --- a/lib/config/schema.yml +++ b/lib/config/schema.yml @@ -86,6 +86,10 @@ properties: type: "boolean" requestTimeoutSeconds: type: "number" + ruleFile: + type: "string" + enableReload: + type: "boolean" passwordEncryptionKeyPath: type: "string" matrixHandler: diff --git a/lib/provisioning/Provisioner.js b/lib/provisioning/Provisioner.js index 1a8dfe18e..0d2dd75eb 100644 --- a/lib/provisioning/Provisioner.js +++ b/lib/provisioning/Provisioner.js @@ -244,6 +244,16 @@ Provisioner.prototype._userHasProvisioningPower = Promise.coroutine( // Try 100 times to join a room, or timeout after 10 min yield retry(req, 100, 5000, matrixClient, matrixClient.joinRoom, roomId).timeout(600000); + try { + yield this._ircBridge.getAppServiceBridge().canProvisionRoom(roomId); + } + catch (err) { + req.log.error(`Room failed room validator check: (${err})`); + throw new Error( + 'Room failed validation. You may be attempting to "double bridge" this room.' + + ' Error: ' + err + ); + } try { powerState = yield matrixClient.getStateEvent(roomId, 'm.room.power_levels'); diff --git a/package.json b/package.json index 19f21e041..80cc8a025 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "he": "^1.1.1", "irc": "matrix-org/node-irc#c9abb427bec5016d94a2abf3e058cc62de09ea5a", "js-yaml": "^3.2.7", - "matrix-appservice-bridge": "1.6.0c", + "matrix-appservice-bridge": "^1.7.0", "nedb": "^1.1.2", "nopt": "^3.0.1", "prom-client": "^6.3.0", diff --git a/provisioning.rules.sample.yaml b/provisioning.rules.sample.yaml new file mode 100644 index 000000000..ea91fccb8 --- /dev/null +++ b/provisioning.rules.sample.yaml @@ -0,0 +1,12 @@ +# A set of regexes to match against joined members in rooms. +# If one of the regexes matches a userId, then do not allow provisioning +# to the room UNLESS it also matches a exempt regex. +# This doesn't affect existing bridge entrys, only new provisioned rooms. +# +# For this to work, config.provisioning.ruleFile must point to this file. +userIds: + exempt: + - "@appservice-irc:localhost" + - "@irc_.+:localhost" + conflict: + - "@irc_.+:.+" diff --git a/spec/util/client-sdk-mock.js b/spec/util/client-sdk-mock.js index ca6a2cde8..afadee0ab 100644 --- a/spec/util/client-sdk-mock.js +++ b/spec/util/client-sdk-mock.js @@ -23,6 +23,7 @@ function MockClient(config) { this.setRoomTopic = jasmine.createSpy("sdk.setRoomTopic(roomId, topic)"); this.setDisplayName = jasmine.createSpy("sdk.setDisplayName(name)"); this.getStateEvent = jasmine.createSpy("sdk.getStateEvent(room,type,key)"); + this.fetchRoomEvent = jasmine.createSpy("sdk.fetchRoomEvent(room,event_id)"); this.sendStateEvent = jasmine.createSpy("sdk.sendStateEvent(room,type,content,key)"); this.sendEvent = jasmine.createSpy("sdk.sendEvent(roomId,type,content)"); this.invite = jasmine.createSpy("sdk.invite(roomId, userId)");