diff --git a/changelog.d/1374.feature b/changelog.d/1374.feature new file mode 100644 index 000000000..7ce8ca694 --- /dev/null +++ b/changelog.d/1374.feature @@ -0,0 +1,11 @@ +Add ability to specify realname by template. + +This deprecates the old mxid/reverse-mxid format (though it's still available). +Behaves similar to nickTemplate. Available templating variables: + +* `$DISPLAY`: Matrix user display name +* `$USERID`:User mxid +* `$LOCALPART`: Matrix user localpart +* `$REVERSEID`: User mxid with host and localpart swapped +* `$IRCUSER`: IRC username + diff --git a/config.sample.yaml b/config.sample.yaml index 82f16c532..3d645536a 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -404,8 +404,11 @@ ircService: # through the bridge e.g. caller ID as there is no way to /ACCEPT. # Default: "" (no user modes) # userModes: "R" - # The format of the realname defined for users, either mxid or reverse-mxid - realnameFormat: "mxid" + # The format of the realname defined for users. This MUST have either + # $DISPLAY, $USERID, $LOCALPART, $REVERSEID or $IRCUSER somewhere in it. + # The template to apply to every IRC client nick. + # Note that realnames longer than 48 characters will be trucated. + realnameFormat: "$USERID" # The minimum time to wait between connection attempts if we were disconnected # due to throttling. # pingTimeoutMs: 600000 diff --git a/config.schema.yml b/config.schema.yml index 1cf7a1eac..bbd53a50f 100644 --- a/config.schema.yml +++ b/config.schema.yml @@ -329,7 +329,7 @@ properties: type: "string" aliasTemplate: type: "string" - pattern: "^(#.*\\$CHANNEL|\\$CHANNEL)$" + pattern: "^(#.*\\$CHANNEL.*|\\$CHANNEL)$" whitelist: type: "array" items: @@ -391,7 +391,7 @@ properties: type: "boolean" realnameFormat: type: "string" - enum: ["mxid","reverse-mxid"] + pattern: "\\$USERID|\\$LOCALPART|\\$DISPLAY|\\$REVERSEID|\\$IRCUSER" ipv6: type: "object" properties: diff --git a/spec/unit/IdentGenerator.spec.js b/spec/unit/IdentGenerator.spec.js index 30659a885..80bcfbb2d 100644 --- a/spec/unit/IdentGenerator.spec.js +++ b/spec/unit/IdentGenerator.spec.js @@ -65,7 +65,7 @@ describe("Username generation", function() { expect(info.username).toEqual(uname); }); - it("should reverse the userID", async function() { + it("should reverse the userID according to legacy format", async function() { var userId = "@myreallylonguseridhere:localhost"; const info = await identGenerator.getIrcNames(ircClientConfig, { getRealNameFormat: () => "reverse-mxid", @@ -74,6 +74,21 @@ describe("Username generation", function() { expect(info.realname).toEqual("localhost:myreallylonguseridhere"); }); + it("should allow template userID", async function() { + var userId = "@mxuser:localhost"; + const user = new MatrixUser(userId); + user.setDisplayName('bar'); + ircClientConfig.getUsername = () => 'foo'; + let info = await identGenerator.getIrcNames(ircClientConfig, { + getRealNameFormat: () => "$USERID_$REVERSEID_suffix", + }, user); + expect(info.realname).toEqual("@mxuser:localhost_localhost:mxuser_suffix"); + info = await identGenerator.getIrcNames(ircClientConfig, { + getRealNameFormat: () => "$IRCUSER_$DISPLAY_$LOCALPART_suffix", + }, user); + expect(info.realname).toEqual("foo_bar_mxuser_suffix"); + }); + it("should start with '_1' on an occupied user ID", async function() { const userId = "@myreallylonguseridhere:localhost"; const uname = "myreal_1"; diff --git a/src/irc/IdentGenerator.ts b/src/irc/IdentGenerator.ts index 7a2b5cf16..f1c17ba9d 100644 --- a/src/irc/IdentGenerator.ts +++ b/src/irc/IdentGenerator.ts @@ -20,6 +20,7 @@ import { DataStore } from "../datastore/DataStore"; import { MatrixUser } from "matrix-appservice-bridge"; import { IrcClientConfig } from "../models/IrcClientConfig"; import { IrcServer } from "./IrcServer"; +import { renderTemplate } from "../util/Template"; const log = getLogger("IdentGenerator"); @@ -66,18 +67,29 @@ export class IdentGenerator { let realname: string; if (!matrixUser) { - realname = IdentGenerator.sanitiseRealname(username || ""); + realname = username || ""; } else if (server.getRealNameFormat() === "mxid") { - realname = IdentGenerator.sanitiseRealname(matrixUser.getId()); + realname = matrixUser.getId(); + log.warn("** The IrcClient.realnameFormat config schema has changed, allowing legacy format for now. **"); + log.warn("See https://github.com/matrix-org/matrix-appservice-irc/blob/master/CHANGELOG.md for details"); } else if (server.getRealNameFormat() === "reverse-mxid") { - realname = IdentGenerator.sanitiseRealname(IdentGenerator.switchAroundMxid(matrixUser)); + realname = IdentGenerator.switchAroundMxid(matrixUser); + log.warn("** The IrcClient.realnameFormat config schema has changed, allowing legacy format for now. **"); + log.warn("See https://github.com/matrix-org/matrix-appservice-irc/blob/master/CHANGELOG.md for details"); } else { - throw Error('Invalid value for realNameFormat'); + realname = renderTemplate(server.getRealNameFormat(), { + userId: matrixUser.userId, + localpart: matrixUser.localpart, + display: matrixUser.getDisplayName() || "", + reverseId: IdentGenerator.switchAroundMxid(matrixUser), + ircUser: username || "" + }); } + realname = IdentGenerator.sanitiseRealname(realname); realname = realname.substring(0, IdentGenerator.MAX_REAL_NAME_LENGTH); if (matrixUser) {