Skip to content

Commit cbbd9f8

Browse files
authored
Fix not being able to add custom endpoints to the appservice's express instance (turt2live#349)
* Add failing test * Fix endpoint registration ordering
1 parent 8aebc8e commit cbbd9f8

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

src/appservice/Appservice.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -302,12 +302,7 @@ export class Appservice extends EventEmitter {
302302
this.app.post("/_matrix/app/v1/unstable/org.matrix.msc3984/keys/query", this.onKeysQuery.bind(this));
303303
this.app.post("/unstable/org.matrix.msc3984/keys/query", this.onKeysQuery.bind(this));
304304

305-
// Everything else should 404
306-
// Technically, according to https://spec.matrix.org/v1.6/application-service-api/#unknown-routes we should
307-
// be returning 405 for *known* endpoints with the wrong method.
308-
this.app.all("*", (req: express.Request, res: express.Response) => {
309-
res.status(404).json({ errcode: "M_UNRECOGNIZED", error: "Endpoint not implemented" });
310-
});
305+
// We register the 404 handler in the `begin()` function to allow consumers to add their own endpoints.
311306

312307
if (!this.registration.namespaces || !this.registration.namespaces.users || this.registration.namespaces.users.length === 0) {
313308
throw new Error("No user namespaces in registration");
@@ -381,6 +376,13 @@ export class Appservice extends EventEmitter {
381376
*/
382377
public begin(): Promise<void> {
383378
return new Promise<void>((resolve, reject) => {
379+
// Per constructor, all other endpoints should 404.
380+
// Technically, according to https://spec.matrix.org/v1.6/application-service-api/#unknown-routes we should
381+
// be returning 405 for *known* endpoints with the wrong method.
382+
this.app.all("*", (req: express.Request, res: express.Response) => {
383+
res.status(404).json({ errcode: "M_UNRECOGNIZED", error: "Endpoint not implemented" });
384+
});
385+
384386
this.appServer = this.app.listen(this.options.port, this.options.bindAddress, () => resolve());
385387
}).then(async () => {
386388
if (this.options.intentOptions?.encryption) {

test/appservice/AppserviceTest.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,6 +2039,44 @@ describe('Appservice', () => {
20392039
}
20402040
});
20412041

2042+
it('should allow custom endpoints to be added to the express instance', async () => {
2043+
const port = await getPort();
2044+
const hsToken = "s3cret_token";
2045+
const appservice = new Appservice({
2046+
port: port,
2047+
bindAddress: '',
2048+
homeserverName: 'example.org',
2049+
homeserverUrl: 'https://localhost',
2050+
registration: {
2051+
as_token: "",
2052+
hs_token: hsToken,
2053+
sender_localpart: "_bot_",
2054+
namespaces: {
2055+
users: [{ exclusive: true, regex: "@_prefix_.*:.+" }],
2056+
rooms: [],
2057+
aliases: [],
2058+
},
2059+
},
2060+
});
2061+
appservice.botIntent.ensureRegistered = () => {
2062+
return null;
2063+
};
2064+
2065+
appservice.expressAppInstance.get("/test", (_, res) => res.sendStatus(200));
2066+
2067+
await appservice.begin();
2068+
2069+
try {
2070+
const res = await requestPromise({
2071+
uri: `http://localhost:${port}/test`,
2072+
method: "GET",
2073+
});
2074+
expect(res).toEqual("OK");
2075+
} finally {
2076+
appservice.stop();
2077+
}
2078+
});
2079+
20422080
// TODO: Populate once intent tests are stable
20432081

20442082
it.skip('should not try decryption if crypto is not possible', async () => {

0 commit comments

Comments
 (0)