72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { configurePaymentFromConfig } from "../src/config.ts";
|
|
import { configurePaymentApi } from "../src/http.ts";
|
|
import { GET, POST } from "../src/runtime-api.ts";
|
|
import { memoryPaymentStore } from "../src/store.ts";
|
|
|
|
function request(path: string, body?: unknown) {
|
|
return new Request(`https://app.test${path}`, {
|
|
method: body ? "POST" : "GET",
|
|
headers: body ? { "content-type": "application/json" } : undefined,
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
}
|
|
|
|
test("package APIs use server subjects and never expose gateway secrets", async () => {
|
|
configurePaymentFromConfig(
|
|
{
|
|
default: "testGateway",
|
|
environment: "test",
|
|
gateways: { testGateway: { provider: "sandbox", secret: "server-only" } },
|
|
},
|
|
memoryPaymentStore(),
|
|
);
|
|
configurePaymentApi({ subject: (ctx) => ctx.user?.id });
|
|
|
|
const providers = await GET({ req: request("/api/payments/providers") });
|
|
const providerBody = await providers.text();
|
|
expect(providers.status).toBe(200);
|
|
expect(providerBody).toContain("testGateway");
|
|
expect(providerBody).toContain('"provider":"sandbox"');
|
|
expect(providerBody).not.toContain("server-only");
|
|
|
|
const denied = await POST({
|
|
req: request("/api/payments/intents", {
|
|
subject: "attacker-selected",
|
|
amount: 500,
|
|
currency: "USD",
|
|
idempotencyKey: "anonymous",
|
|
}),
|
|
});
|
|
expect(denied.status).toBe(403);
|
|
|
|
const created = await POST({
|
|
req: request("/api/payments/intents", {
|
|
subject: "attacker-selected",
|
|
amount: 500,
|
|
currency: "USD",
|
|
idempotencyKey: "owned",
|
|
}),
|
|
user: { id: "user-1" },
|
|
});
|
|
expect(created.status).toBe(201);
|
|
const payment = await created.json();
|
|
expect(payment.id).toStartWith("pay_");
|
|
expect(JSON.stringify(payment)).not.toContain("server-only");
|
|
|
|
const listed = await GET({
|
|
req: request("/api/payments/intents"),
|
|
user: { id: "user-1" },
|
|
});
|
|
expect((await listed.json()).payments).toHaveLength(1);
|
|
});
|
|
|
|
test("administrative payment APIs deny by default", async () => {
|
|
configurePaymentApi({ subject: () => "user-1" });
|
|
const response = await POST({
|
|
req: request("/api/payments/reconcile", {}),
|
|
user: { id: "user-1" },
|
|
});
|
|
expect(response.status).toBe(403);
|
|
});
|