Skip to content

Commit 8cb1816

Browse files
committed
test: Add blacklist tests
1 parent 4481249 commit 8cb1816

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { EventEmitter } from 'events';
2+
import * as fs from 'node:fs';
3+
import type { ClientRequest, IncomingMessage } from 'node:http';
4+
import type { RequestOptions } from 'node:https';
5+
import * as path from 'node:path';
6+
import Blacklist from '../../dimensions/blacklist.js';
7+
import type { EnabledBlackList } from '../../dimensions/configloader.js';
8+
9+
type HttpsGet = typeof import('node:https').get;
10+
11+
describe("Blacklist", () => {
12+
class FakeRequest extends EventEmitter {
13+
destroy(error?: Error): this {
14+
if (error) {
15+
this.emit("error", error);
16+
}
17+
18+
return this;
19+
}
20+
}
21+
22+
class FakeResponse extends EventEmitter {
23+
}
24+
25+
function makeConfig(): EnabledBlackList {
26+
return {
27+
enabled: true,
28+
hostname: "blacklist.example.test",
29+
path: "/blacklisted",
30+
port: 443,
31+
apiKey: "secret-token",
32+
errorPolicy: "DenyJoining"
33+
};
34+
}
35+
36+
function makeHttpsGet(responseBody: string, capturedRequests: RequestOptions[]): HttpsGet {
37+
return ((options: RequestOptions | string | URL, callback?: (res: IncomingMessage) => void) => {
38+
if (typeof options !== "object" || options instanceof URL) {
39+
throw new Error("Expected blacklist request to use request options");
40+
}
41+
42+
capturedRequests.push(options);
43+
const request = new FakeRequest();
44+
const response = new FakeResponse();
45+
46+
queueMicrotask(() => {
47+
callback?.(response as IncomingMessage);
48+
response.emit("data", Buffer.from(responseBody));
49+
response.emit("end");
50+
});
51+
52+
return request as ClientRequest;
53+
}) as HttpsGet;
54+
}
55+
56+
async function expectRejects(promise: Promise<unknown>, message?: string): Promise<void> {
57+
let rejection: unknown;
58+
try {
59+
await promise;
60+
} catch (e) {
61+
rejection = e;
62+
}
63+
64+
expect(rejection).toEqual(jasmine.any(Error));
65+
if (typeof message !== "undefined") {
66+
expect((rejection as Error).message).toContain(message);
67+
}
68+
}
69+
70+
it("sends blacklist checks over HTTPS with the token header and encoded player metadata", async () => {
71+
const capturedRequests: RequestOptions[] = [];
72+
const blacklist = new Blacklist(makeConfig(), makeHttpsGet(JSON.stringify(["Ok", { isBlacklisted: false }]), capturedRequests));
73+
74+
const isBlacklisted = await blacklist.checkInformation("Alice & Bob", "203.0.113.5", "uuid/value?");
75+
76+
expect(isBlacklisted).toBeFalse();
77+
expect(capturedRequests.length).toBe(1);
78+
const requestOptions = capturedRequests[0];
79+
expect(requestOptions.protocol).toBe("https:");
80+
expect(requestOptions.hostname).toBe("blacklist.example.test");
81+
expect(requestOptions.port).toBe(443);
82+
expect(requestOptions.headers).toEqual({ token: "secret-token" });
83+
84+
const requestUrl = new URL(requestOptions.path!, "https://blacklist.example.test");
85+
expect(requestUrl.pathname).toBe("/blacklisted");
86+
expect(requestUrl.searchParams.get("name")).toBe("Alice & Bob");
87+
expect(requestUrl.searchParams.get("ip")).toBe("203.0.113.5");
88+
expect(requestUrl.searchParams.get("uuid")).toBe("uuid/value?");
89+
});
90+
91+
it("resolves true when the blacklist response marks the client as blacklisted", async () => {
92+
const blacklist = new Blacklist(makeConfig(), makeHttpsGet(JSON.stringify(["Ok", { isBlacklisted: true }]), []));
93+
94+
await expectAsync(blacklist.checkInformation("Smekku", "127.0.0.1", "uuid")).toBeResolvedTo(true);
95+
});
96+
97+
it("rejects forbidden responses", async () => {
98+
const blacklist = new Blacklist(makeConfig(), makeHttpsGet(JSON.stringify(["Forbidden"]), []));
99+
100+
await expectRejects(blacklist.checkInformation("Smekku", "127.0.0.1", "uuid"), "Invalid token");
101+
});
102+
103+
it("rejects malformed JSON responses", async () => {
104+
const blacklist = new Blacklist(makeConfig(), makeHttpsGet("not json", []));
105+
106+
await expectRejects(blacklist.checkInformation("Smekku", "127.0.0.1", "uuid"));
107+
});
108+
109+
it("does not use plaintext HTTP transport in the blacklist implementation", () => {
110+
const source = fs.readFileSync(path.resolve(process.cwd(), "app/dimensions/blacklist.ts"), "utf8");
111+
112+
expect(source).not.toContain("http.get");
113+
expect(source).not.toContain("protocol: 'http'");
114+
expect(source).not.toContain('protocol: "http"');
115+
expect(source).not.toContain("rejectUnauthorized: false");
116+
});
117+
});

0 commit comments

Comments
 (0)