~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
220 lines · 7.6 KB Raw History
// The core seam: PersonalDataServer.fetch() hands non-PDS hostnames to the
// site handler before any PDS machinery runs. Every position of that check
// is load-bearing — these tests pin the ordering, the flag-off path, and
// the header hygiene of site responses.

import { PersonalDataServer } from '@pdsjs/core';
import {
  CID,
  cborEncodeDagCbor,
  cidToString,
  createBlobCid,
  createCid,
} from '@pdsjs/core/repo';
import { beforeEach, describe, expect, it } from 'vitest';
import { createSiteHandler } from '../src/handler.js';
import { clearManifestCache } from '../src/manifest.js';

const DID = 'did:plc:seamtest';
const PDS_HOST = 'pds.example.com';
const SITE_DOMAIN = 'example.com';

/** Build a one-file site record plus its blob store. */
async function siteFixture() {
  const data = new TextEncoder().encode('<h1>site</h1>');
  const cidBytes = await createBlobCid(data);
  const blobCid = cidToString(cidBytes);
  const record = {
    $type: 'dev.pdsjs.site.deploy',
    files: [
      {
        path: 'index.html',
        blob: {
          $type: 'blob',
          ref: new CID(cidBytes),
          mimeType: 'text/html',
          size: data.length,
        },
      },
    ],
    createdAt: '2026-08-06T00:00:00.000Z',
  };
  const bytes = cborEncodeDagCbor(record);
  return {
    recordCid: cidToString(await createCid(bytes)),
    recordBytes: bytes,
    blobCid,
    blobData: data,
  };
}

/**
 * A PDS with just enough ports mocked to dispatch requests, optionally with
 * the site handler composed in.
 * @param {{sites?: boolean, hostname?: string}} [opts]
 */
async function makePds(opts = {}) {
  const fixture = await siteFixture();
  const actorStorage = /** @type {any} */ ({
    getRecord: async (/** @type {string} */ uri) =>
      uri === `at://${DID}/dev.pdsjs.site.deploy/home`
        ? { cid: fixture.recordCid, value: fixture.recordBytes }
        : null,
    getDid: async () => DID,
  });
  const blobs = /** @type {any} */ ({
    get: async (/** @type {string} */ _did, /** @type {string} */ cid) =>
      cid === fixture.blobCid
        ? { data: fixture.blobData, mimeType: 'text/html' }
        : null,
  });
  const siteHandler = opts.sites
    ? createSiteHandler({
        actorStorage,
        blobs,
        getDid: async () => DID,
        siteDomain: SITE_DOMAIN,
      })
    : undefined;
  return new PersonalDataServer({
    actorStorage,
    sharedStorage: /** @type {any} */ ({}),
    blobs,
    jwtSecret: 'seam-test-secret',
    hostname: opts.hostname ?? PDS_HOST,
    extensions: siteHandler
      ? [() => ({ name: 'sites', handleHost: siteHandler })]
      : [],
  });
}

beforeEach(() => clearManifestCache());

describe('site seam, flag off', () => {
  it('treats foreign hostnames exactly like the PDS hostname', async () => {
    const pds = await makePds({ sites: false });
    const response = await pds.fetch(
      new Request('https://home.example.com/index.html'),
    );
    expect(response.status).toBe(404);
    // Normal dispatch answered: CORS decoration proves it
    expect(response.headers.get('access-control-allow-origin')).toBe('*');
  });

  it('answers preflights with CORS on any hostname', async () => {
    const pds = await makePds({ sites: false });
    const response = await pds.fetch(
      new Request('https://home.example.com/', { method: 'OPTIONS' }),
    );
    expect(response.status).toBe(200);
    expect(response.headers.get('access-control-allow-origin')).toBe('*');
  });

  it('mounts no host handler', async () => {
    const pds = await makePds({ sites: false });
    expect(pds.extensions.some((e) => e.handleHost)).toBe(false);
  });
});

describe('site seam, flag on', () => {
  it('serves the site outside the PDS API middleware', async () => {
    const pds = await makePds({ sites: true });
    const response = await pds.fetch(new Request('https://example.com/'));
    expect(response.status).toBe(200);
    expect(await response.text()).toBe('<h1>site</h1>');
    // The open origin is the sites package's own header. The API
    // middleware's companion headers prove the site path bypassed it.
    expect(response.headers.get('access-control-allow-origin')).toBe('*');
    expect(response.headers.get('access-control-allow-methods')).toBeNull();
  });

  it('adds no DPoP nonce to site responses', async () => {
    const pds = await makePds({ sites: true });
    const response = await pds.fetch(
      new Request('https://example.com/', {
        headers: { Authorization: 'DPoP faketoken' },
      }),
    );
    expect(response.status).toBe(200);
    expect(response.headers.get('dpop-nonce')).toBeNull();

    // The same request on the PDS hostname does get a nonce, proving the
    // site path bypassed withDpopNonce rather than nonces being off.
    const pdsResponse = await pds.fetch(
      new Request(`https://${PDS_HOST}/nope`, {
        headers: { Authorization: 'DPoP faketoken' },
      }),
    );
    expect(pdsResponse.headers.get('dpop-nonce')).not.toBeNull();
  });

  it('answers OPTIONS on site hostnames with 405, not a CORS preflight', async () => {
    const pds = await makePds({ sites: true });
    const response = await pds.fetch(
      new Request('https://example.com/', { method: 'OPTIONS' }),
    );
    expect(response.status).toBe(405);
    expect(response.headers.get('allow')).toBe('GET, HEAD');
    expect(response.headers.get('access-control-allow-origin')).toBeNull();
  });

  it('keeps /account on a site hostname inside the site', async () => {
    const pds = await makePds({ sites: true });
    const response = await pds.fetch(
      new Request('https://home.example.com/account'),
    );
    // The site 404 page, not the PDS account surface
    expect(response.status).toBe(404);
    expect(await response.text()).toContain('Nothing is deployed here');
  });

  it('keeps XRPC off site hostnames', async () => {
    const pds = await makePds({ sites: true });
    const response = await pds.fetch(
      new Request('https://home.example.com/xrpc/_health'),
    );
    expect(response.status).toBe(404);
    expect(await response.text()).toContain('Nothing is deployed here');
  });

  it('leaves the PDS hostname entirely alone', async () => {
    const pds = await makePds({ sites: true });
    const health = await pds.fetch(
      new Request(`https://${PDS_HOST}/xrpc/_health`),
    );
    expect(health.status).toBe(200);
    expect(health.headers.get('access-control-allow-origin')).toBe('*');
    // Even though "pds" parses as a valid site label under example.com,
    // the exact-hostname guard wins before the handler could look it up.
  });

  it('matches a configured hostname that carries a port', async () => {
    const pds = await makePds({ sites: true, hostname: `${PDS_HOST}:3443` });
    const health = await pds.fetch(
      new Request(`https://${PDS_HOST}/xrpc/_health`),
    );
    expect(health.status).toBe(200);
    expect(health.headers.get('access-control-allow-origin')).toBe('*');
  });

  it('falls through to normal dispatch for unrelated hostnames', async () => {
    const pds = await makePds({ sites: true });
    const response = await pds.fetch(new Request('https://elsewhere.org/nope'));
    expect(response.status).toBe(404);
    expect(response.headers.get('access-control-allow-origin')).toBe('*');
  });

  it('answers handle verification on the apex', async () => {
    const pds = await makePds({ sites: true });
    const response = await pds.fetch(
      new Request(`https://${SITE_DOMAIN}/.well-known/atproto-did`),
    );
    expect(response.status).toBe(200);
    expect(await response.text()).toBe(DID);
  });

  it('mounts a host handler', async () => {
    const pds = await makePds({ sites: true });
    expect(pds.extensions.some((e) => e.handleHost)).toBe(true);
  });
});