chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
// The Cloudflare API passthrough for the site-hosted setup wizard: open CORS
// on its own responses, an allowlist of API paths, and nothing kept.
import { afterEach, describe, expect, it, vi } from 'vitest';
import {
CF_API_PROXY_PREFIX,
cfApiProxyEnabled,
handleCfApiProxy,
} from '../src/cf-api-proxy.js';
const BASE = `https://start.example.com${CF_API_PROXY_PREFIX.slice(0, -1)}`;
afterEach(() => {
vi.unstubAllGlobals();
});
describe('cf api proxy', () => {
it('is off unless the flag says true', () => {
expect(cfApiProxyEnabled({})).toBe(false);
expect(cfApiProxyEnabled({ PDS_EXPERIMENTAL_CF_API_PROXY: '1' })).toBe(
false,
);
expect(cfApiProxyEnabled({ PDS_EXPERIMENTAL_CF_API_PROXY: 'true' })).toBe(
true,
);
});
it('answers the preflight with open CORS', async () => {
const response = await handleCfApiProxy(
new Request(`${BASE}/client/v4/accounts`, { method: 'OPTIONS' }),
);
expect(response.status).toBe(204);
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
expect(response.headers.get('Access-Control-Allow-Headers')).toContain(
'Authorization',
);
});
it('refuses paths outside the allowlist', async () => {
for (const path of [
'/client/v4/user',
'/client/v4/zones/abc123/settings',
'/client/v4/zones/00000000000000000000000000000000/purge_cache',
]) {
const response = await handleCfApiProxy(
new Request(`${BASE}${path}`, {
headers: { Authorization: 'Bearer t' },
}),
);
expect(response.status, path).toBe(403);
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
}
});
it('allows the zone list and a zone dns_records path', async () => {
const stub = vi.fn(
async () =>
new Response('{"success":true}', {
headers: { 'Content-Type': 'application/json' },
}),
);
vi.stubGlobal('fetch', stub);
for (const path of [
'/client/v4/zones',
'/client/v4/zones/00000000000000000000000000000000/dns_records',
'/client/v4/zones/00000000000000000000000000000000/dns_records/11111111111111111111111111111111',
]) {
const response = await handleCfApiProxy(
new Request(`${BASE}${path}`, {
headers: { Authorization: 'Bearer t' },
}),
);
expect(response.status, path).toBe(200);
}
});
it('requires a token', async () => {
const response = await handleCfApiProxy(
new Request(`${BASE}/client/v4/accounts`),
);
expect(response.status).toBe(401);
});
it('forwards an allowed call with the token and the query string', async () => {
const stub = vi.fn(
async () =>
new Response('{"success":true}', {
headers: {
'Content-Type': 'application/json',
'Set-Cookie': 'sneaky=1',
},
}),
);
vi.stubGlobal('fetch', stub);
const response = await handleCfApiProxy(
new Request(`${BASE}/client/v4/accounts?page=2`, {
headers: { Authorization: 'Bearer t' },
}),
);
expect(response.status).toBe(200);
expect(await response.json()).toEqual({ success: true });
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
// The upstream cookie does not ride through.
expect(response.headers.get('Set-Cookie')).toBe(null);
const [url, init] = /** @type {[string, RequestInit]} */ (
/** @type {unknown} */ (stub.mock.calls[0])
);
expect(url).toBe('https://api.cloudflare.com/client/v4/accounts?page=2');
expect(
/** @type {Record<string, string>} */ (init.headers).Authorization,
).toBe('Bearer t');
});
it('forwards a PUT body', async () => {
const stub = vi.fn(async (_url, /** @type {any} */ init) => {
const echoed = await new Response(init.body).text();
return new Response(echoed, {
headers: { 'Content-Type': 'application/json' },
});
});
vi.stubGlobal('fetch', stub);
const response = await handleCfApiProxy(
new Request(`${BASE}/client/v4/accounts/abc/workers/scripts/pds`, {
method: 'PUT',
headers: { Authorization: 'Bearer t', 'Content-Type': 'text/plain' },
body: 'module bytes',
}),
);
expect(await response.text()).toBe('module bytes');
});
});