matrix-org / matrix-appservice-irc

Node.js IRC bridge for Matrix
Apache License 2.0
467 stars 151 forks source link

M_INVALID_USERNAME when setting a profile from IRC to Matrix #1432

Open erdnaxe opened 3 years ago

erdnaxe commented 3 years ago

Describe the bug

I am getting M_INVALID_USERNAME errors when joining a bridging a IRC room with membershipLists synced

Jul 25 10:27:11 neocarie node[56160]: 2021-07-25 10:27:11 INFO:req [5gu6dhb121400] [[I->M]] onJoin(names) toto[z] to #general
Jul 25 10:27:11 neocarie node[56160]: 2021-07-25 10:27:11 INFO:IrcBridge irc_toto[z] does not exist in the store yet, setting a profile
Jul 25 10:27:11 neocarie node[56160]: 2021-07-25 10:27:11 INFO:IrcBridge [-] POST https://matrix.[DOMAIN]:8448/_matrix/client/r0/register (AS) Body: "{\"type\":\"m.login.application_service\",\"username\":\"irc_toto[z]\"}"
Jul 25 10:27:11 neocarie node[56160]: 2021-07-25 10:27:11 ERROR:IrcBridge [-] POST https://matrix.[DOMAIN]:8448/_matrix/client/r0/register (AS) HTTP 400 Error: "{\"errcode\":\"M_INVALID_USERNAME\",\"error\":\"Username can only contain characters a-z, 0-9, or '_-./='\"}"

([DOMAIN] is my domain name that I removed from the logs)

Configuration

# Configuration specific to AS registration. Unless other marked, all fields
# are *REQUIRED*.
# Unless otherwise specified, these keys CANNOT be hot-reloaded.
homeserver:
  # The URL to the home server for client-server API calls, also used to form the
  # media URLs as displayed in bridged IRC channels:
  url: "https://matrix.[DOMAIN]:8448"

  # The 'domain' part for user IDs on this home server. Usually (but not always)
  # is the "domain name" part of the HS URL.
  domain: "[DOMAIN]"

  # Should presence be enabled for matrix clients on this bridge. If disabled on the
  # homeserver then it should also be disabled here to avoid excess traffic.
  # Default: true
  enablePresence: false

  # Which port should the appservice bind to. Can be overriden by the one provided in the
  # command line! Optional.
  bindPort: 8009

  # Use this option to force the appservice to listen on another hostname for transactions.
  # This is NOT your synapse hostname. E.g. use 127.0.0.1 to only listen locally. Optional.
  bindHostname: 127.0.0.1

# Configuration specific to the IRC service
ircService:
  # All server keys can be hot-reloaded, however existing IRC connections
  # will not have changes applied to them.
  servers:
    # The address of the server to connect to.
    irc.[DOMAIN]:
      # A human-readable short name. This is used to label IRC status rooms
      # where matrix users control their connections.
      # E.g. 'ExampleNet IRC Bridge status'.
      # It is also used in the Third Party Lookup API as the instance `desc`
      # property, where each server is an instance.
      name: "[DOMAIN]"
      # Additional addresses to connect to, used for load balancing between IRCDs.
      additionalAddresses: []
      # Typically additionalAddresses would be in addition to the address key given above,
      # but some configurations wish to exclusively use additional addresses while reserving
      # the top key for identification purposes. Set this to true to exclusively use the
      # additionalAddresses array when connecting to servers.
      onlyAdditionalAddresses: false

      # The port to connect to. Optional.
      port: 6697
      # Whether to use SSL or not. Default: false.
      ssl: true
      # Whether or not IRC server is using a self-signed cert or not providing CA Chain
      sslselfsign: true

      # A map for conversion of IRC user modes to Matrix power levels. This enables bridging
      # of IRC ops to Matrix power levels only, it does not enable the reverse. If a user has
      # been given multiple modes, the one that maps to the highest power level will be used.
      modePowerMap:
        o: 50
        v: 1

      botConfig:
        # Enable the presence of the bot in IRC channels. The bot serves as the entity
        # which maps from IRC -> Matrix. You can disable the bot entirely which
        # means IRC -> Matrix chat will be shared by active "M-Nick" connections
        # in the room. If there are no users in the room (or if there are users
        # but their connections are not on IRC) then nothing will be bridged to
        # Matrix. If you're concerned about the bot being treated as a "logger"
        # entity, then you may want to disable the bot. If you want IRC->Matrix
        # but don't want to have TCP connections to IRC unless a Matrix user speaks
        # (because your client connection limit is low), then you may want to keep
        # the bot enabled. Default: true.
        # NB: If the bot is disabled, you SHOULD have matrix-to-IRC syncing turned
        #     on, else there will be no users and no bot in a channel (meaning no
        #     messages to Matrix!) until a Matrix user speaks which makes a client
        #     join the target IRC channel.
        # NBB: The bridge bot IRC client will still join the target IRC network so
        #      it can service bridge-specific queries from the IRC-side e.g. so
        #      real IRC clients have a way to change their Matrix display name.
        #      See https://github.com/matrix-org/matrix-appservice-irc/issues/55
        enabled: false

      # Configuration for PMs / private 1:1 communications between users.
      privateMessages:
        # Enable the ability for PMs to be sent to/from IRC/Matrix.
        # Default: true.
        enabled: true

      # Configuration for mappings not explicitly listed in the 'mappings'
      # section.
      dynamicChannels:
        # Enable the ability for Matrix users to join *any* channel on this IRC
        # network.
        # Default: false.
        enabled: true
        # The room alias template to apply when creating new aliases. This only
        # applies if createAlias is 'true'. The following variables are exposed:
        # $SERVER => The IRC server address (e.g. "irc.example.com")
        # $CHANNEL => The IRC channel (e.g. "#python")
        # This MUST have $CHANNEL somewhere in it.
        #
        # In certain circumstances you might want to bridge your whole IRC network as a
        # homeserver (e.g. #matrix:libera.chat). For these use cases, you can set the
        # template to just be $CHANNEL. Doing so will preclude you from supporting
        # other prefix characters though.
        #
        # Default: '#irc_$SERVER_$CHANNEL'
        aliasTemplate: "$CHANNEL"

      # Configuration for controlling how Matrix and IRC membership lists are
      # synced.
      membershipLists:
        # Enable the syncing of membership lists between IRC and Matrix. This
        # can have a significant effect on performance on startup as the lists are
        # synced. This must be enabled for anything else in this section to take
        # effect. Default: false.
        enabled: true

        global:
          ircToMatrix:
            # Get a snapshot of all real IRC users on a channel (via NAMES) and
            # join their virtual matrix clients to the room.
            initial: true
            # Make virtual matrix clients join and leave rooms as their real IRC
            # counterparts join/part channels. Default: false.
            incremental: true
            # Should the bridge check if all Matrix users are connected to IRC and
            # joined to the channel before relaying messages into the room.
            #
            # This is considered a safety net to avoid any leakages by the bridge to
            # unconnected users, but given it ignores all IRC messages while users
            # are still connecting it may be overkill.
            requireMatrixJoined: true

          matrixToIrc:
            # Get a snapshot of all real Matrix users in the room and join all of
            # them to the mapped IRC channel on startup. Default: false.
            initial: true
            # Make virtual IRC clients join and leave channels as their real Matrix
            # counterparts join/leave rooms. Make sure your 'maxClients' value is
            # high enough! Default: false.
            incremental: true

      # Configuration for virtual matrix users. The following variables are
      # exposed:
      # $NICK => The IRC nick
      # $SERVER => The IRC server address (e.g. "irc.example.com")
      matrixClients:
        # The user ID template to use when creating virtual matrix users. This
        # MUST have $NICK somewhere in it.
        # Optional. Default: "@$SERVER_$NICK".
        # Example: "@irc.example.com_Alice:example.com"
        userTemplate: "@irc_$NICK"
        # The display name to use for created matrix clients. This should have
        # $NICK somewhere in it if it is specified. Can also use $SERVER to
        # insert the IRC domain.
        # Optional. Default: "$NICK (IRC)". Example: "Alice (IRC)"
        displayName: "$NICK"

      # Configuration for virtual IRC users. The following variables are exposed:
      # $LOCALPART => The user ID localpart ("alice" in @alice:localhost)
      # $USERID => The user ID
      # $DISPLAY => The display name of this user, with excluded characters
      #             (e.g. space) removed. If the user has no display name, this
      #             falls back to $LOCALPART.
      ircClients:
        # The template to apply to every IRC client nick. This MUST have either
        # $DISPLAY or $USERID or $LOCALPART somewhere in it.
        # Optional. Default: "M-$DISPLAY". Example: "M-Alice".
        nickTemplate: "$DISPLAY"
        # True to allow virtual IRC clients to change their nick on this server
        # by issuing !nick <server> <nick> commands to the IRC AS bot.
        # This is completely freeform: it will NOT follow the nickTemplate.
        allowNickChanges: true
        # The max number of IRC clients that will connect. If the limit is
        # reached, the client that spoke the longest time ago will be
        # disconnected and replaced.
        # Optional. Default: 30.
        maxClients: 500
        # The number of lines to allow being sent by the IRC client that has received
        # a large block of text to send from matrix. If the number of lines that would
        # be sent is > lineLimit, the text will instead be uploaded to matrix and the
        # resulting URI is treated as a file. As such, a link will be sent to the IRC
        # side instead of potentially spamming IRC and getting the IRC client kicked.
        # Default: 3.
        lineLimit: 10
        # Choose which conditions the IRC bridge should kick Matrix users for. Decisions to this from
        # defaults should be taken with care as it may dishonestly repesent Matrix users on the IRC
        # network, and cause your bridge to be banned.
        kickOn:
          # Kick a Matrix user from a bridged room if they fail to join the IRC channel.
          channelJoinFailure: true
          # Kick a Matrix user from ALL rooms if they are unable to get connected to IRC.
          ircConnectionFailure: true
          # Kick a Matrix user from ALL rooms if they choose to QUIT the IRC network.
          userQuit: true

  # Configuration for logging. Optional. Default: console debug level logging
  # only.
  # This key CANNOT be hot-reloaded
  logging:
    # Level to log on console/logfile. One of error|warn|info|debug
    level: "info"

# Use an external database to store bridge state.
# This key CANNOT be hot-reloaded.
database:
  # database engine (must be 'postgres' or 'nedb'). Default: nedb
  engine: "postgres"
   # Either a PostgreSQL connection string, or a path to the NeDB storage directory.
   # For postgres, it must start with postgres://
   # For NeDB, it must start with nedb://. The path is relative to the project directory.
  connectionString: "postgres://matrix-appservice-irc:CHANGE_ME@localhost:5432/matrix-appservice-irc"

The appservice works and I am able to send and receive messages from both ends. The appservice bot user is buggy (can not invite and does not respond to !help), but I believe that's a separate issue.

Expected behavior I would expect the appservice to normalize IRC usernames to make them fit the Matrix constraints.

Server:

Half-Shot commented 3 years ago

This is hard :(

The bridge is not spec compliant because it allows characters in the ghost names which should not be present in a Matrix ID, (such as [, ]). Synapse allows the bridge to use these characters because it's been left in for legacy reasons, but Dendrite is spec compliant and does not.

The fix is for the bridge to encode these usernames in such a way that we can work with spec complaint bridges. In the meantime, perhaps you can approach the Dendrite developers on this one?