From 96f6e22bb6d82843ca82d914562ae1751195c26a Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Thu, 19 Oct 2023 23:10:47 +0200
Subject: [PATCH 01/20] Initial MSC1929 Implementation
---
src/commands/QueryAdminDetails.tsx | 111 +++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
create mode 100644 src/commands/QueryAdminDetails.tsx
diff --git a/src/commands/QueryAdminDetails.tsx b/src/commands/QueryAdminDetails.tsx
new file mode 100644
index 00000000..332ae1d1
--- /dev/null
+++ b/src/commands/QueryAdminDetails.tsx
@@ -0,0 +1,111 @@
+import { Permalinks, UserID, getRequestFn } from "matrix-bot-sdk";
+import { MjolnirContext } from "./CommandHandler";
+import { CommandError, CommandResult } from "./interface-manager/Validation";
+import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
+import { findPresentationType, parameters, ParsedKeywords, union } from "./interface-manager/ParameterParsing";
+import "./interface-manager/MatrixPresentations";
+import { JSXFactory } from "./interface-manager/JSXFactory";
+import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
+import { renderMatrixAndSend } from "./interface-manager/DeadDocumentMatrix";
+import { DocumentNode } from "./interface-manager/DeadDocument";
+
+export type MatrixHomeserver = string;
+
+interface SupportJson {
+ contacts?: {
+ matrix_id?: string,
+ email_address?: string;
+ role: "admin" | "security";
+ }[],
+ support_page?: string;
+}
+
+async function queryAdminDetails(
+ this: MjolnirContext,
+ _keywords: ParsedKeywords,
+ entity: UserID | MatrixHomeserver | string
+): Promise> {
+ let domain: string;
+ if (entity instanceof UserID) {
+ domain = `https://${entity.domain}`;
+ } else {
+ // Doing some cleanup on the url
+ if (!entity.startsWith("https://") && !entity.startsWith("http://")) {
+ domain = `https://${entity}`;
+ } else if (entity.startsWith("http://")) {
+ domain = entity.replace("http://", "https://");
+ } else {
+ domain = entity;
+ }
+ }
+
+
+ const resp: SupportJson = await new Promise((resolve, reject) => {
+ getRequestFn()(`${domain}/.well-known/matrix/support`, (error: any, response: any, resBody: unknown) => {
+ if (error || response.statusCode !== 200) {
+ reject(error);
+ } else if (typeof resBody === 'object' && resBody !== null && ('contacts' in resBody || 'support_page' in resBody)) {
+ resolve(resBody as SupportJson)
+ } else {
+ reject(new TypeError(`Don't know what to do with response body ${JSON.stringify(resBody)}. Assuming its not a json`));
+ }
+ });
+ });
+
+ return CommandResult.Ok([entity, resp]);
+}
+
+defineInterfaceCommand({
+ designator: ["queryAdmin"],
+ table: "mjolnir",
+ parameters: parameters([
+ {
+ name: "entity",
+ acceptor: union(
+ findPresentationType("UserID"),
+ findPresentationType("MatrixHomeserver"),
+ findPresentationType("string")
+ )
+ }
+ ]),
+ command: queryAdminDetails,
+ summary: "Queries the admin of the Homeserver or user using MSC1929 if available",
+})
+
+function renderSupportJson([entity, support_json]: [UserID | MatrixHomeserver | string, SupportJson],): DocumentNode {
+ if (!support_json.support_page) {
+ return
+ Support infos for ({entity}):
+
+
+ } else if (!support_json.contacts) {
+ return
+ Support Page for ({entity}):
+
+ Support Page: {support_json.support_page}
+
+
+ } else {
+ return
+ Support info for ({entity}):
+
+ Support Page: {support_json.support_page}
+
+
+
+ }
+}
+
+defineMatrixInterfaceAdaptor({
+ interfaceCommand: findTableCommand("mjolnir", "queryAdmin"),
+ renderer: async function (client, commandRoomId, event, result) {
+ await renderMatrixAndSend(
+ renderSupportJson(result.ok),
+ commandRoomId, event, client
+ );
+ }
+})
From 7dd0a86da5155a99a89dfd2b1390a79faecefacf Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Fri, 20 Oct 2023 12:46:34 +0200
Subject: [PATCH 02/20] Add missing import
---
src/commands/CommandHandler.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/commands/CommandHandler.ts b/src/commands/CommandHandler.ts
index f2212db3..229acbbd 100644
--- a/src/commands/CommandHandler.ts
+++ b/src/commands/CommandHandler.ts
@@ -73,6 +73,7 @@ import "./Rules";
import "./WatchUnwatchCommand";
import "./Help";
import "./SetDisplayNameCommand";
+import "./QueryAdminDetails";
export const COMMAND_PREFIX = "!mjolnir";
From 5f3c4000147da3f9566a566dd2e7f1905e7ad49e Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 10:48:49 +0200
Subject: [PATCH 03/20] Add missing makePresentationType
---
src/commands/QueryAdminDetails.tsx | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/commands/QueryAdminDetails.tsx b/src/commands/QueryAdminDetails.tsx
index 332ae1d1..451b6614 100644
--- a/src/commands/QueryAdminDetails.tsx
+++ b/src/commands/QueryAdminDetails.tsx
@@ -2,15 +2,22 @@ import { Permalinks, UserID, getRequestFn } from "matrix-bot-sdk";
import { MjolnirContext } from "./CommandHandler";
import { CommandError, CommandResult } from "./interface-manager/Validation";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
-import { findPresentationType, parameters, ParsedKeywords, union } from "./interface-manager/ParameterParsing";
+import { findPresentationType, makePresentationType, parameters, ParsedKeywords, simpleTypeValidator, union } from "./interface-manager/ParameterParsing";
import "./interface-manager/MatrixPresentations";
import { JSXFactory } from "./interface-manager/JSXFactory";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { renderMatrixAndSend } from "./interface-manager/DeadDocumentMatrix";
import { DocumentNode } from "./interface-manager/DeadDocument";
+import { ReadItem } from "./interface-manager/CommandReader";
export type MatrixHomeserver = string;
+makePresentationType({
+ name: "MatrixHomeserver",
+ // This is a very very crude way to detect a url.
+ validator: simpleTypeValidator("MatrixHomeserver", (readItem: ReadItem) => (readItem instanceof String) && (!readItem.includes('#') || !readItem.includes('!')) && !readItem.includes('.'))
+})
+
interface SupportJson {
contacts?: {
matrix_id?: string,
From 48824f49c19c2918e9668474991e2af43b664cf7 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 11:06:57 +0200
Subject: [PATCH 04/20] Prepare nginx for queryAdmin command tests
---
mx-tester.yml | 2 +-
test/nginx.conf | 89 +++++++++++++++++++++++++++++++++++++------------
2 files changed, 68 insertions(+), 23 deletions(-)
diff --git a/mx-tester.yml b/mx-tester.yml
index 12e9e5b8..a249b61a 100644
--- a/mx-tester.yml
+++ b/mx-tester.yml
@@ -6,7 +6,7 @@ up:
# Wait until postgresql is ready
- until psql postgres://mjolnir-tester:mjolnir-test@127.0.0.1:8083/mjolnir-test-db -c ""; do echo "Waiting for psql..."; sleep 1s; done
# Launch the reverse proxy, listening for connections *only* on the local host.
- - docker run --rm --network host --name mjolnir-test-reverse-proxy -p 127.0.0.1:8081:80 -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
+ - docker run --rm --network host --name mjolnir-test-reverse-proxy -p 127.0.0.1:8084:8084 -p 127.0.0.1:8085:8085 -p 127.0.0.1:8086:8086 -p 127.0.0.1:8081:8081 -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
- yarn install
- npx ts-node src/appservice/cli.ts -r -u "http://host.docker.internal:9000"
- cp mjolnir-registration.yaml $MX_TEST_SYNAPSE_DIR/data/
diff --git a/test/nginx.conf b/test/nginx.conf
index 23c73c76..9892e443 100644
--- a/test/nginx.conf
+++ b/test/nginx.conf
@@ -4,29 +4,74 @@ events {
http {
server {
- listen [::]:8081 ipv6only=off;
-
- location ~ ^/_matrix/client/(r0|v3)/rooms/([^/]*)/report/(.*)$ {
- # Abuse reports should be sent to Mjölnir.
- # The r0 endpoint is deprecated but still used by many clients.
- # As of this writing, the v3 endpoint is the up-to-date version.
-
- # Add CORS, otherwise a browser will refuse this request.
- add_header 'Access-Control-Allow-Origin' '*' always; # Note: '*' is for testing purposes. For your own server, you probably want to tighten this.
- add_header 'Access-Control-Allow-Credentials' 'true' always;
- add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
- add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since' always;
- add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
- add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
-
- # Alias the regexps, to ensure that they're not rewritten.
- set $room_id $2;
- set $event_id $3;
- proxy_pass http://127.0.0.1:8082/api/1/report/$room_id/$event_id;
+ listen [::]:8081 ipv6only=off;
+
+ location ~ ^/_matrix/client/(r0|v3)/rooms/([^/]*)/report/(.*)$ {
+ # Abuse reports should be sent to Mjölnir.
+ # The r0 endpoint is deprecated but still used by many clients.
+ # As of this writing, the v3 endpoint is the up-to-date version.
+
+ # Add CORS, otherwise a browser will refuse this request.
+ add_header 'Access-Control-Allow-Origin' '*' always; # Note: '*' is for testing purposes. For your own server, you probably want to tighten this.
+ add_header 'Access-Control-Allow-Credentials' 'true' always;
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
+ add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since' always;
+ add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
+ add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
+
+ # Alias the regexps, to ensure that they're not rewritten.
+ set $room_id $2;
+ set $event_id $3;
+ proxy_pass http://127.0.0.1:8082/api/1/report/$room_id/$event_id;
+ }
+ # MSC1929 Test in best-case
+ location /.well-known/matrix/support {
+ default_type application/json;
+ return 200 '{
+ "contacts": [{
+ "matrix_id": "@admin:localhost",
+ "role": "admin"
+ }],
+ "support_page": "http://localhost"
+ }';
+ }
+ location / {
+ # Everything else should be sent to Synapse.
+ proxy_pass http://127.0.0.1:9999;
+ }
+ }
+ server {
+ listen [::]:8084 ipv6only=off;
+
+ # MSC1929 Test in worst-case
+ location /.well-known/matrix/support {
+ default_type application/json;
+ return 404 '{}';
+ }
+ }
+ server {
+ listen [::]:8085 ipv6only=off;
+
+ # MSC1929 Test in supportpage_only-case
+ location /.well-known/matrix/support {
+ default_type application/json;
+ return 200 '{
+ "support_page": "http://localhost"
+ }';
+ }
}
- location / {
- # Everything else should be sent to Synapse.
- proxy_pass http://127.0.0.1:9999;
+ server {
+ listen [::]:8086 ipv6only=off;
+
+ # MSC1929 Test in contacts-case
+ location /.well-known/matrix/support {
+ default_type application/json;
+ return 200 '{
+ "contacts": [{
+ "matrix_id": "@admin:localhost",
+ "role": "admin"
+ }],
+ }';
}
}
}
From 0ac0b44bd4e07cb41cb1e19aa2de7daf5a2085b9 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 11:21:37 +0200
Subject: [PATCH 05/20] Fix tests
---
mx-tester.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mx-tester.yml b/mx-tester.yml
index a249b61a..1e903e89 100644
--- a/mx-tester.yml
+++ b/mx-tester.yml
@@ -6,7 +6,7 @@ up:
# Wait until postgresql is ready
- until psql postgres://mjolnir-tester:mjolnir-test@127.0.0.1:8083/mjolnir-test-db -c ""; do echo "Waiting for psql..."; sleep 1s; done
# Launch the reverse proxy, listening for connections *only* on the local host.
- - docker run --rm --network host --name mjolnir-test-reverse-proxy -p 127.0.0.1:8084:8084 -p 127.0.0.1:8085:8085 -p 127.0.0.1:8086:8086 -p 127.0.0.1:8081:8081 -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
+ - docker run --rm --network host --name mjolnir-test-reverse-proxy -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
- yarn install
- npx ts-node src/appservice/cli.ts -r -u "http://host.docker.internal:9000"
- cp mjolnir-registration.yaml $MX_TEST_SYNAPSE_DIR/data/
From 06960231e2f62baa93fe7c52139243f4b7121c69 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 11:35:32 +0200
Subject: [PATCH 06/20] Fixup reverse proxy (maybe)
---
mx-tester.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mx-tester.yml b/mx-tester.yml
index 1e903e89..bccaec3d 100644
--- a/mx-tester.yml
+++ b/mx-tester.yml
@@ -6,7 +6,7 @@ up:
# Wait until postgresql is ready
- until psql postgres://mjolnir-tester:mjolnir-test@127.0.0.1:8083/mjolnir-test-db -c ""; do echo "Waiting for psql..."; sleep 1s; done
# Launch the reverse proxy, listening for connections *only* on the local host.
- - docker run --rm --network host --name mjolnir-test-reverse-proxy -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
+ - docker run --rm --network host --name mjolnir-test-reverse-proxy -p 127.0.0.1:8084:8084 -p 127.0.0.1:8085:8085 -p 127.0.0.1:8086:8086 -p 127.0.0.1:8081:80 -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
- yarn install
- npx ts-node src/appservice/cli.ts -r -u "http://host.docker.internal:9000"
- cp mjolnir-registration.yaml $MX_TEST_SYNAPSE_DIR/data/
From 97fcdb9a0b135848529f616083f884a5f0d50ba9 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 11:43:33 +0200
Subject: [PATCH 07/20] Use ports that are further away
---
mx-tester.yml | 2 +-
test/nginx.conf | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/mx-tester.yml b/mx-tester.yml
index bccaec3d..1e903e89 100644
--- a/mx-tester.yml
+++ b/mx-tester.yml
@@ -6,7 +6,7 @@ up:
# Wait until postgresql is ready
- until psql postgres://mjolnir-tester:mjolnir-test@127.0.0.1:8083/mjolnir-test-db -c ""; do echo "Waiting for psql..."; sleep 1s; done
# Launch the reverse proxy, listening for connections *only* on the local host.
- - docker run --rm --network host --name mjolnir-test-reverse-proxy -p 127.0.0.1:8084:8084 -p 127.0.0.1:8085:8085 -p 127.0.0.1:8086:8086 -p 127.0.0.1:8081:80 -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
+ - docker run --rm --network host --name mjolnir-test-reverse-proxy -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
- yarn install
- npx ts-node src/appservice/cli.ts -r -u "http://host.docker.internal:9000"
- cp mjolnir-registration.yaml $MX_TEST_SYNAPSE_DIR/data/
diff --git a/test/nginx.conf b/test/nginx.conf
index 9892e443..943d8e84 100644
--- a/test/nginx.conf
+++ b/test/nginx.conf
@@ -6,7 +6,7 @@ http {
server {
listen [::]:8081 ipv6only=off;
- location ~ ^/_matrix/client/(r0|v3)/rooms/([^/]*)/report/(.*)$ {
+ location ~ ^/_matrix/client/(r0|v3)/rooms/([^/\s]*)/report/(.*)$ {
# Abuse reports should be sent to Mjölnir.
# The r0 endpoint is deprecated but still used by many clients.
# As of this writing, the v3 endpoint is the up-to-date version.
@@ -41,7 +41,7 @@ http {
}
}
server {
- listen [::]:8084 ipv6only=off;
+ listen [::]:7070 ipv6only=off;
# MSC1929 Test in worst-case
location /.well-known/matrix/support {
@@ -50,7 +50,7 @@ http {
}
}
server {
- listen [::]:8085 ipv6only=off;
+ listen [::]:7071 ipv6only=off;
# MSC1929 Test in supportpage_only-case
location /.well-known/matrix/support {
@@ -61,7 +61,7 @@ http {
}
}
server {
- listen [::]:8086 ipv6only=off;
+ listen [::]:7072 ipv6only=off;
# MSC1929 Test in contacts-case
location /.well-known/matrix/support {
From b5c8e988f84608f8e307ddc776e276bb876e01a0 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 12:00:39 +0200
Subject: [PATCH 08/20] Add basics tests for queryAdmin command
---
src/commands/QueryAdminDetails.tsx | 2 +-
.../commands/queryAdminDetailsTest.ts | 89 +++++++++++++++++++
tsconfig.json | 1 +
3 files changed, 91 insertions(+), 1 deletion(-)
create mode 100644 test/integration/commands/queryAdminDetailsTest.ts
diff --git a/src/commands/QueryAdminDetails.tsx b/src/commands/QueryAdminDetails.tsx
index 451b6614..06077afd 100644
--- a/src/commands/QueryAdminDetails.tsx
+++ b/src/commands/QueryAdminDetails.tsx
@@ -15,7 +15,7 @@ export type MatrixHomeserver = string;
makePresentationType({
name: "MatrixHomeserver",
// This is a very very crude way to detect a url.
- validator: simpleTypeValidator("MatrixHomeserver", (readItem: ReadItem) => (readItem instanceof String) && (!readItem.includes('#') || !readItem.includes('!')) && !readItem.includes('.'))
+ validator: simpleTypeValidator("MatrixHomeserver", (readItem: ReadItem) => (readItem instanceof String) && (!readItem.includes('#') || !readItem.includes('!')))
})
interface SupportJson {
diff --git a/test/integration/commands/queryAdminDetailsTest.ts b/test/integration/commands/queryAdminDetailsTest.ts
new file mode 100644
index 00000000..bcf750d9
--- /dev/null
+++ b/test/integration/commands/queryAdminDetailsTest.ts
@@ -0,0 +1,89 @@
+import { strict as assert } from "assert";
+
+import { newTestUser } from "../clientHelper";
+import { getMessagesByUserIn } from "../../../src/utils";
+
+describe("Test: The queryAdmin command", function () {
+ // If a test has a timeout while awaitng on a promise then we never get given control back.
+ afterEach(function () { this.moderator?.stop(); });
+
+ it('Mjölnir can query and display the query results for a complete json.', async function () {
+ let moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
+ this.moderator = moderator;
+ await moderator.joinRoom(this.config.managementRoom);
+ moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:8081` });
+
+
+ const draupnir = this.config.RUNTIME.client!
+ let draupnirUserId = await draupnir.getUserId();
+
+ // Check if draupnir replied
+ await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
+ events.map(e => {
+ if (e.type === 'm.room.message') {
+ assert.equal(e.content.body, "", `Draipnir did not parse the json as expected: ${e.content.body}.`)
+ }
+ })
+ });
+ })
+
+ it('Mjölnir can query and display the query results for a partial contacts-only json.', async function () {
+ let moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
+ this.moderator = moderator;
+ await moderator.joinRoom(this.config.managementRoom);
+ moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7072` });
+
+
+ const draupnir = this.config.RUNTIME.client!
+ let draupnirUserId = await draupnir.getUserId();
+
+ // Check if draupnir replied
+ await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
+ events.map(e => {
+ if (e.type === 'm.room.message') {
+ assert.equal(e.content.body, "", `Draipnir did not parse the json as expected: ${e.content.body}.`)
+ }
+ })
+ });
+ })
+
+ it('Mjölnir can query and display the query results for a partial support_page-only json.', async function () {
+ let moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
+ this.moderator = moderator;
+ await moderator.joinRoom(this.config.managementRoom);
+ moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7071` });
+
+
+ const draupnir = this.config.RUNTIME.client!
+ let draupnirUserId = await draupnir.getUserId();
+
+ // Check if draupnir replied
+ await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
+ events.map(e => {
+ if (e.type === 'm.room.message') {
+ assert.equal(e.content.body, "", `Draipnir did not parse the json as expected: ${e.content.body}.`)
+ }
+ })
+ });
+ })
+
+ it('Mjölnir can query and display an error for a non well-formed json.', async function () {
+ let moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
+ this.moderator = moderator;
+ await moderator.joinRoom(this.config.managementRoom);
+ moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7070` });
+
+
+ const draupnir = this.config.RUNTIME.client!
+ let draupnirUserId = await draupnir.getUserId();
+
+ // Check if draupnir replied
+ await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
+ events.map(e => {
+ if (e.type === 'm.room.message') {
+ assert.equal(e.content.body, "", `Draipnir did not parse the json as expected: ${e.content.body}.`)
+ }
+ })
+ });
+ })
+});
diff --git a/tsconfig.json b/tsconfig.json
index 046c87d5..b9ddfff7 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -33,5 +33,6 @@
"./test/integration/protectionSettingsTest.ts",
"./test/integration/banPropagationTest.ts",
"./test/integration/protectedRoomsConfigTest.ts",
+ "./test/integration/commands/queryAdminDetailsTest.ts",
]
}
From 7563a443a97bad7e8db3202385fc78c7969f3b61 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 12:09:15 +0200
Subject: [PATCH 09/20] Fix typo
---
test/integration/commands/queryAdminDetailsTest.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/integration/commands/queryAdminDetailsTest.ts b/test/integration/commands/queryAdminDetailsTest.ts
index bcf750d9..0049c35e 100644
--- a/test/integration/commands/queryAdminDetailsTest.ts
+++ b/test/integration/commands/queryAdminDetailsTest.ts
@@ -21,7 +21,7 @@ describe("Test: The queryAdmin command", function () {
await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
events.map(e => {
if (e.type === 'm.room.message') {
- assert.equal(e.content.body, "", `Draipnir did not parse the json as expected: ${e.content.body}.`)
+ assert.equal(e.content.body, "", `Draupnir did not parse the json as expected: ${e.content.body}.`)
}
})
});
@@ -41,7 +41,7 @@ describe("Test: The queryAdmin command", function () {
await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
events.map(e => {
if (e.type === 'm.room.message') {
- assert.equal(e.content.body, "", `Draipnir did not parse the json as expected: ${e.content.body}.`)
+ assert.equal(e.content.body, "", `Draupnir did not parse the json as expected: ${e.content.body}.`)
}
})
});
@@ -61,7 +61,7 @@ describe("Test: The queryAdmin command", function () {
await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
events.map(e => {
if (e.type === 'm.room.message') {
- assert.equal(e.content.body, "", `Draipnir did not parse the json as expected: ${e.content.body}.`)
+ assert.equal(e.content.body, "", `Draupnir did not parse the json as expected: ${e.content.body}.`)
}
})
});
@@ -81,7 +81,7 @@ describe("Test: The queryAdmin command", function () {
await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
events.map(e => {
if (e.type === 'm.room.message') {
- assert.equal(e.content.body, "", `Draipnir did not parse the json as expected: ${e.content.body}.`)
+ assert.equal(e.content.body, "", `Draupnir did not parse the json as expected: ${e.content.body}.`)
}
})
});
From 7e6c0edef53341c9dcfa50bb29476c19c13c1185 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 12:15:12 +0200
Subject: [PATCH 10/20] Fix event handler for queryAdmin Test
---
.../commands/queryAdminDetailsTest.ts | 96 +++++++++----------
1 file changed, 46 insertions(+), 50 deletions(-)
diff --git a/test/integration/commands/queryAdminDetailsTest.ts b/test/integration/commands/queryAdminDetailsTest.ts
index 0049c35e..9b06c450 100644
--- a/test/integration/commands/queryAdminDetailsTest.ts
+++ b/test/integration/commands/queryAdminDetailsTest.ts
@@ -1,89 +1,85 @@
import { strict as assert } from "assert";
-import { newTestUser } from "../clientHelper";
-import { getMessagesByUserIn } from "../../../src/utils";
+import { newTestUser, noticeListener } from "../clientHelper";
describe("Test: The queryAdmin command", function () {
// If a test has a timeout while awaitng on a promise then we never get given control back.
afterEach(function () { this.moderator?.stop(); });
it('Mjölnir can query and display the query results for a complete json.', async function () {
- let moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
+ const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
this.moderator = moderator;
await moderator.joinRoom(this.config.managementRoom);
- moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:8081` });
+ // listener for getting the event reply
+ const reply = new Promise((resolve, reject) => {
+ moderator.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
+ resolve(event);
+ }))
+ });
- const draupnir = this.config.RUNTIME.client!
- let draupnirUserId = await draupnir.getUserId();
+ await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:8081` });
- // Check if draupnir replied
- await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
- events.map(e => {
- if (e.type === 'm.room.message') {
- assert.equal(e.content.body, "", `Draupnir did not parse the json as expected: ${e.content.body}.`)
- }
- })
- });
+
+ const reply_event = await reply;
+
+ assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`)
})
it('Mjölnir can query and display the query results for a partial contacts-only json.', async function () {
- let moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
+ const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
this.moderator = moderator;
await moderator.joinRoom(this.config.managementRoom);
- moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7072` });
+ // listener for getting the event reply
+ const reply = new Promise((resolve, reject) => {
+ moderator.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
+ resolve(event);
+ }))
+ });
- const draupnir = this.config.RUNTIME.client!
- let draupnirUserId = await draupnir.getUserId();
+ await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7072` });
- // Check if draupnir replied
- await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
- events.map(e => {
- if (e.type === 'm.room.message') {
- assert.equal(e.content.body, "", `Draupnir did not parse the json as expected: ${e.content.body}.`)
- }
- })
- });
+ const reply_event = await reply;
+
+ assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`)
})
it('Mjölnir can query and display the query results for a partial support_page-only json.', async function () {
- let moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
+ const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
this.moderator = moderator;
await moderator.joinRoom(this.config.managementRoom);
- moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7071` });
+ // listener for getting the event reply
+ const reply = new Promise((resolve, reject) => {
+ moderator.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
+ resolve(event);
+ }))
+ });
- const draupnir = this.config.RUNTIME.client!
- let draupnirUserId = await draupnir.getUserId();
+ await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7071` });
- // Check if draupnir replied
- await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
- events.map(e => {
- if (e.type === 'm.room.message') {
- assert.equal(e.content.body, "", `Draupnir did not parse the json as expected: ${e.content.body}.`)
- }
- })
- });
+ const reply_event = await reply;
+
+ assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`)
})
it('Mjölnir can query and display an error for a non well-formed json.', async function () {
- let moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
+ const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
this.moderator = moderator;
await moderator.joinRoom(this.config.managementRoom);
- moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7070` });
+ // listener for getting the event reply
+ const reply = new Promise((resolve, reject) => {
+ moderator.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
+ resolve(event);
+ }))
+ });
- const draupnir = this.config.RUNTIME.client!
- let draupnirUserId = await draupnir.getUserId();
+ moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7070` });
- // Check if draupnir replied
- await getMessagesByUserIn(moderator, draupnirUserId, this.mjolnir.managementRoomId, 1000, function (events) {
- events.map(e => {
- if (e.type === 'm.room.message') {
- assert.equal(e.content.body, "", `Draupnir did not parse the json as expected: ${e.content.body}.`)
- }
- })
- });
+ const reply_event = await reply;
+
+ assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`)
})
});
From 8a888e282406887a0c317f5b768f3421057b3b1e Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 12:38:47 +0200
Subject: [PATCH 11/20] Fix test reliability
---
.../commands/queryAdminDetailsTest.ts | 60 +++++--------------
1 file changed, 14 insertions(+), 46 deletions(-)
diff --git a/test/integration/commands/queryAdminDetailsTest.ts b/test/integration/commands/queryAdminDetailsTest.ts
index 9b06c450..23136f94 100644
--- a/test/integration/commands/queryAdminDetailsTest.ts
+++ b/test/integration/commands/queryAdminDetailsTest.ts
@@ -1,6 +1,7 @@
import { strict as assert } from "assert";
-import { newTestUser, noticeListener } from "../clientHelper";
+import { newTestUser } from "../clientHelper";
+import { getFirstReply } from "./commandUtils";
describe("Test: The queryAdmin command", function () {
// If a test has a timeout while awaitng on a promise then we never get given control back.
@@ -11,19 +12,10 @@ describe("Test: The queryAdmin command", function () {
this.moderator = moderator;
await moderator.joinRoom(this.config.managementRoom);
- // listener for getting the event reply
- const reply = new Promise((resolve, reject) => {
- moderator.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
- resolve(event);
- }))
+ const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
+ return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:8081` });
});
-
- await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:8081` });
-
-
- const reply_event = await reply;
-
- assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`)
+ assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`);
})
it('Mjölnir can query and display the query results for a partial contacts-only json.', async function () {
@@ -31,18 +23,10 @@ describe("Test: The queryAdmin command", function () {
this.moderator = moderator;
await moderator.joinRoom(this.config.managementRoom);
- // listener for getting the event reply
- const reply = new Promise((resolve, reject) => {
- moderator.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
- resolve(event);
- }))
+ const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
+ return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7072` });
});
-
- await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7072` });
-
- const reply_event = await reply;
-
- assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`)
+ assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`);
})
it('Mjölnir can query and display the query results for a partial support_page-only json.', async function () {
@@ -50,18 +34,10 @@ describe("Test: The queryAdmin command", function () {
this.moderator = moderator;
await moderator.joinRoom(this.config.managementRoom);
- // listener for getting the event reply
- const reply = new Promise((resolve, reject) => {
- moderator.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
- resolve(event);
- }))
+ const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
+ return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7071` });
});
-
- await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7071` });
-
- const reply_event = await reply;
-
- assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`)
+ assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`);
})
it('Mjölnir can query and display an error for a non well-formed json.', async function () {
@@ -69,17 +45,9 @@ describe("Test: The queryAdmin command", function () {
this.moderator = moderator;
await moderator.joinRoom(this.config.managementRoom);
- // listener for getting the event reply
- const reply = new Promise((resolve, reject) => {
- moderator.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
- resolve(event);
- }))
+ const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
+ return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7070` });
});
-
- moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text.', body: `!mjolnir queryAdmin http://localhost:7070` });
-
- const reply_event = await reply;
-
- assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`)
+ assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`);
})
});
From 05b37d86279a5ad5bb2fdff1b053df2b7d9b4c05 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 13:49:51 +0200
Subject: [PATCH 12/20] Do not upgrade http to https
---
src/commands/QueryAdminDetails.tsx | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/commands/QueryAdminDetails.tsx b/src/commands/QueryAdminDetails.tsx
index 06077afd..510cd9ff 100644
--- a/src/commands/QueryAdminDetails.tsx
+++ b/src/commands/QueryAdminDetails.tsx
@@ -39,8 +39,6 @@ async function queryAdminDetails(
// Doing some cleanup on the url
if (!entity.startsWith("https://") && !entity.startsWith("http://")) {
domain = `https://${entity}`;
- } else if (entity.startsWith("http://")) {
- domain = entity.replace("http://", "https://");
} else {
domain = entity;
}
From 147d7737afff6e39909f598e7987686a2559b783 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 14:04:23 +0200
Subject: [PATCH 13/20] Improve request call and error handling
---
src/commands/QueryAdminDetails.tsx | 31 ++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/src/commands/QueryAdminDetails.tsx b/src/commands/QueryAdminDetails.tsx
index 510cd9ff..21232b24 100644
--- a/src/commands/QueryAdminDetails.tsx
+++ b/src/commands/QueryAdminDetails.tsx
@@ -45,19 +45,26 @@ async function queryAdminDetails(
}
- const resp: SupportJson = await new Promise((resolve, reject) => {
- getRequestFn()(`${domain}/.well-known/matrix/support`, (error: any, response: any, resBody: unknown) => {
- if (error || response.statusCode !== 200) {
- reject(error);
- } else if (typeof resBody === 'object' && resBody !== null && ('contacts' in resBody || 'support_page' in resBody)) {
- resolve(resBody as SupportJson)
- } else {
- reject(new TypeError(`Don't know what to do with response body ${JSON.stringify(resBody)}. Assuming its not a json`));
- }
+ try {
+ const resp: SupportJson = await new Promise((resolve, reject) => {
+ getRequestFn()(`${domain}/.well-known/matrix/support`, (error: any, response: any, resBody: string) => {
+ if (error) {
+ reject(new CommandError(`The request failed with an error: ${error}.`));
+ } else if (response.statusCode !== 200) {
+ reject(new CommandError(`The server didn't reply with a valid response code: ${response.statusCode}.`));
+ } else if (resBody !== null && (resBody.includes('contacts') || resBody.includes('support_page'))) {
+ resolve(JSON.parse(resBody) as SupportJson)
+ } else if (resBody === null) {
+ reject(new CommandError(`The response was empty.`));
+ } else {
+ reject(new CommandError(`Don't know what to do with response body ${resBody}. Assuming its not a json`));
+ }
+ });
});
- });
-
- return CommandResult.Ok([entity, resp]);
+ return CommandResult.Ok([entity, resp]);
+ } catch (error: any) {
+ return CommandResult.Err(error);
+ }
}
defineInterfaceCommand({
From d40647d7f79922be05907f9ddb70fbf5c9b24385 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 14:05:42 +0200
Subject: [PATCH 14/20] Remove extra comma
---
test/nginx.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/nginx.conf b/test/nginx.conf
index 943d8e84..2885f153 100644
--- a/test/nginx.conf
+++ b/test/nginx.conf
@@ -70,7 +70,7 @@ http {
"contacts": [{
"matrix_id": "@admin:localhost",
"role": "admin"
- }],
+ }]
}';
}
}
From 948c9958554012a83481591ac3c59242900bda8a Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 14:07:26 +0200
Subject: [PATCH 15/20] Fix newlines
---
src/commands/QueryAdminDetails.tsx | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/commands/QueryAdminDetails.tsx b/src/commands/QueryAdminDetails.tsx
index 21232b24..7d7ce3b2 100644
--- a/src/commands/QueryAdminDetails.tsx
+++ b/src/commands/QueryAdminDetails.tsx
@@ -87,26 +87,26 @@ defineInterfaceCommand({
function renderSupportJson([entity, support_json]: [UserID | MatrixHomeserver | string, SupportJson],): DocumentNode {
if (!support_json.support_page) {
return
- Support infos for ({entity}):
+ Support infos for ({entity}):
} else if (!support_json.contacts) {
return
- Support Page for ({entity}):
+ Support Page for ({entity}):
Support Page: {support_json.support_page}
} else {
return
- Support info for ({entity}):
+ Support info for ({entity}):
Support Page: {support_json.support_page}
-
+
}
From 830b6fc2b7f0329d0d2867621f753d2f00afea0c Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 14:15:05 +0200
Subject: [PATCH 16/20] Revert json parsing changes
---
src/commands/QueryAdminDetails.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/commands/QueryAdminDetails.tsx b/src/commands/QueryAdminDetails.tsx
index 7d7ce3b2..33da21ed 100644
--- a/src/commands/QueryAdminDetails.tsx
+++ b/src/commands/QueryAdminDetails.tsx
@@ -47,13 +47,13 @@ async function queryAdminDetails(
try {
const resp: SupportJson = await new Promise((resolve, reject) => {
- getRequestFn()(`${domain}/.well-known/matrix/support`, (error: any, response: any, resBody: string) => {
+ getRequestFn()(`${domain}/.well-known/matrix/support`, (error: any, response: any, resBody: unknown) => {
if (error) {
reject(new CommandError(`The request failed with an error: ${error}.`));
} else if (response.statusCode !== 200) {
reject(new CommandError(`The server didn't reply with a valid response code: ${response.statusCode}.`));
- } else if (resBody !== null && (resBody.includes('contacts') || resBody.includes('support_page'))) {
- resolve(JSON.parse(resBody) as SupportJson)
+ } else if (typeof resBody === 'object' && resBody !== null && ('contacts' in resBody || 'support_page' in resBody)) {
+ resolve(resBody as SupportJson)
} else if (resBody === null) {
reject(new CommandError(`The response was empty.`));
} else {
From faee925aff23da5605333b5dd99ff49b5bfae329 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 14:27:53 +0200
Subject: [PATCH 17/20] Fix asserts
---
test/integration/commands/queryAdminDetailsTest.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/integration/commands/queryAdminDetailsTest.ts b/test/integration/commands/queryAdminDetailsTest.ts
index 23136f94..f4b6c4e4 100644
--- a/test/integration/commands/queryAdminDetailsTest.ts
+++ b/test/integration/commands/queryAdminDetailsTest.ts
@@ -15,7 +15,7 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:8081` });
});
- assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`);
+ assert.equal(reply_event.content.body, "**Support info for (http://localhost:8081):**\nSupport Page: http://localhost\n\n\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n", `Draupnir did not parse the json as expected.`);
})
it('Mjölnir can query and display the query results for a partial contacts-only json.', async function () {
@@ -26,7 +26,7 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7072` });
});
- assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`);
+ assert.equal(reply_event.content.body, "**Support infos for (http://localhost:7072):**\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n", `Draupnir did not parse the json as expected.`);
})
it('Mjölnir can query and display the query results for a partial support_page-only json.', async function () {
@@ -37,7 +37,7 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7071` });
});
- assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`);
+ assert.equal(reply_event.content.body, "**Support Page for (http://localhost:7071):**\nSupport Page: http://localhost\n", `Draupnir did not parse the json as expected.`);
})
it('Mjölnir can query and display an error for a non well-formed json.', async function () {
@@ -48,6 +48,6 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7070` });
});
- assert.equal(reply_event.content.body, "", `Draupnir did not parse the json as expected: ${reply_event.content.body}.`);
+ assert.equal(reply_event.content.body, "> <@mjolnir-test-user-moderator61610:localhost:9999> !mjolnir queryAdmin http://localhost:7070\nThe request failed with an error: Error: Error during MatrixClient request GET /.well-known/matrix/support: 404 Not Found -- {}.", `Draupnir did not parse the json as expected.`);
})
});
From 179e74a84549d61aaea36e180eeeb4389fd52e78 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 24 Oct 2023 14:39:55 +0200
Subject: [PATCH 18/20] Fix newlines
---
test/integration/commands/queryAdminDetailsTest.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/integration/commands/queryAdminDetailsTest.ts b/test/integration/commands/queryAdminDetailsTest.ts
index f4b6c4e4..c3493c8b 100644
--- a/test/integration/commands/queryAdminDetailsTest.ts
+++ b/test/integration/commands/queryAdminDetailsTest.ts
@@ -15,7 +15,7 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:8081` });
});
- assert.equal(reply_event.content.body, "**Support info for (http://localhost:8081):**\nSupport Page: http://localhost\n\n\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n", `Draupnir did not parse the json as expected.`);
+ assert.equal(reply_event.content.body, "**Support info for (http://localhost:8081):**\nSupport Page: http://localhost\n\n\n\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n\n", `Draupnir did not parse the json as expected.`);
})
it('Mjölnir can query and display the query results for a partial contacts-only json.', async function () {
@@ -26,7 +26,7 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7072` });
});
- assert.equal(reply_event.content.body, "**Support infos for (http://localhost:7072):**\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n", `Draupnir did not parse the json as expected.`);
+ assert.equal(reply_event.content.body, "**Support infos for (http://localhost:7072):**\n\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n\n", `Draupnir did not parse the json as expected.`);
})
it('Mjölnir can query and display the query results for a partial support_page-only json.', async function () {
@@ -37,7 +37,7 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7071` });
});
- assert.equal(reply_event.content.body, "**Support Page for (http://localhost:7071):**\nSupport Page: http://localhost\n", `Draupnir did not parse the json as expected.`);
+ assert.equal(reply_event.content.body, "**Support Page for (http://localhost:7071):**\nSupport Page: http://localhost\n\n", `Draupnir did not parse the json as expected.`);
})
it('Mjölnir can query and display an error for a non well-formed json.', async function () {
@@ -48,6 +48,6 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7070` });
});
- assert.equal(reply_event.content.body, "> <@mjolnir-test-user-moderator61610:localhost:9999> !mjolnir queryAdmin http://localhost:7070\nThe request failed with an error: Error: Error during MatrixClient request GET /.well-known/matrix/support: 404 Not Found -- {}.", `Draupnir did not parse the json as expected.`);
+ assert.equal(reply_event.content.body.includes("The request failed with an error: Error: Error during MatrixClient request GET /.well-known/matrix/support:"), true, `Draupnir did not print an error as.`);
})
});
From 506ae54ed926b32b3ba6cd6ced54f5122db173e0 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 31 Oct 2023 15:16:52 +0100
Subject: [PATCH 19/20] Change the command `queryAdmin` to `query admin` and
apply suggestions for the representation type.
Co-authored-by: gnuxie
---
src/commands/QueryAdminDetails.tsx | 15 ++++++++++-----
.../integration/commands/queryAdminDetailsTest.ts | 8 ++++----
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/src/commands/QueryAdminDetails.tsx b/src/commands/QueryAdminDetails.tsx
index 33da21ed..c64645b9 100644
--- a/src/commands/QueryAdminDetails.tsx
+++ b/src/commands/QueryAdminDetails.tsx
@@ -10,12 +10,17 @@ import { renderMatrixAndSend } from "./interface-manager/DeadDocumentMatrix";
import { DocumentNode } from "./interface-manager/DeadDocument";
import { ReadItem } from "./interface-manager/CommandReader";
-export type MatrixHomeserver = string;
+const MatrixHomeserverSecret = Symbol("MatrixHomeserverSecret");
+export type MatrixHomeserver = string & { [MatrixHomeserverSecret]: true };
+
+function isMatrixHomeserver(string: string): string is MatrixHomeserver {
+ return !string.includes('#') && !string.includes('!')
+}
makePresentationType({
name: "MatrixHomeserver",
// This is a very very crude way to detect a url.
- validator: simpleTypeValidator("MatrixHomeserver", (readItem: ReadItem) => (readItem instanceof String) && (!readItem.includes('#') || !readItem.includes('!')))
+ validator: simpleTypeValidator("MatrixHomeserver", (readItem: ReadItem) => (typeof readItem === 'string') && isMatrixHomeserver(readItem))
})
interface SupportJson {
@@ -68,7 +73,7 @@ async function queryAdminDetails(
}
defineInterfaceCommand({
- designator: ["queryAdmin"],
+ designator: ["query", "admin"],
table: "mjolnir",
parameters: parameters([
{
@@ -87,7 +92,7 @@ defineInterfaceCommand({
function renderSupportJson([entity, support_json]: [UserID | MatrixHomeserver | string, SupportJson],): DocumentNode {
if (!support_json.support_page) {
return
- Support infos for ({entity}):
+ Support info for ({entity}):
@@ -113,7 +118,7 @@ function renderSupportJson([entity, support_json]: [UserID | MatrixHomeserver |
}
defineMatrixInterfaceAdaptor({
- interfaceCommand: findTableCommand("mjolnir", "queryAdmin"),
+ interfaceCommand: findTableCommand("mjolnir", "query", "admin"),
renderer: async function (client, commandRoomId, event, result) {
await renderMatrixAndSend(
renderSupportJson(result.ok),
diff --git a/test/integration/commands/queryAdminDetailsTest.ts b/test/integration/commands/queryAdminDetailsTest.ts
index c3493c8b..af80ef84 100644
--- a/test/integration/commands/queryAdminDetailsTest.ts
+++ b/test/integration/commands/queryAdminDetailsTest.ts
@@ -13,7 +13,7 @@ describe("Test: The queryAdmin command", function () {
await moderator.joinRoom(this.config.managementRoom);
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
- return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:8081` });
+ return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir query admin http://localhost:8081` });
});
assert.equal(reply_event.content.body, "**Support info for (http://localhost:8081):**\nSupport Page: http://localhost\n\n\n\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n\n", `Draupnir did not parse the json as expected.`);
})
@@ -24,7 +24,7 @@ describe("Test: The queryAdmin command", function () {
await moderator.joinRoom(this.config.managementRoom);
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
- return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7072` });
+ return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir query admin http://localhost:7072` });
});
assert.equal(reply_event.content.body, "**Support infos for (http://localhost:7072):**\n\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n\n", `Draupnir did not parse the json as expected.`);
})
@@ -35,7 +35,7 @@ describe("Test: The queryAdmin command", function () {
await moderator.joinRoom(this.config.managementRoom);
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
- return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7071` });
+ return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir query admin http://localhost:7071` });
});
assert.equal(reply_event.content.body, "**Support Page for (http://localhost:7071):**\nSupport Page: http://localhost\n\n", `Draupnir did not parse the json as expected.`);
})
@@ -46,7 +46,7 @@ describe("Test: The queryAdmin command", function () {
await moderator.joinRoom(this.config.managementRoom);
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
- return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir queryAdmin http://localhost:7070` });
+ return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir query admin http://localhost:7070` });
});
assert.equal(reply_event.content.body.includes("The request failed with an error: Error: Error during MatrixClient request GET /.well-known/matrix/support:"), true, `Draupnir did not print an error as.`);
})
From 86a73efce03107c5b290beebac3e03354fc0dc77 Mon Sep 17 00:00:00 2001
From: MTRNord
Date: Tue, 31 Oct 2023 15:30:22 +0100
Subject: [PATCH 20/20] Update the test to reflect the type change
---
test/integration/commands/queryAdminDetailsTest.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/integration/commands/queryAdminDetailsTest.ts b/test/integration/commands/queryAdminDetailsTest.ts
index af80ef84..4f536090 100644
--- a/test/integration/commands/queryAdminDetailsTest.ts
+++ b/test/integration/commands/queryAdminDetailsTest.ts
@@ -26,7 +26,7 @@ describe("Test: The queryAdmin command", function () {
const reply_event = await getFirstReply(this.mjolnir.matrixEmitter, this.mjolnir.managementRoomId, async () => {
return await moderator.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir query admin http://localhost:7072` });
});
- assert.equal(reply_event.content.body, "**Support infos for (http://localhost:7072):**\n\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n\n", `Draupnir did not parse the json as expected.`);
+ assert.equal(reply_event.content.body, "**Support info for (http://localhost:7072):**\n\n * **admin** - [@admin:localhost](https://matrix.to/#/@admin:localhost)\n\n", `Draupnir did not parse the json as expected.`);
})
it('Mjölnir can query and display the query results for a partial support_page-only json.', async function () {