Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/modules/plugins/utils/capabilityConsentPayload.server.test.ts
T

123 lines
4.4 KiB
TypeScript

import { describe, expect, test } from "vitest";
import {
MAX_PLUGIN_CONSENT_CAPABILITY_ITEMS,
MAX_PLUGIN_CONSENT_CAPABILITY_NAME_LENGTH,
parsePluginCapabilityGrantArray,
parsePluginCapabilityNameArray,
readPluginConsentJsonObject,
readPluginConsentUrlEncodedFormData,
} from "./capabilityConsentPayload.server";
describe("plugin capability consent payload helpers", () => {
test("parses valid capability name arrays", () => {
expect(parsePluginCapabilityNameArray(["http.outbound", "log"])).toEqual({
ok: true,
capabilityNames: ["http.outbound", "log"],
});
});
test("rejects malformed capability name arrays", () => {
const cases: unknown[] = [
[],
Array.from({ length: MAX_PLUGIN_CONSENT_CAPABILITY_ITEMS + 1 }, (_, index) => `capability.${index}`),
["http.outbound", "http.outbound"],
[" http.outbound"],
["x".repeat(MAX_PLUGIN_CONSENT_CAPABILITY_NAME_LENGTH + 1)],
["log", null],
];
for (const value of cases) {
expect(parsePluginCapabilityNameArray(value)).toEqual({ ok: false });
}
});
test("parses valid capability grant arrays", () => {
expect(parsePluginCapabilityGrantArray([{ capabilityName: "http.outbound", scopeJson: { allowedHosts: ["api.example.com"] } }])).toEqual({
ok: true,
grants: [{ capabilityName: "http.outbound", scopeJson: { allowedHosts: ["api.example.com"] } }],
});
});
test("rejects duplicate capability grants", () => {
expect(
parsePluginCapabilityGrantArray([
{ capabilityName: "http.outbound", scopeJson: { allowedHosts: ["api.example.com"] } },
{ capabilityName: "http.outbound", scopeJson: { allowedHosts: ["api2.example.com"] } },
])
).toEqual({ ok: false });
});
test("rejects unsafe capability grant scopes", () => {
expect(parsePluginCapabilityGrantArray([{ capabilityName: "http.outbound", scopeJson: ["api.example.com"] }])).toEqual({ ok: false });
expect(parsePluginCapabilityGrantArray([{ capabilityName: "http.outbound", scopeJson: { __proto__: { polluted: true } } }])).toEqual({ ok: false });
expect(parsePluginCapabilityGrantArray([{ capabilityName: "http.outbound", scopeJson: { note: "x".repeat(16 * 1024) } }])).toEqual({ ok: false });
});
test("reads bounded JSON objects", async () => {
const response = await readPluginConsentJsonObject(
new Request("http://localhost/plugins", {
method: "POST",
body: JSON.stringify({ pluginId: "com.acme.hello" }),
headers: { "content-type": "application/json; charset=utf-8" },
})
);
expect(response).toEqual({ ok: true, value: { pluginId: "com.acme.hello" } });
});
test("rejects JSON object bodies without an application/json content type", async () => {
for (const headers of [{ "content-type": "text/plain" }, {}]) {
await expect(
readPluginConsentJsonObject(
new Request("http://localhost/plugins", {
method: "POST",
body: JSON.stringify({ pluginId: "com.acme.hello" }),
headers,
})
)
).resolves.toEqual({ ok: false, error: "unsupported_media_type" });
}
});
test("rejects oversized request bodies before parsing", async () => {
const response = await readPluginConsentUrlEncodedFormData(
new Request("http://localhost/plugins", {
method: "POST",
body: "op=enable&id=pl-1",
headers: {
"content-type": "application/x-www-form-urlencoded",
"content-length": String(129 * 1024),
},
})
);
expect(response).toEqual({ ok: false });
});
test("accepts only exact urlencoded form content types", async () => {
const valid = await readPluginConsentUrlEncodedFormData(
new Request("http://localhost/plugins", {
method: "POST",
body: "op=enable&id=pl-1",
headers: { "content-type": "application/x-www-form-urlencoded; charset=utf-8" },
})
);
expect(valid.ok).toBe(true);
if (valid.ok) {
expect(valid.formData.get("op")).toBe("enable");
}
for (const contentType of ["text/plain; application/x-www-form-urlencoded", "application/x-www-form-urlencoded-malformed"]) {
await expect(
readPluginConsentUrlEncodedFormData(
new Request("http://localhost/plugins", {
method: "POST",
body: "op=enable&id=pl-1",
headers: { "content-type": contentType },
})
)
).resolves.toEqual({ ok: false });
}
});
});