Skip to content

Commit e26c847

Browse files
committed
Tidy up the web API
1 parent 20027d1 commit e26c847

File tree

2 files changed

+73
-20
lines changed

2 files changed

+73
-20
lines changed

src/appservice/Api.ts

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import * as bodyParser from "body-parser";
44
import { MjolnirManager } from "./MjolnirManager";
55
import * as http from "http";
66

7+
/**
8+
* This provides a web api that is designed to power the mjolnir widget https://github.com/matrix-org/mjolnir-widget.
9+
*/
710
export class Api {
811
private httpdConfig: express.Express = express();
912
private httpServer?: http.Server;
@@ -59,44 +62,58 @@ export class Api {
5962
this.httpServer = this.httpdConfig.listen(port);
6063
}
6164

65+
/**
66+
* Finds the management room for a mjolnir.
67+
* @param req.body.openId An OpenID token to verify the send of the request with.
68+
* @param req.body.mxid The mjolnir we want to find the management room for.
69+
*/
6270
private async pathGet(req: express.Request, response: express.Response) {
63-
const accessToken = req.query["openId"];
71+
const accessToken = req.body["openId"];
6472
if (accessToken === undefined) {
6573
response.status(401).send("unauthorised");
6674
return;
6775
}
6876

69-
const mjolnirId = req.query["mxid"];
77+
const userId = await this.resolveAccessToken(accessToken);
78+
if (userId === null) {
79+
response.status(401).send("unauthorised");
80+
return;
81+
}
82+
83+
const mjolnirId = req.body["mxid"];
7084
if (mjolnirId === undefined) {
7185
response.status(400).send("invalid request");
7286
return;
7387
}
7488

75-
//const userId = await this.resolveAccessToken(accessToken);
76-
// doesn't exist yet
77-
//if (!this.appService.canSeeMjolnir(userId, mjolnirId)) {
78-
if (false) {
79-
response.status(403);
89+
// TODO: getMjolnir can fail if the ownerId doesn't match the requesting userId.
90+
const mjolnir = this.mjolnirManager.getMjolnir(mjolnirId, userId);
91+
if (mjolnir === undefined) {
92+
response.status(400).send("unknown mjolnir mxid");
8093
return;
8194
}
8295

83-
// doesn't exist yet
84-
//const managementRoom = this.appService.managementRoomFor(mjolnirId);
85-
const managementRoom = "!123456:matrix.org";
86-
response.status(200).json({ managementRoom: managementRoom });
96+
response.status(200).json({ managementRoom: mjolnir.managementRoomId });
8797
}
8898

99+
/**
100+
* Return the mxids of mjolnirs that this user has provisioned.
101+
* @param req.body.openId An OpenID token to verify the send of the request with.
102+
*/
89103
private async pathList(req: express.Request, response: express.Response) {
90-
const accessToken = req.query["openId"];
104+
const accessToken = req.body["openId"];
91105
if (accessToken === undefined) {
92106
response.status(401).send("unauthorised");
93107
return;
94108
}
95109

96-
//const userId = await this.resolveAccessToken(accessToken);
97-
// doesn't exist yet
98-
//const existing = this.appService.listForUser(userId);
99-
const existing = ["@mjolnir_12345:matrix.org", "@mjolnir_12346:matrix.org"];
110+
const userId = await this.resolveAccessToken(accessToken);
111+
if (userId === null) {
112+
response.status(401).send("unauthorised");
113+
return;
114+
}
115+
116+
const existing = this.mjolnirManager.getOwnedMjolnirs(userId)
100117
response.status(200).json(existing);
101118
}
102119

@@ -131,6 +148,12 @@ export class Api {
131148
response.status(200).json({ mxid: mjolnirId, roomId: managementRoom });
132149
}
133150

151+
/**
152+
* Request a mjolnir to join and protect a room.
153+
* @param req.body.openId An OpenID token to verify the send of the request with.
154+
* @param req.body.mxid The mjolnir that should join the room.
155+
* @param req.body.roomId The room that this mjolnir should join and protect.
156+
*/
134157
private async pathJoin(req: express.Request, response: express.Response) {
135158
const accessToken = req.body["openId"];
136159
if (accessToken === undefined) {
@@ -156,7 +179,8 @@ export class Api {
156179
return;
157180
}
158181

159-
const mjolnir = this.mjolnirManager.mjolnirs.get(mjolnirId);
182+
// TODO: getMjolnir can fail if the ownerId doesn't match the requesting userId.
183+
const mjolnir = this.mjolnirManager.getMjolnir(mjolnirId, userId);
160184
if (mjolnir === undefined) {
161185
response.status(400).send("unknown mjolnir mxid");
162186
return;

src/appservice/MjolnirManager.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { randomUUID } from "crypto";
1515
* * Informing mjolnirs about new events.
1616
*/
1717
export class MjolnirManager {
18-
public readonly mjolnirs: Map</*the user id of the mjolnir*/string, ManagedMjolnir> = new Map();
18+
private readonly mjolnirs: Map</*the user id of the mjolnir*/string, ManagedMjolnir> = new Map();
1919

2020
private constructor(
2121
private readonly dataStore: DataStore,
@@ -39,11 +39,33 @@ export class MjolnirManager {
3939
}
4040

4141
public async makeInstance(requestingUserId: string, managementRoomId: string, client: MatrixClient): Promise<ManagedMjolnir> {
42-
const managedMjolnir = new ManagedMjolnir(await Mjolnir.setupMjolnirFromConfig(client, this.getDefaultMjolnirConfig(managementRoomId)));
42+
const managedMjolnir = new ManagedMjolnir(
43+
requestingUserId,
44+
await Mjolnir.setupMjolnirFromConfig(client, this.getDefaultMjolnirConfig(managementRoomId))
45+
);
4346
this.mjolnirs.set(await client.getUserId(), managedMjolnir);
4447
return managedMjolnir;
4548
}
4649

50+
public getMjolnir(mjolnirId: string, ownerId: string): ManagedMjolnir|undefined {
51+
const mjolnir = this.mjolnirs.get(mjolnirId);
52+
if (mjolnir) {
53+
if (mjolnir.ownerId !== ownerId) {
54+
throw new Error(`${mjolnirId} is owned by a different user to ${ownerId}`);
55+
} else {
56+
return mjolnir;
57+
}
58+
} else {
59+
return undefined;
60+
}
61+
}
62+
63+
public getOwnedMjolnirs(ownerId: string): ManagedMjolnir[] {
64+
// TODO we need to use the database for this but also provide the utility
65+
// for going from a MjolnirRecord to a ManagedMjolnir.
66+
return [...this.mjolnirs.values()].filter(mjolnir => mjolnir.ownerId !== ownerId);
67+
}
68+
4769
public onEvent(request: Request<WeakEvent>, context: BridgeContext) {
4870
// We honestly don't know how we're going to map from bridge to user
4971
// https://github.com/matrix-org/matrix-appservice-bridge/blob/6046d31c54d461ad53e6d6e244ce2d944b62f890/src/components/room-bridge-store.ts
@@ -111,7 +133,10 @@ export class MjolnirManager {
111133
// Isolating this mjolnir is going to require provisioning an access token just for this user to be useful.
112134
// We can use fork and node's IPC to inform the process of matrix evnets.
113135
export class ManagedMjolnir {
114-
public constructor(private readonly mjolnir: Mjolnir) { }
136+
public constructor(
137+
public readonly ownerId: string,
138+
private readonly mjolnir: Mjolnir,
139+
) { }
115140

116141
public async onEvent(request: Request<WeakEvent>) {
117142
// phony sync.
@@ -147,4 +172,8 @@ export class ManagedMjolnir {
147172
const roomRef = Permalinks.forRoom(listRoomId);
148173
return await this.mjolnir.watchList(roomRef);
149174
}
175+
176+
public get managementRoomId(): string {
177+
return this.mjolnir.managementRoomId;
178+
}
150179
}

0 commit comments

Comments
 (0)