mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-07 17:04:42 +00:00
fix(hub): reject invalid socket transport URLs
This commit is contained in:
@@ -73,6 +73,24 @@ test.each([408, 429])("transient enrollment status %s remains retryable", async
|
||||
expect((error as Error).message).toBe(`Hub enrollment failed (${status})`);
|
||||
});
|
||||
|
||||
test("enrollment rejects a transport URL that cannot open a WebSocket", async () => {
|
||||
const hubOrigin = await startEnrollmentHub("ftp://hub.test/daemon");
|
||||
const remote = new DirectHubRelationshipRemote();
|
||||
|
||||
await expect(
|
||||
remote.enroll({
|
||||
relationshipId: "relationship-1",
|
||||
idempotencyKey: "ceremony-1",
|
||||
hubOrigin,
|
||||
token: "token",
|
||||
serverId: "server-1",
|
||||
daemonPublicKey: "public-key",
|
||||
credentialVerifier: "verifier",
|
||||
scopes: ["hub.*"],
|
||||
}),
|
||||
).rejects.toThrow("Hub WebSocket URL must use ws or wss");
|
||||
});
|
||||
|
||||
test.each(["enrollment", "revocation"])("%s HTTP calls are bounded", async (operation) => {
|
||||
const hubOrigin = await startStalledHub();
|
||||
const remote = new DirectHubRelationshipRemote({ requestTimeoutMs: 25 });
|
||||
@@ -212,6 +230,28 @@ async function startHubReturning(status: number): Promise<string> {
|
||||
return `http://127.0.0.1:${address.port}`;
|
||||
}
|
||||
|
||||
async function startEnrollmentHub(webSocketUrl: string): Promise<string> {
|
||||
const server = createServer(async (request, response) => {
|
||||
let body = "";
|
||||
for await (const chunk of request) body += chunk;
|
||||
const enrollment = JSON.parse(body) as { relationshipId: string };
|
||||
response.writeHead(200, { "content-type": "application/json" }).end(
|
||||
JSON.stringify({
|
||||
relationshipId: enrollment.relationshipId,
|
||||
scopes: ["hub.*"],
|
||||
webSocketUrl,
|
||||
}),
|
||||
);
|
||||
});
|
||||
openServers.push(server);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", resolve);
|
||||
});
|
||||
const address = server.address() as AddressInfo;
|
||||
return `http://127.0.0.1:${address.port}`;
|
||||
}
|
||||
|
||||
async function startStalledHub(): Promise<string> {
|
||||
const server = createServer(() => undefined);
|
||||
openServers.push(server);
|
||||
|
||||
@@ -58,7 +58,12 @@ export class HubEnrollmentRejectedError extends Error {
|
||||
const EnrollmentResultSchema = z.object({
|
||||
relationshipId: z.string(),
|
||||
scopes: z.array(z.string()),
|
||||
webSocketUrl: z.string().url(),
|
||||
webSocketUrl: z
|
||||
.string()
|
||||
.url()
|
||||
.refine((value) => ["ws:", "wss:"].includes(new URL(value).protocol), {
|
||||
message: "Hub WebSocket URL must use ws or wss",
|
||||
}),
|
||||
});
|
||||
|
||||
export class DirectHubRelationshipRemote implements HubRelationshipRemote {
|
||||
|
||||
Reference in New Issue
Block a user