From a23885e659f93870e68db3579be0a496a15a7308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Tue, 17 Aug 2021 18:23:01 +0200 Subject: [PATCH 01/26] Make sure we don't exceed the line limit when trimming long messages getMaxLineLength() doesn't actually include the channel name in its calculations (though it does add required spaces around it), so we need to take care of that bit ourselves here. The API could be a bit more helpful here perhaps, but this at least fixes the issue for now. --- changelog.d/1459.bugfix | 1 + src/bridge/MatrixHandler.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/1459.bugfix diff --git a/changelog.d/1459.bugfix b/changelog.d/1459.bugfix new file mode 100644 index 000000000..e8e0bdd3d --- /dev/null +++ b/changelog.d/1459.bugfix @@ -0,0 +1 @@ +Make sure we don't exceed the line limit when trimming long messages diff --git a/src/bridge/MatrixHandler.ts b/src/bridge/MatrixHandler.ts index bda7c25ef..a8a110fbb 100644 --- a/src/bridge/MatrixHandler.ts +++ b/src/bridge/MatrixHandler.ts @@ -1132,7 +1132,7 @@ export class MatrixHandler { const explanation = renderTemplate(this.config.truncatedMessageTemplate, { url: httpUrl }); let messagePreview = trimString( potentialMessages[0], - ircClient.getMaxLineLength() - 4 /* "... " */ - explanation.length + ircClient.getMaxLineLength() - 4 /* "... " */ - explanation.length - ircRoom.channel.length ); if (potentialMessages.length > 1 || messagePreview.length < potentialMessages[0].length) { messagePreview += '...'; From d4a843673d149ecff3a6ddf2341898fa3214f64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 09:36:28 +0200 Subject: [PATCH 02/26] Make message edits more compact when possible --- changelog.d/1465.feature | 1 + package-lock.json | 27 ++++++++++++++ package.json | 2 ++ spec/integ/matrix-to-irc.spec.js | 2 +- spec/unit/NiceDiff.spec.js | 32 +++++++++++++++++ src/bridge/MatrixHandler.ts | 34 +++++++++++++++++- src/models/MatrixAction.ts | 7 ++++ src/util/NiceDiff.ts | 60 ++++++++++++++++++++++++++++++++ 8 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 changelog.d/1465.feature create mode 100644 spec/unit/NiceDiff.spec.js create mode 100644 src/util/NiceDiff.ts diff --git a/changelog.d/1465.feature b/changelog.d/1465.feature new file mode 100644 index 000000000..002890847 --- /dev/null +++ b/changelog.d/1465.feature @@ -0,0 +1 @@ +Make message edits more compact when possible diff --git a/package-lock.json b/package-lock.json index e42980109..36befbf13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@sentry/node": "^5.27.1", "bluebird": "^3.7.2", + "diff": "^5.0.0", "escape-string-regexp": "^4.0.0", "extend": "^3.0.2", "he": "^1.2.0", @@ -35,6 +36,7 @@ }, "devDependencies": { "@types/bluebird": "^3.5.32", + "@types/diff": "^5.0.1", "@types/express": "^4.17.7", "@types/extend": "^3.0.1", "@types/he": "^1.1.1", @@ -425,6 +427,12 @@ "@types/node": "*" } }, + "node_modules/@types/diff": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.1.tgz", + "integrity": "sha512-XIpxU6Qdvp1ZE6Kr3yrkv1qgUab0fyf4mHYvW8N3Bx3PCsbN6or1q9/q72cv5jIFWolaGH08U9XyYoLLIykyKQ==", + "dev": true + }, "node_modules/@types/express": { "version": "4.17.8", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz", @@ -1759,6 +1767,14 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -6890,6 +6906,12 @@ "@types/node": "*" } }, + "@types/diff": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.1.tgz", + "integrity": "sha512-XIpxU6Qdvp1ZE6Kr3yrkv1qgUab0fyf4mHYvW8N3Bx3PCsbN6or1q9/q72cv5jIFWolaGH08U9XyYoLLIykyKQ==", + "dev": true + }, "@types/express": { "version": "4.17.8", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz", @@ -7927,6 +7949,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", diff --git a/package.json b/package.json index 998515f56..fbd800332 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "dependencies": { "@sentry/node": "^5.27.1", "bluebird": "^3.7.2", + "diff": "^5.0.0", "escape-string-regexp": "^4.0.0", "extend": "^3.0.2", "he": "^1.2.0", @@ -50,6 +51,7 @@ }, "devDependencies": { "@types/bluebird": "^3.5.32", + "@types/diff": "^5.0.1", "@types/express": "^4.17.7", "@types/extend": "^3.0.1", "@types/he": "^1.1.1", diff --git a/spec/integ/matrix-to-irc.spec.js b/spec/integ/matrix-to-irc.spec.js index 4a925e58a..132ff2c55 100644 --- a/spec/integ/matrix-to-irc.spec.js +++ b/spec/integ/matrix-to-irc.spec.js @@ -392,7 +392,7 @@ describe("Matrix-to-IRC message bridging", function() { expect(client.nick).toEqual(testUser.nick); expect(client.addr).toEqual(roomMapping.server); expect(channel).toEqual(roomMapping.channel); - expect(text).toEqual(`<${repliesUser.nick}> "This" <- Reply Text`); + expect(text).toEqual(`<${repliesUser.nick}> "This..." <- Reply Text`); } ); const formatted_body = constructHTMLReply( diff --git a/spec/unit/NiceDiff.spec.js b/spec/unit/NiceDiff.spec.js new file mode 100644 index 000000000..c8cd557bb --- /dev/null +++ b/spec/unit/NiceDiff.spec.js @@ -0,0 +1,32 @@ +"use strict"; +const { niceDiff } = require("../../lib/util/NiceDiff.js"); + +describe("niceDiff", function() { + [ + [ + 'should not generate a diff if the message is short enough', + 'hello everyone', 'hello world', + undefined, + ], + [ + 'should generate a diff for short, multiline messages', + 'one\nfoo\nthree', 'one\ntwo\nthree', + 's/foo/two/', + ], + [ + 'should generate sed-like substitution when a short part of the message changes', + "Sounds good – I'll be there before 9", "Sounds good – I'll be there after 9", + 's/before/after/' + ], + [ + 'should only show changes from the line that has changed in multiline messages', + 'in a marmalade forest\nbetween the make-believe trees\nI forgot the third verse, sorry', + 'in a marmalade forest\nbetween the make-believe trees\nin a cottage-cheese cottage...', + 's/I forgot the third verse, sorry/in a cottage-cheese cottage.../', + ], + ].forEach(c => it(c[0], () => { + const result = niceDiff(c[1], c[2]); + console.log(`"${c[1]}" -> "${c[2]}" -> ${result}`); + expect(result).toBe(c[3]); + })); +}); diff --git a/src/bridge/MatrixHandler.ts b/src/bridge/MatrixHandler.ts index bda7c25ef..52abee854 100644 --- a/src/bridge/MatrixHandler.ts +++ b/src/bridge/MatrixHandler.ts @@ -19,6 +19,7 @@ import { AdminRoomHandler } from "./AdminRoomHandler"; import { trackChannelAndCreateRoom } from "./RoomCreation"; import { renderTemplate } from "../util/Template"; import { trimString } from "../util/TrimString"; +import { niceDiff } from "../util/NiceDiff"; async function reqHandler(req: BridgeRequest, promise: PromiseLike) { try { @@ -1058,6 +1059,8 @@ export class MatrixHandler { } let cacheBody = ircAction.text; + + // special handling for replies if (event.content["m.relates_to"] && event.content["m.relates_to"]["m.in_reply_to"]) { const eventId = event.content["m.relates_to"]["m.in_reply_to"].event_id; const reply = await this.textForReplyEvent(event, eventId, ircRoom); @@ -1066,6 +1069,35 @@ export class MatrixHandler { cacheBody = reply.reply; } } + + // special handling for edits + if (event.content["m.relates_to"] && event.content["m.relates_to"].rel_type === "m.replace") { + const originalEventId = event.content["m.relates_to"].event_id; + let originalBody = this.getCachedEvent(originalEventId)?.body; + if (!originalBody) { + try { + // FIXME: this will return the new event rather than the original one + // to actually see the original content we'd need to use whatever + // https://github.com/matrix-org/matrix-doc/pull/2675 stabilizes on + const eventContent = await this.ircBridge.getAppServiceBridge().getIntent().getEvent( + event.room_id, originalEventId + ); + originalBody = eventContent.content.body; + } + catch (_err) { + req.log.warn("Couldn't find an event being edited, using fallback text"); + } + } + req.log.debug(JSON.stringify(event.content)); + const newBody = event.content["m.new_content"]?.body; + if (originalBody && newBody) { + const diff = niceDiff(originalBody, newBody); + if (diff) { + ircAction.text = diff; + } + } + } + let body = cacheBody.trim().substring(0, this.config.replySourceMaxLength); const nextNewLine = body.indexOf("\n"); if (nextNewLine !== -1) { @@ -1073,7 +1105,7 @@ export class MatrixHandler { } // Cache events in here so we can refer to them for replies. this.cacheEvent(event.event_id, { - body, + body: cacheBody, sender: event.sender, timestamp: event.origin_server_ts, }); diff --git a/src/models/MatrixAction.ts b/src/models/MatrixAction.ts index a449b621e..ad52e8094 100644 --- a/src/models/MatrixAction.ts +++ b/src/models/MatrixAction.ts @@ -56,6 +56,13 @@ export interface MatrixMessageEvent { "m.in_reply_to"?: { event_id: string; }; + // edits + "rel_type"?: string; + "event_id": string; + }; + "m.new_content"?: { + body: string; + msgtype: string; }; body?: string; topic?: string; diff --git a/src/util/NiceDiff.ts b/src/util/NiceDiff.ts new file mode 100644 index 000000000..29e9189f3 --- /dev/null +++ b/src/util/NiceDiff.ts @@ -0,0 +1,60 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import * as Diff from 'diff'; + +function formatChanges(diff: Diff.Change[]): string[] { + const changes = []; + + let i = 0; + while (i < diff.length - 1) { + if (diff[i].removed && diff[i+1].added) { + changes.push([diff[i].value, diff[i+1].value]); + } + i++; + } + + return changes.map(c => `s/${c[0]}/${c[1]}/`); +} + +// tries to find a sensible representation of a message edit +// returns undefined it it can't come up with anything better than +// "just post the new message in its entirety" +export function niceDiff(from: string, to: string): string|undefined { + // don't bother if the message is short enough + if (to.length < 20 && !to.match(/\n/)) { + return undefined; + } + + const changesets = [ + formatChanges(Diff.diffWords(from, to)), + formatChanges(Diff.diffLines(from, to)), + ].filter( + // too many substitutions aren't that readable + diffs => diffs.length > 0 && diffs.length <= 3 + ).map( + diffs => diffs.join(', ') + ).sort( + // prefer shorter overall length + (a, b) => a.length - b.length + ); + + if (changesets.length > 0) { + return changesets[0]; + } + + return undefined; +} From cc53ac7e0595f9fbe4734d0bc141e469ae16f6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 14:37:56 +0200 Subject: [PATCH 03/26] Avoid magic numbers --- src/util/NiceDiff.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/util/NiceDiff.ts b/src/util/NiceDiff.ts index 29e9189f3..b3a2c5c35 100644 --- a/src/util/NiceDiff.ts +++ b/src/util/NiceDiff.ts @@ -30,12 +30,17 @@ function formatChanges(diff: Diff.Change[]): string[] { return changes.map(c => `s/${c[0]}/${c[1]}/`); } +// Minimum length of the message for us to try to generate a diff for +const MIN_MESSAGE_LENGTH = 20; +// The maximum number of substitutions that we still consider to be readable +const MAX_SUBSTITUTIONS = 3; + // tries to find a sensible representation of a message edit // returns undefined it it can't come up with anything better than // "just post the new message in its entirety" export function niceDiff(from: string, to: string): string|undefined { // don't bother if the message is short enough - if (to.length < 20 && !to.match(/\n/)) { + if (to.length < MIN_MESSAGE_LENGTH && !to.match(/\n/)) { return undefined; } @@ -43,8 +48,7 @@ export function niceDiff(from: string, to: string): string|undefined { formatChanges(Diff.diffWords(from, to)), formatChanges(Diff.diffLines(from, to)), ].filter( - // too many substitutions aren't that readable - diffs => diffs.length > 0 && diffs.length <= 3 + diffs => diffs.length > 0 && diffs.length <= MAX_SUBSTITUTIONS ).map( diffs => diffs.join(', ') ).sort( From 131cc5c593913dcdcb412a0b7132824589c7eb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 14:49:41 +0200 Subject: [PATCH 04/26] Make the niceDiff comment a proper docstring --- src/util/NiceDiff.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/util/NiceDiff.ts b/src/util/NiceDiff.ts index b3a2c5c35..1b83dc84a 100644 --- a/src/util/NiceDiff.ts +++ b/src/util/NiceDiff.ts @@ -35,9 +35,15 @@ const MIN_MESSAGE_LENGTH = 20; // The maximum number of substitutions that we still consider to be readable const MAX_SUBSTITUTIONS = 3; -// tries to find a sensible representation of a message edit -// returns undefined it it can't come up with anything better than -// "just post the new message in its entirety" +/** + * Try to find a sensible representation of a message edit, + * or returns undefined if it deems posting the entire new message + * to be a better choice. Optimize for terseness, legibility + * and an IRC-native feel. + * + * @param {string} from : The original message + * @param {string} to : The new, edited version + */ export function niceDiff(from: string, to: string): string|undefined { // don't bother if the message is short enough if (to.length < MIN_MESSAGE_LENGTH && !to.match(/\n/)) { From c46023af129f9b5a1729d9460fc2de0055a02854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 14:49:56 +0200 Subject: [PATCH 05/26] Remove a stray debug statement --- src/bridge/MatrixHandler.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bridge/MatrixHandler.ts b/src/bridge/MatrixHandler.ts index 52abee854..515d3bfc1 100644 --- a/src/bridge/MatrixHandler.ts +++ b/src/bridge/MatrixHandler.ts @@ -1088,7 +1088,6 @@ export class MatrixHandler { req.log.warn("Couldn't find an event being edited, using fallback text"); } } - req.log.debug(JSON.stringify(event.content)); const newBody = event.content["m.new_content"]?.body; if (originalBody && newBody) { const diff = niceDiff(originalBody, newBody); From 39293482b9aed119ab521548262619247c1062d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 14:51:12 +0200 Subject: [PATCH 06/26] Improve the changelog entry --- changelog.d/1465.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/1465.feature b/changelog.d/1465.feature index 002890847..894fba49d 100644 --- a/changelog.d/1465.feature +++ b/changelog.d/1465.feature @@ -1 +1 @@ -Make message edits more compact when possible +Render matrix message edits as sed-like diff statements, falling back to asterisk formatted messages From 9f534687f83ed598a72f32a668616cc69da63db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 14:52:56 +0200 Subject: [PATCH 07/26] Compact a definedness check --- src/bridge/MatrixHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bridge/MatrixHandler.ts b/src/bridge/MatrixHandler.ts index 515d3bfc1..466f21a63 100644 --- a/src/bridge/MatrixHandler.ts +++ b/src/bridge/MatrixHandler.ts @@ -1071,7 +1071,7 @@ export class MatrixHandler { } // special handling for edits - if (event.content["m.relates_to"] && event.content["m.relates_to"].rel_type === "m.replace") { + if (event.content["m.relates_to"]?.rel_type === "m.replace") { const originalEventId = event.content["m.relates_to"].event_id; let originalBody = this.getCachedEvent(originalEventId)?.body; if (!originalBody) { From 555538e7162fe4ec559890776da797558dbca23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 16:05:21 +0200 Subject: [PATCH 08/26] Ensure we don't use newlines in message edit diffs --- spec/unit/NiceDiff.spec.js | 5 +++++ src/util/NiceDiff.ts | 3 +++ 2 files changed, 8 insertions(+) diff --git a/spec/unit/NiceDiff.spec.js b/spec/unit/NiceDiff.spec.js index c8cd557bb..389573ec3 100644 --- a/spec/unit/NiceDiff.spec.js +++ b/spec/unit/NiceDiff.spec.js @@ -24,6 +24,11 @@ describe("niceDiff", function() { 'in a marmalade forest\nbetween the make-believe trees\nin a cottage-cheese cottage...', 's/I forgot the third verse, sorry/in a cottage-cheese cottage.../', ], + [ + 'should not use diffs with newlines in them', + 'a\nb\nc', 'bla\nbleh\nc', + 's/a/bla/, s/b/bleh/', + ], ].forEach(c => it(c[0], () => { const result = niceDiff(c[1], c[2]); console.log(`"${c[1]}" -> "${c[2]}" -> ${result}`); diff --git a/src/util/NiceDiff.ts b/src/util/NiceDiff.ts index 1b83dc84a..dd3e04afc 100644 --- a/src/util/NiceDiff.ts +++ b/src/util/NiceDiff.ts @@ -55,6 +55,9 @@ export function niceDiff(from: string, to: string): string|undefined { formatChanges(Diff.diffLines(from, to)), ].filter( diffs => diffs.length > 0 && diffs.length <= MAX_SUBSTITUTIONS + ).filter( + // a newline in a diff is a total disaster + diffs => !diffs.find(diff => diff.match(/\n/)) ).map( diffs => diffs.join(', ') ).sort( From 9767a0ae7da035b1afdb60e59efa74850841d6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 16:27:36 +0200 Subject: [PATCH 09/26] Make sure we can lookup original events from PM rooms --- src/bridge/MatrixHandler.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bridge/MatrixHandler.ts b/src/bridge/MatrixHandler.ts index 466f21a63..ec7682109 100644 --- a/src/bridge/MatrixHandler.ts +++ b/src/bridge/MatrixHandler.ts @@ -7,6 +7,7 @@ import { MembershipQueue, StateLookup, StateLookupEvent, + Intent, } from "matrix-appservice-bridge"; import { IrcUser } from "../models/IrcUser"; import { MatrixAction, MatrixMessageEvent } from "../models/MatrixAction"; @@ -1079,7 +1080,15 @@ export class MatrixHandler { // FIXME: this will return the new event rather than the original one // to actually see the original content we'd need to use whatever // https://github.com/matrix-org/matrix-doc/pull/2675 stabilizes on - const eventContent = await this.ircBridge.getAppServiceBridge().getIntent().getEvent( + let intent: Intent; + if (ircRoom.getType() === "pm") { + // no Matrix Bot, use the IRC user's intent + const userId = ircRoom.server.getUserIdFromNick(ircRoom.channel); + intent = this.ircBridge.getAppServiceBridge().getIntent(userId); + } else { + intent = this.ircBridge.getAppServiceBridge().getIntent(); + } + const eventContent = await intent.getEvent( event.room_id, originalEventId ); originalBody = eventContent.content.body; From 0859ce04d51f169875b1fbc98202e25165c121b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 16:49:22 +0200 Subject: [PATCH 10/26] Update NiceDiff' Co-authored-by: Will Hunt --- src/util/NiceDiff.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/NiceDiff.ts b/src/util/NiceDiff.ts index dd3e04afc..02ebaed25 100644 --- a/src/util/NiceDiff.ts +++ b/src/util/NiceDiff.ts @@ -41,8 +41,8 @@ const MAX_SUBSTITUTIONS = 3; * to be a better choice. Optimize for terseness, legibility * and an IRC-native feel. * - * @param {string} from : The original message - * @param {string} to : The new, edited version + * @param {string} from The original message + * @param {string} to The new, edited version */ export function niceDiff(from: string, to: string): string|undefined { // don't bother if the message is short enough From be49efb38e64d2d9bf34d9924a2dc1d12f5e6819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Wed, 18 Aug 2021 16:49:49 +0200 Subject: [PATCH 11/26] Rename niceDiff to messageDiff --- spec/unit/{NiceDiff.spec.js => MessageDiff.spec.js} | 4 ++-- src/bridge/MatrixHandler.ts | 7 ++++--- src/util/{NiceDiff.ts => MessageDiff.ts} | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) rename spec/unit/{NiceDiff.spec.js => MessageDiff.spec.js} (92%) rename src/util/{NiceDiff.ts => MessageDiff.ts} (96%) diff --git a/spec/unit/NiceDiff.spec.js b/spec/unit/MessageDiff.spec.js similarity index 92% rename from spec/unit/NiceDiff.spec.js rename to spec/unit/MessageDiff.spec.js index 389573ec3..c65d1d66f 100644 --- a/spec/unit/NiceDiff.spec.js +++ b/spec/unit/MessageDiff.spec.js @@ -1,5 +1,5 @@ "use strict"; -const { niceDiff } = require("../../lib/util/NiceDiff.js"); +const { messageDiff } = require("../../lib/util/MessageDiff.js"); describe("niceDiff", function() { [ @@ -30,7 +30,7 @@ describe("niceDiff", function() { 's/a/bla/, s/b/bleh/', ], ].forEach(c => it(c[0], () => { - const result = niceDiff(c[1], c[2]); + const result = messageDiff(c[1], c[2]); console.log(`"${c[1]}" -> "${c[2]}" -> ${result}`); expect(result).toBe(c[3]); })); diff --git a/src/bridge/MatrixHandler.ts b/src/bridge/MatrixHandler.ts index ec7682109..d4bfe6088 100644 --- a/src/bridge/MatrixHandler.ts +++ b/src/bridge/MatrixHandler.ts @@ -20,7 +20,7 @@ import { AdminRoomHandler } from "./AdminRoomHandler"; import { trackChannelAndCreateRoom } from "./RoomCreation"; import { renderTemplate } from "../util/Template"; import { trimString } from "../util/TrimString"; -import { niceDiff } from "../util/NiceDiff"; +import { messageDiff } from "../util/MessageDiff"; async function reqHandler(req: BridgeRequest, promise: PromiseLike) { try { @@ -1085,7 +1085,8 @@ export class MatrixHandler { // no Matrix Bot, use the IRC user's intent const userId = ircRoom.server.getUserIdFromNick(ircRoom.channel); intent = this.ircBridge.getAppServiceBridge().getIntent(userId); - } else { + } + else { intent = this.ircBridge.getAppServiceBridge().getIntent(); } const eventContent = await intent.getEvent( @@ -1099,7 +1100,7 @@ export class MatrixHandler { } const newBody = event.content["m.new_content"]?.body; if (originalBody && newBody) { - const diff = niceDiff(originalBody, newBody); + const diff = messageDiff(originalBody, newBody); if (diff) { ircAction.text = diff; } diff --git a/src/util/NiceDiff.ts b/src/util/MessageDiff.ts similarity index 96% rename from src/util/NiceDiff.ts rename to src/util/MessageDiff.ts index 02ebaed25..58a6423a7 100644 --- a/src/util/NiceDiff.ts +++ b/src/util/MessageDiff.ts @@ -44,7 +44,7 @@ const MAX_SUBSTITUTIONS = 3; * @param {string} from The original message * @param {string} to The new, edited version */ -export function niceDiff(from: string, to: string): string|undefined { +export function messageDiff(from: string, to: string): string|undefined { // don't bother if the message is short enough if (to.length < MIN_MESSAGE_LENGTH && !to.match(/\n/)) { return undefined; From e6a42b239f7bdc76e2178e198c79f773ca2ecfda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Thu, 19 Aug 2021 15:38:44 +0200 Subject: [PATCH 12/26] Fallback to sending an invite as a bot if the regular invite fails This works around an issue where an invite is sent before the room is fully configured, and the power level of the actual inviter is not yet known and set. --- changelog.d/1467.bugfix | 1 + src/bridge/IrcHandler.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 changelog.d/1467.bugfix diff --git a/changelog.d/1467.bugfix b/changelog.d/1467.bugfix new file mode 100644 index 000000000..e264fd7c3 --- /dev/null +++ b/changelog.d/1467.bugfix @@ -0,0 +1 @@ +Fallback to sending an invite as a bot if the regular invite fails diff --git a/src/bridge/IrcHandler.ts b/src/bridge/IrcHandler.ts index bfe7b016f..7c592992b 100644 --- a/src/bridge/IrcHandler.ts +++ b/src/bridge/IrcHandler.ts @@ -406,7 +406,15 @@ export class IrcHandler { virtualMatrixUser.getId() ).invite( room.getId(), invitee - ); + ).catch(err => { + req.log.warn( + `Failed to invite %s as the inviter user (reason: ${err}), + inviting as a bot as fallback` + ); + // TODO Note the original inviter in the reason + // once MSC 2367 stabilizes and is implemented by the SDK + return this.ircBridge.getAppServiceBridge().getIntent().invite(room.getId(), invitee); + }); }); await Promise.all(invitePromises); return undefined; From 8479d887d4e302f9d0648ec60330d9109d5c5d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Fri, 20 Aug 2021 10:05:30 +0200 Subject: [PATCH 13/26] Fix a logline Co-authored-by: Will Hunt --- src/bridge/IrcHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bridge/IrcHandler.ts b/src/bridge/IrcHandler.ts index 7c592992b..66d577328 100644 --- a/src/bridge/IrcHandler.ts +++ b/src/bridge/IrcHandler.ts @@ -408,7 +408,7 @@ export class IrcHandler { room.getId(), invitee ).catch(err => { req.log.warn( - `Failed to invite %s as the inviter user (reason: ${err}), + `Failed to invite ${invitee} as the inviter user (reason: ${err}), inviting as a bot as fallback` ); // TODO Note the original inviter in the reason From abe0f03156b4dc76430e0aa8cabcd81ef50b6061 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 20 Aug 2021 09:15:41 +0100 Subject: [PATCH 14/26] Remove mistake config line --- config.sample.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.sample.yaml b/config.sample.yaml index 82f16c532..866c6c667 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -453,7 +453,7 @@ ircService: # Encoding fallback - which text encoding to try if text is not UTF-8. Default: not set. # List of supported encodings: https://www.npmjs.com/package/iconv#supported-encodings # encodingFallback: "ISO-8859-15" - encodingFallback: "ISO-8859-15" + # Configuration for logging. Optional. Default: console debug level logging # only. # This key CANNOT be hot-reloaded From e1757d6b6fa15535b1560ad420101d231978eea2 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 20 Aug 2021 09:16:39 +0100 Subject: [PATCH 15/26] Create 1468.misc --- changelog.d/1468.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/1468.misc diff --git a/changelog.d/1468.misc b/changelog.d/1468.misc new file mode 100644 index 000000000..b228b6727 --- /dev/null +++ b/changelog.d/1468.misc @@ -0,0 +1 @@ +Remove extra `encodingFallback` from sample config. From 18d54e010086b01dc4cd24998b87e017fcb55845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Fri, 20 Aug 2021 15:44:13 +0200 Subject: [PATCH 16/26] Make sure we produce sensible diffs for additions and removals, not just substitutions --- spec/unit/MessageDiff.spec.js | 23 ++++++++++++++-- src/util/MessageDiff.ts | 51 ++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/spec/unit/MessageDiff.spec.js b/spec/unit/MessageDiff.spec.js index c65d1d66f..0188f5dcf 100644 --- a/spec/unit/MessageDiff.spec.js +++ b/spec/unit/MessageDiff.spec.js @@ -1,7 +1,7 @@ "use strict"; const { messageDiff } = require("../../lib/util/MessageDiff.js"); -describe("niceDiff", function() { +describe('messageDiff', function() { [ [ 'should not generate a diff if the message is short enough', @@ -29,9 +29,28 @@ describe("niceDiff", function() { 'a\nb\nc', 'bla\nbleh\nc', 's/a/bla/, s/b/bleh/', ], + [ + 'should only show small portion of the message when a new word is added', + 'this is a message where i a word', 'this is a message where i missed a word', + '* where i missed a word', + ], + [ + 'should only show small portion of the message when a new word is added at the beginning', + 'get lunch now, be back a bit later', 'gonna get lunch now, be back a bit later', + '* gonna get lunch', + ], + [ + 'should only show small portion of the message when a new word is added at the beginning', + "I'm gonna get lunch now", "I'm gonna get lunch now, bbl", + '* lunch now, bbl', + ], + [ + 'should show word removals as s/foo//', + 'I gotta go clean up my filthy room', 'I gotta go clean up my room', + 's/filthy//' + ], ].forEach(c => it(c[0], () => { const result = messageDiff(c[1], c[2]); - console.log(`"${c[1]}" -> "${c[2]}" -> ${result}`); expect(result).toBe(c[3]); })); }); diff --git a/src/util/MessageDiff.ts b/src/util/MessageDiff.ts index 58a6423a7..5cb2cbde4 100644 --- a/src/util/MessageDiff.ts +++ b/src/util/MessageDiff.ts @@ -17,17 +17,60 @@ limitations under the License. import * as Diff from 'diff'; function formatChanges(diff: Diff.Change[]): string[] { - const changes = []; + // true if Change represents... no change + const noChanges = (change: Diff.Change) => !change.added && !change.removed; + const substitutions = []; let i = 0; while (i < diff.length - 1) { - if (diff[i].removed && diff[i+1].added) { - changes.push([diff[i].value, diff[i+1].value]); + if (diff[i].removed) { + let replacement: string; + if (diff[i+1].added) { + replacement = diff[i+1].value; + } + else if (noChanges(diff[i+1])) { + replacement = ''; + } + else { + i++; + continue; + } + substitutions.push([diff[i].value.trim(), replacement]); } i++; } - return changes.map(c => `s/${c[0]}/${c[1]}/`); + const additions = []; + // noops before and after so that we can go through + // the entire thing without caring about bounds + const paddedDiff = [ + { value: '' } as Diff.Change, + ...diff, + { value: '' } as Diff.Change, + ]; + i = 1; + while (i < paddedDiff.length - 1) { + if (noChanges(paddedDiff[i - 1]) && paddedDiff[i].added && noChanges(paddedDiff[i + 1])) { + // ideally last two words of what was before... (regex always matches) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const prefix = paddedDiff[i - 1].value.match(/(\S+\s+)?\S*\s*$/)![0]; + // ...and first two words of what followed (regex always matches) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const postfix = paddedDiff[i + 1].value.match(/^\S*(\s+\S+)?/)![0]; + + additions.push([prefix, paddedDiff[i].value, postfix]); + } + i++; + } + + // if it mixes substitutions and additions, give up - it's not gonna be very readable + if (substitutions.length > 0 && additions.length === 0) { + return substitutions.map(c => `s/${c[0]}/${c[1]}/`); + } + if (substitutions.length === 0 && additions.length > 0) { + return additions.map(a => `* ${a.join('')}`); + } + return []; } // Minimum length of the message for us to try to generate a diff for From 1158f6e504a952c47cc2f0529160ee8599c190cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Fri, 20 Aug 2021 10:48:34 +0200 Subject: [PATCH 17/26] Mention the original inviter in the invite reason when inviting on their behalf --- src/bridge/IrcHandler.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/bridge/IrcHandler.ts b/src/bridge/IrcHandler.ts index 66d577328..b5c338952 100644 --- a/src/bridge/IrcHandler.ts +++ b/src/bridge/IrcHandler.ts @@ -411,9 +411,12 @@ export class IrcHandler { `Failed to invite ${invitee} as the inviter user (reason: ${err}), inviting as a bot as fallback` ); - // TODO Note the original inviter in the reason - // once MSC 2367 stabilizes and is implemented by the SDK - return this.ircBridge.getAppServiceBridge().getIntent().invite(room.getId(), invitee); + return this.ircBridge.getAppServiceBridge().getIntent().sendStateEvent( + room.getId(), "m.room.member", invitee, { + membership: "invite", + reason: `Invited by ${virtualMatrixUser.getDisplayName()} (${virtualMatrixUser.getId()})`, + } + ); }); }); await Promise.all(invitePromises); From ac87eba9ccf48e4c07b9ecf7df16d0ae52d67a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Mon, 23 Aug 2021 11:17:05 +0200 Subject: [PATCH 18/26] 0.31.0-rc1 --- CHANGELOG.md | 31 ++++++++++++++++++++++++++++++- changelog.d/1458.doc | 1 - changelog.d/1459.bugfix | 1 - changelog.d/1461.bugfix | 1 - changelog.d/1465.feature | 1 - changelog.d/1467.bugfix | 1 - changelog.d/1468.misc | 1 - package-lock.json | 5 +++-- package.json | 2 +- 9 files changed, 34 insertions(+), 10 deletions(-) delete mode 100644 changelog.d/1458.doc delete mode 100644 changelog.d/1459.bugfix delete mode 100644 changelog.d/1461.bugfix delete mode 100644 changelog.d/1465.feature delete mode 100644 changelog.d/1467.bugfix delete mode 100644 changelog.d/1468.misc diff --git a/CHANGELOG.md b/CHANGELOG.md index bf2e4874f..3a533b1e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,33 @@ - 0.30.0 (2021-08-18) + 0.31.0-rc1 (2021-08-23) +======================== + +Features +-------- + +- Render matrix message edits as sed-like diff statements, falling back to asterisk formatted messages ([\#1465](https://github.com/matrix-org/matrix-appservice-irc/issues/1465)) + + +Bugfixes +-------- + +- Make sure we don't exceed the line limit when trimming long messages ([\#1459](https://github.com/matrix-org/matrix-appservice-irc/issues/1459)) +- Make sure Matrix notice messages are also pastebinned when they exceed the line limit for IRC. ([\#1461](https://github.com/matrix-org/matrix-appservice-irc/issues/1461)) +- Fallback to sending an invite as a bot if the regular invite fails ([\#1467](https://github.com/matrix-org/matrix-appservice-irc/issues/1467)) + + +Improved Documentation +---------------------- + +- Replace HOWTO.md with a link to our hosted documentation, and generally improve documentation wording. ([\#1458](https://github.com/matrix-org/matrix-appservice-irc/issues/1458)) + + +Internal Changes +---------------- + +- Remove extra `encodingFallback` from sample config. ([\#1468](https://github.com/matrix-org/matrix-appservice-irc/issues/1468)) + + +0.30.0 (2021-08-18) ==================== No significant changes. diff --git a/changelog.d/1458.doc b/changelog.d/1458.doc deleted file mode 100644 index 075b8dcb3..000000000 --- a/changelog.d/1458.doc +++ /dev/null @@ -1 +0,0 @@ -Replace HOWTO.md with a link to our hosted documentation, and generally improve documentation wording. \ No newline at end of file diff --git a/changelog.d/1459.bugfix b/changelog.d/1459.bugfix deleted file mode 100644 index e8e0bdd3d..000000000 --- a/changelog.d/1459.bugfix +++ /dev/null @@ -1 +0,0 @@ -Make sure we don't exceed the line limit when trimming long messages diff --git a/changelog.d/1461.bugfix b/changelog.d/1461.bugfix deleted file mode 100644 index f200af82d..000000000 --- a/changelog.d/1461.bugfix +++ /dev/null @@ -1 +0,0 @@ -Make sure Matrix notice messages are also pastebinned when they exceed the line limit for IRC. diff --git a/changelog.d/1465.feature b/changelog.d/1465.feature deleted file mode 100644 index 894fba49d..000000000 --- a/changelog.d/1465.feature +++ /dev/null @@ -1 +0,0 @@ -Render matrix message edits as sed-like diff statements, falling back to asterisk formatted messages diff --git a/changelog.d/1467.bugfix b/changelog.d/1467.bugfix deleted file mode 100644 index e264fd7c3..000000000 --- a/changelog.d/1467.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fallback to sending an invite as a bot if the regular invite fails diff --git a/changelog.d/1468.misc b/changelog.d/1468.misc deleted file mode 100644 index b228b6727..000000000 --- a/changelog.d/1468.misc +++ /dev/null @@ -1 +0,0 @@ -Remove extra `encodingFallback` from sample config. diff --git a/package-lock.json b/package-lock.json index 36befbf13..a9f34e5f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,12 @@ { "name": "matrix-appservice-irc", - "version": "0.30.0", + "version": "0.31.0-rc1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.30.0", + "name": "matrix-appservice-irc", + "version": "0.31.0-rc1", "license": "Apache-2.0", "dependencies": { "@sentry/node": "^5.27.1", diff --git a/package.json b/package.json index fbd800332..09cdf10be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-appservice-irc", - "version": "0.30.0", + "version": "0.31.0-rc1", "description": "An IRC Bridge for Matrix", "main": "app.js", "bin": "./bin/matrix-appservice-irc", From 14602769326e0a099f269d7b890290033eaa4c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20So=C5=9Bnierz?= Date: Mon, 23 Aug 2021 11:46:44 +0200 Subject: [PATCH 19/26] Fix capitalisation in the changelog Co-authored-by: Will Hunt --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a533b1e9..84bd578e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ Features -------- -- Render matrix message edits as sed-like diff statements, falling back to asterisk formatted messages ([\#1465](https://github.com/matrix-org/matrix-appservice-irc/issues/1465)) +- Render Matrix message edits as sed-like diff statements, falling back to asterisk formatted messages ([\#1465](https://github.com/matrix-org/matrix-appservice-irc/issues/1465)) Bugfixes From 8d84185f03f5c7f8de3bcbfd28d6d5fb036292f6 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 25 Aug 2021 15:38:04 +0100 Subject: [PATCH 20/26] Remove unique index on usernames for NeDB --- changelog.d/1471.bugfix | 1 + src/datastore/NedbDataStore.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/1471.bugfix diff --git a/changelog.d/1471.bugfix b/changelog.d/1471.bugfix new file mode 100644 index 000000000..58ce74b1a --- /dev/null +++ b/changelog.d/1471.bugfix @@ -0,0 +1 @@ +Fixed an issue where bridges using the NEdB datastore would still erroneously require IRC usernames to be unique. \ No newline at end of file diff --git a/src/datastore/NedbDataStore.ts b/src/datastore/NedbDataStore.ts index 817728449..9309ea06e 100644 --- a/src/datastore/NedbDataStore.ts +++ b/src/datastore/NedbDataStore.ts @@ -105,7 +105,7 @@ export class NeDBDataStore implements DataStore { const domainKey = server.domain.replace(/\./g, "_"); this.userStore.db.ensureIndex({ fieldName: "data.client_config." + domainKey + ".username", - unique: true, + unique: false, sparse: true }, (err: Error|null) => { if (err) { From e8bac917e2cc804b0cd85cc536a0bcd4d3546700 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 14 Sep 2021 10:54:32 +0100 Subject: [PATCH 21/26] Fix help not showing admin commands --- src/bridge/AdminRoomHandler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bridge/AdminRoomHandler.ts b/src/bridge/AdminRoomHandler.ts index 02f3618f7..212bfaed5 100644 --- a/src/bridge/AdminRoomHandler.ts +++ b/src/bridge/AdminRoomHandler.ts @@ -714,7 +714,8 @@ export class AdminRoomHandler { return new MatrixAction("notice", `BridgeVersion: ${getBridgeVersion()}`); } - private showHelp(userPermission: string|undefined): MatrixAction { + private showHelp(sender: string): MatrixAction { + const userPermission = this.getUserPermission(sender); let body = "This is an IRC admin room for controlling your IRC connection and sending " + "commands directly to IRC.
" + "See the " + From 4808c6630c7341b04d72e02289a9b12fa9e3880e Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 14 Sep 2021 11:01:43 +0100 Subject: [PATCH 22/26] Use an enum to avoid type confusion --- src/bridge/AdminRoomHandler.ts | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/bridge/AdminRoomHandler.ts b/src/bridge/AdminRoomHandler.ts index 212bfaed5..00dcbceaa 100644 --- a/src/bridge/AdminRoomHandler.ts +++ b/src/bridge/AdminRoomHandler.ts @@ -30,13 +30,18 @@ import { IdentGenerator } from "../irc/IdentGenerator"; const log = logging("AdminRoomHandler"); +enum CommandPermission { + User, + Admin, +} + // This is just a length to avoid silly long usernames const SANE_USERNAME_LENGTH = 64; interface Command { example: string; summary: string; - requiresPermission?: string; + requiresPermission?: CommandPermission; } interface Heading { @@ -104,7 +109,7 @@ const COMMANDS: {[command: string]: Command|Heading} = { '!plumb': { example: `!plumb !room:example.com irc.example.net #foobar`, summary: "Plumb an IRC channel into a Matrix room.", - requiresPermission: 'admin' + requiresPermission: CommandPermission.Admin, }, '!unlink': { example: "!unlink !room:example.com irc.example.net #foobar", @@ -151,6 +156,11 @@ export class AdminRoomHandler { } private async handleCommand(cmd: string, args: string[], req: BridgeRequest, event: MatrixSimpleMessage) { + const userPermission = this.getUserPermission(event.sender); + const requiredPermission = (COMMANDS[cmd] as Command|undefined)?.requiresPermission; + if (requiredPermission && requiredPermission > userPermission) { + return new MatrixAction("notice", "You do not have permission to use this command"); + } switch (cmd) { case "!join": return await this.handleJoin(req, args, event.sender); @@ -191,10 +201,6 @@ export class AdminRoomHandler { } private async handlePlumb(args: string[], sender: string) { - const userPermission = this.getUserPermission(sender); - if (userPermission !== 'admin') { - return new MatrixAction("notice", "You must be an admin to use this command"); - } const [matrixRoomId, serverDomain, ircChannel] = args; const server = serverDomain && this.ircBridge.getServer(serverDomain); if (!server) { @@ -249,7 +255,7 @@ export class AdminRoomHandler { user_id: sender, }, ), - userPermission === "admin" + userPermission === CommandPermission.Admin ); } catch (ex) { @@ -754,12 +760,18 @@ export class AdminRoomHandler { return this.ircBridge.getBridgedClientsForUserId(userId); } - private getUserPermission(userId: string): string|undefined { + private getUserPermission(userId: string): CommandPermission { const userDomain = userId.split(':')[1]; - return this.ircBridge.config.ircService.permissions && + const permissionString = this.ircBridge.config.ircService.permissions && (this.ircBridge.config.ircService.permissions[userId] || // This takes priority this.ircBridge.config.ircService.permissions[userDomain] || // Then the domain this.ircBridge.config.ircService.permissions['*']); // Finally wildcard. + switch (permissionString) { + case "admin": + return CommandPermission.Admin; + default: + return CommandPermission.User; + } } } From 381ed87ec6c1e479596d721b5ba122abd18d7b49 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 14 Sep 2021 11:02:55 +0100 Subject: [PATCH 23/26] changelog --- changelog.d/1478.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/1478.bugfix diff --git a/changelog.d/1478.bugfix b/changelog.d/1478.bugfix new file mode 100644 index 000000000..9b86c1507 --- /dev/null +++ b/changelog.d/1478.bugfix @@ -0,0 +1 @@ +Fixed a bug where `!help` in an admin room would not show admin commands. \ No newline at end of file From 3fda80ef0ac89ade3662d11b5f653ad604e69697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20=E2=80=9Etadzik=E2=80=9D=20So=C5=9Bnierz?= Date: Wed, 15 Sep 2021 12:24:51 +0200 Subject: [PATCH 24/26] Fallback to generic profile displayname if we can't get the bot to join the proper room This happens if a matrix users PMs an IRC user while not being in any channel. --- src/bridge/MatrixHandler.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/bridge/MatrixHandler.ts b/src/bridge/MatrixHandler.ts index fc3f9a6f4..02ac761f6 100644 --- a/src/bridge/MatrixHandler.ts +++ b/src/bridge/MatrixHandler.ts @@ -1006,17 +1006,17 @@ export class MatrixHandler { let bridgedClient = this.ircBridge.getIrcUserFromCache(ircRoom.server, event.sender); if (!bridgedClient) { messageSendPromiseSet.push((async () => { - let displayName = undefined; - try { - const res = await this.ircBridge.getAppServiceBridge().getIntent().getStateEvent( - event.room_id, "m.room.member", event.sender - ); - displayName = res.displayname; - } - catch (err) { - req.log.warn("Failed to get display name: %s", err); - // this is non-fatal, continue. - } + const intent = this.ircBridge.getAppServiceBridge().getIntent(); + const displayName = await intent.getStateEvent( + event.room_id, "m.room.member", event.sender + ).catch(err => { + req.log.warn(`Failed to get display name for the room: ${err}`); + return intent.getProfileInfo(event.sender, "displayname"); + }).then( + res => res.displayname + ).catch(err => { + req.log.error(`Failed to get display name: ${err}`); + }); bridgedClient = await this.ircBridge.getBridgedClient( ircRoom.server, event.sender, displayName ); From db6d38e50f193e3ce8819385c65f5a89b0632e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20=E2=80=9Etadzik=E2=80=9D=20So=C5=9Bnierz?= Date: Wed, 15 Sep 2021 13:35:39 +0200 Subject: [PATCH 25/26] Add changelog entry --- changelog.d/1479.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/1479.bugfix diff --git a/changelog.d/1479.bugfix b/changelog.d/1479.bugfix new file mode 100644 index 000000000..71162d8e1 --- /dev/null +++ b/changelog.d/1479.bugfix @@ -0,0 +1 @@ +Fix an edgecase where an nickname was not always set right for matrix users in PMs From f8f5dbb2dfdd4da2678b29968d13afcbb0274273 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Mon, 20 Sep 2021 10:01:29 +0100 Subject: [PATCH 26/26] 0.31.0 --- CHANGELOG.md | 13 ++++++++++++- changelog.d/1471.bugfix | 1 - changelog.d/1478.bugfix | 1 - changelog.d/1479.bugfix | 1 - package-lock.json | 5 ++--- package.json | 2 +- 6 files changed, 15 insertions(+), 8 deletions(-) delete mode 100644 changelog.d/1471.bugfix delete mode 100644 changelog.d/1478.bugfix delete mode 100644 changelog.d/1479.bugfix diff --git a/CHANGELOG.md b/CHANGELOG.md index 84bd578e4..a2b6879c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ - 0.31.0-rc1 (2021-08-23) +0.31.0 (2021-09-20) +======================== + +Bugfixes +-------- + +- Fixed an issue where bridges using the NEdB datastore would still erroneously require IRC usernames to be unique. ([\#1471](https://github.com/matrix-org/matrix-appservice-irc/issues/1471)) +- Fixed a bug where `!help` in an admin room would not show admin commands. ([\#1478](https://github.com/matrix-org/matrix-appservice-irc/issues/1478)) +- Fix an edgecase where an nickname was not always set right for matrix users in PMs ([\#1479](https://github.com/matrix-org/matrix-appservice-irc/issues/1479)) + + +0.31.0-rc1 (2021-08-23) ======================== Features diff --git a/changelog.d/1471.bugfix b/changelog.d/1471.bugfix deleted file mode 100644 index 58ce74b1a..000000000 --- a/changelog.d/1471.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed an issue where bridges using the NEdB datastore would still erroneously require IRC usernames to be unique. \ No newline at end of file diff --git a/changelog.d/1478.bugfix b/changelog.d/1478.bugfix deleted file mode 100644 index 9b86c1507..000000000 --- a/changelog.d/1478.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fixed a bug where `!help` in an admin room would not show admin commands. \ No newline at end of file diff --git a/changelog.d/1479.bugfix b/changelog.d/1479.bugfix deleted file mode 100644 index 71162d8e1..000000000 --- a/changelog.d/1479.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix an edgecase where an nickname was not always set right for matrix users in PMs diff --git a/package-lock.json b/package-lock.json index a9f34e5f3..2e670a464 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,11 @@ { "name": "matrix-appservice-irc", - "version": "0.31.0-rc1", + "version": "0.31.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "matrix-appservice-irc", - "version": "0.31.0-rc1", + "version": "0.31.0", "license": "Apache-2.0", "dependencies": { "@sentry/node": "^5.27.1", diff --git a/package.json b/package.json index 09cdf10be..ff7508faf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-appservice-irc", - "version": "0.31.0-rc1", + "version": "0.31.0", "description": "An IRC Bridge for Matrix", "main": "app.js", "bin": "./bin/matrix-appservice-irc",