the-draupnir-project/Draupnir

Draupnir unable to use Synapse Admin commands

Closed this issue · 11 comments

Matrix Setup

I'm relatively new to setting up Matrix and am trying to use Draupnir for moderation. We utilize the spantaleev/matrix-docker-ansible-deploy Ansible playbook.

The following related YAML vars have been set up:

matrix_bot_draupnir_enabled: true
matrix_bot_draupnir_access_token: "{{ draupnir_access_token }}"
matrix_bot_draupnir_management_room: "!<redacted>:example.org"

Draupnir Setup

I registered the draupnir.bot account using the following account (without Admin) at first:

ansible-playbook -i inventory/hosts setup.yml --extra-vars='username=bot.draupnir password=<redacted> admin=no' --tags=register-user

However, afterwards I gave it Server Admin using Synapse Admin, see below:
image

Issue summary

I am getting the following error when trying to use !draupnir hijack room #general:example.org @bartvdbraak:example.org:

Either the command is disabled or Mjolnir is not running as homeserver administrator.

image

I even gave it a new access token after making it server administrator.

Any idea what I might be doing wrong here?

Hjack is default disabled in mdad draupnir config. Its enabled via putting the following in your config if memory serves. Config extension is a bit funny behaving at times. But ye thats the fix for this and thank you for the issue report as that reminds me i need to update the Draupnir docs to say this is a thing.

Probably could even add a variable to quickly flip this to true so config extension isnt needed. And that would be backwards compatible with anyone who has this in their config extension as config extension overrides the default template.

matrix_bot_draupnir_configuration_extension_yaml: |
  admin:
    enableMakeRoomAdminCommand: true

I should add the ammendment that i have knowledge of reports that people have had issues with the admin API in mdad with draupnir. But i dont know if that issue is universal or was specific to one person.

Ofc the admin API access may have to be enabled and that information is found upstream in mdad documentation i hope.

Adding

matrix_bot_draupnir_configuration_extension_yaml: |
  admin:
    enableMakeRoomAdminCommand: true

Unfortunately didn't fix it. I will investigate a bit further.

This is what the /matrix/draupnir/config/production.yaml file looks like:

accessToken: syt_<redacted>
admin:
  enableMakeRoomAdminCommand: true
autojoinOnlyIfManager: true
automaticallyRedactForReasons:
- spam
- advertising
backgroundDelayMS: 500
commands:
  additionalPrefixes:
  - draupnir-bot
  - draupnir_bot
  - draupnir
  allowNoPrefix: false
  ban:
    defaultReasons:
    - spam
    - brigading
    - harassment
    - disagreement
  confirmWildcardBan: true
dataPath: /data
disableServerACL: 'false'
displayReports: false
fasterMembershipChecks: false
health:
  healthz:
    address: 0.0.0.0
    enabled: false
    endpoint: /healthz
    healthyStatus: 200
    port: 8080
    unhealthyStatus: 418
homeserverUrl: http://matrix-traefik:8008
logLevel: INFO
managementRoom: '!<redacted>:<redacted>.org'
noop: false
pollReports: false
protectAllJoinedRooms: false
rawHomeserverUrl: http://matrix-traefik:8008
recordIgnoredInvites: false
syncOnStartup: true
verifyPermissionsOnStartup: true

I checked where this message stems from, which is

// !mjolnir make admin <room> [<user ID>]
export async function execMakeRoomAdminCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
    const isAdmin = await mjolnir.isSynapseAdmin();
    if (!mjolnir.config.admin?.enableMakeRoomAdminCommand || !isAdmin) {
        const message = "Either the command is disabled or I am not running as homeserver administrator.";
        const reply = RichReply.createFor(roomId, event, message, message);
        reply['msgtype'] = "m.notice";
        mjolnir.client.sendMessage(roomId, reply);
        return;
    }

    let err = await mjolnir.makeUserRoomAdmin(await mjolnir.client.resolveRoom(parts[3]), parts[4]);
    if (err instanceof Error || typeof (err) === "string") {
        const errMsg = "Failed to process command:";
        const message = typeof (err) === "string" ? `${errMsg}: ${err}` : `${errMsg}: ${err.message}`;
        const reply = RichReply.createFor(roomId, event, message, message);
        reply['msgtype'] = "m.notice";
        mjolnir.client.sendMessage(roomId, reply);
        return;
    } else {
        await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
    }
}

Source: https://github.com/matrix-org/mjolnir/blob/5e35efd1dbc0097a7c19bed2831a1308a29d7be7/src/commands/MakeRoomAdminCommand.ts#L21

And isSynapseAdmin is defined as:

    public async isSynapseAdmin(): Promise<boolean> {
        try {
            const endpoint = `/_synapse/admin/v1/users/${await this.client.getUserId()}/admin`;
            const response = await this.client.doRequest("GET", endpoint);
            return response['admin'];
        } catch (e) {
            LogService.error("Mjolnir", "Error determining if Mjolnir is a server admin:");
            LogService.error("Mjolnir", extractRequestError(e));
            return false; // assume not
        }
    }

Source: https://github.com/matrix-org/mjolnir/blob/5e35efd1dbc0097a7c19bed2831a1308a29d7be7/src/Mjolnir.ts#L465

I checked if that would respond correctly with the current configured access token:

$ curl 'https://matrix.<redacted>.org/_synapse/admin/v1/users/@bot.draupnir:<redacted>.org/admin' -H 'Authorization: Bearer syt_<redacted>'
{"admin":true}

Could it be that the issue lies with the following?

I have this configured:

homeserverUrl: http://matrix-traefik:8008

If I get into the Draupnir container and start a Node.js REPL (docker exec -it <container-id> node), and run it as follows:

const http = require('http');

http.get({
  hostname: 'matrix-traefik',
  port: 8008,
  path: '/_synapse/admin/v1/users/@bot.draupnir:<redacted>.org/admin',
  headers: {
    'Authorization': 'Bearer syt_<redacted>'
  }
}, (res) => {
  let data = '';
  res.on('data', chunk => data += chunk);
  res.on('end', () => console.log('Response:', data));
}).on('error', (e) => console.error(`Problem with request: ${e.message}`));

I get:

> Response: 404 page not found

Thanks for troubleshooting this and yes your running into the Admin API not visible from container bug in mdad. That means its time to file an upstream issue i would susspect.

And it also happens to exceed my personal knowledge of how the playbook works internally so i cant be too much help on that front.

Anyways this whole adventure has exposed a legitimate bug in Draupnir so i am thankful of that.

You're a beast! Thanks!

Anything I can configure as a workaround for now?

spantaleev/matrix-docker-ansible-deploy#3308 (comment) claims to have a solution and its what i am deriving the proper fix for this from.

I fixed it on my server by adding:

matrix_synapse_reverse_proxy_companion_enabled: true
matrix_synapse_reverse_proxy_companion_container_labels_additional_labels: |
  ############################################################
  #                                                          #
  # Internal Synapse Admin API (/_synapse/client)            #
  #                                                          #
  ############################################################

  traefik.http.routers.matrix-synapse-reverse-proxy-companion-internal-client-synapse-client-api.rule=PathPrefix(`/_synapse/client`)


  traefik.http.routers.matrix-synapse-reverse-proxy-companion-internal-client-synapse-client-api.service=matrix-synapse-reverse-proxy-companion-client-api
  traefik.http.routers.matrix-synapse-reverse-proxy-companion-internal-client-synapse-client-api.entrypoints=matrix-internal-matrix-client-api

  ############################################################
  #                                                          #
  # /Internal Synapse Admin API (/_synapse/client)           #
  #                                                          #
  ############################################################


  ############################################################
  #                                                          #
  # Internal Synapse Admin API (/_synapse/admin)             #
  #                                                          #
  ############################################################

  traefik.http.routers.matrix-synapse-reverse-proxy-companion-internal-client-synapse-admin-api.rule=PathPrefix(`/_synapse/admin`)


  traefik.http.routers.matrix-synapse-reverse-proxy-companion-internal-client-synapse-admin-api.service=matrix-synapse-reverse-proxy-companion-client-api
  traefik.http.routers.matrix-synapse-reverse-proxy-companion-internal-client-synapse-admin-api.entrypoints=matrix-internal-matrix-client-api

  ############################################################
  #                                                          #
  # /Internal Synapse Admin API (/_synapse/admin)            #
  #                                                          #
  ############################################################

with

matrix_bot_draupnir_enabled: true
matrix_bot_draupnir_access_token: "{{ draupnir_access_token }}"
matrix_bot_draupnir_management_room: "!xxxxx:example.org"
matrix_bot_draupnir_configuration_extension_yaml: |
  admin:
    enableMakeRoomAdminCommand: true