Skip to content

Commit 20027d1

Browse files
committed
start testing the web api used by the widget
1 parent bf90546 commit 20027d1

File tree

3 files changed

+115
-4
lines changed

3 files changed

+115
-4
lines changed

src/appservice/Api.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ export class Api {
100100
response.status(200).json(existing);
101101
}
102102

103+
/**
104+
* Creates a new mjolnir for the requesting user and protects their first room.
105+
* @param req.body.roomId The room id that the request to create a mjolnir originates from.
106+
* This is so that mjolnir can protect the room once the authenticity of the request has been verified.
107+
* @param req.body.openId An OpenID token to verify the send of the request with.
108+
*/
103109
private async pathCreate(req: express.Request, response: express.Response) {
104110
const accessToken = req.body["openId"];
105111
if (accessToken === undefined) {
@@ -119,12 +125,9 @@ export class Api {
119125
return;
120126
}
121127

128+
// TODO: provisionNewMjolnir will throw if it fails...
122129
const [mjolnirId, managementRoom] = await this.mjolnirManager.provisionNewMjolnir(userId);
123130

124-
// privisionNewMjolnir can't fail yet, but it should be able to
125-
//if (mjolnirId === null) {
126-
//}
127-
128131
response.status(200).json({ mxid: mjolnirId, roomId: managementRoom });
129132
}
130133

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { MjolnirAppService } from "../../../src/appservice/AppService";
2+
import { newTestUser } from "../../integration/clientHelper";
3+
import { isPolicyRoom, readTestConfig, setupHarness } from "../utils/harness";
4+
import { CreateMjolnirResponse, MjolnirWebAPIClient } from "../utils/webAPIClient";
5+
import { MatrixClient } from "matrix-bot-sdk";
6+
import { getFirstReply } from "../../integration/commands/commandUtils";
7+
import expect from "expect";
8+
9+
10+
interface Context extends Mocha.Context {
11+
appservice?: MjolnirAppService
12+
user?: MatrixClient
13+
}
14+
15+
16+
describe("Test that the app service can provision a mjolnir when requested from the web API", function () {
17+
afterEach(function(this: Context) {
18+
this.user?.stop();
19+
if (this.appservice) {
20+
return this.appservice.close();
21+
} else {
22+
console.warn("Missing Appservice in this context, so cannot stop it.")
23+
}
24+
});
25+
it("", async function (this: Context) {
26+
const config = readTestConfig();
27+
this.appservice = await setupHarness();
28+
// create a user
29+
const user = await newTestUser(config.homeserver.url, { name: { contains: "test" } });
30+
const apiClient = await MjolnirWebAPIClient.makeClient(user, "http://localhost:9001");
31+
const roomToProtectId = await user.createRoom({ preset: "public_chat" });
32+
33+
this.user = user;
34+
const roomsInvitedTo: string[] = [];
35+
const mjolnirDetails: CreateMjolnirResponse = await new Promise(async resolve => {
36+
const mjolnirDetailsPromise = apiClient.createMjolnir(roomToProtectId);
37+
user.on('room.invite', (roomId: string) => {
38+
roomsInvitedTo.push(roomId)
39+
// the appservice should invite it to a policy room and a management room.
40+
if (roomsInvitedTo.length === 2) {
41+
mjolnirDetailsPromise.then(resolve);
42+
}
43+
});
44+
await user.start();
45+
});
46+
await Promise.all(roomsInvitedTo.map(roomId => user.joinRoom(roomId)));
47+
const managementRoomId = roomsInvitedTo.filter(async roomId => !(await isPolicyRoom(user, roomId)))[0];
48+
expect(managementRoomId).toBe(mjolnirDetails.managementRoomId);
49+
const event = await getFirstReply(user, managementRoomId, () => {
50+
return user.sendMessage(managementRoomId, { body: `!mjolnir status`, msgtype: 'm.text' });
51+
})
52+
expect(event.sender).toBe(mjolnirDetails.mjolnirUserId);
53+
})
54+
})
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import * as request from "request";
2+
import { MatrixClient } from "matrix-bot-sdk";
3+
4+
interface OpenIDTokenInfo {
5+
access_token: string,
6+
expires_in: number,
7+
matrix_server_name: string,
8+
token_type: string
9+
}
10+
11+
async function getOpenIDToken(client: MatrixClient): Promise<string> {
12+
const tokenInfo: OpenIDTokenInfo = await client.doRequest("POST", `/_matrix/client/v3/user/${await client.getUserId()}/openid/request_token`, undefined, {});
13+
return tokenInfo.access_token;
14+
}
15+
16+
export interface CreateMjolnirResponse {
17+
mjolnirUserId: string,
18+
managementRoomId: string,
19+
}
20+
21+
export class MjolnirWebAPIClient {
22+
23+
private constructor(
24+
private readonly matrixClient: MatrixClient,
25+
/**
26+
* This will want refactoring later on since, well, for some reason our API is designed to accept the token in request body and not authorization header :(
27+
* it will need to include the expiry for the token.
28+
*/
29+
private readonly openIDToken: string,
30+
private readonly baseURL: string,
31+
) {
32+
33+
}
34+
35+
public static async makeClient(client: MatrixClient, baseUrl: string): Promise<MjolnirWebAPIClient> {
36+
const token = await getOpenIDToken(client);
37+
return new MjolnirWebAPIClient(client, token, baseUrl);
38+
}
39+
40+
public async createMjolnir(roomToProtectId: string): Promise<CreateMjolnirResponse> {
41+
const body: { mxid: string, roomId: string } = await new Promise((resolve, reject) => {
42+
request.post(`${this.baseURL}/create`, {
43+
json: {
44+
openId: this.openIDToken,
45+
roomId: roomToProtectId,
46+
},
47+
}, (error, response) => error ? reject(error) : resolve(response.body))
48+
});
49+
return {
50+
mjolnirUserId: body.mxid,
51+
managementRoomId: body.roomId
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)