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

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
98 lines · 3.1 KB Raw History
import { afterEach, describe, expect, it, vi } from 'vitest';
import { createIdentityHandlers } from '../src/handlers/xrpc-identity.js';

// These take the hostname and global fetch, and nothing else in the context.
function makePds(/** @type {string | undefined} */ hostname) {
  return createIdentityHandlers(
    /** @type {any} */ ({ hostname, readOnly: false }),
  );
}

describe('ownDomain', () => {
  it('drops the port and lowercases the configured hostname', () => {
    expect(makePds('Example.com:3000').ownDomain()).toBe('example.com');
  });

  it('falls back to the request host when no hostname is configured', () => {
    expect(makePds(undefined).ownDomain('Req.Host:8080')).toBe('req.host');
    expect(makePds('').ownDomain()).toBe('');
  });
});

describe('classifyHandle', () => {
  it('marks the server’s own address as self', () => {
    expect(makePds('example.com').classifyHandle('example.com')).toBe('self');
  });

  it('marks a subdomain of the server as internal', () => {
    const pds = makePds('example.com');
    expect(pds.classifyHandle('alice.example.com')).toBe('internal');
    // A look-alike suffix is not a subdomain
    expect(pds.classifyHandle('notexample.com')).toBe('external');
  });

  it('marks a domain elsewhere as external', () => {
    expect(makePds('example.com').classifyHandle('alice.com')).toBe('external');
  });

  it('treats everything as external when the domain is unknown', () => {
    expect(makePds('').classifyHandle('anything.com')).toBe('external');
  });
});

describe('resolveHandleDid', () => {
  afterEach(() => vi.unstubAllGlobals());

  it('reads the DID from an _atproto DNS TXT record', async () => {
    vi.stubGlobal(
      'fetch',
      vi.fn(async (url) => {
        expect(String(url)).toContain('_atproto.alice.com');
        return {
          ok: true,
          json: async () => ({
            Answer: [
              { type: 16, data: '"did=did:plc:abcdefghijklmnopqrstuvwx"' },
            ],
          }),
        };
      }),
    );
    expect(await makePds('example.com').resolveHandleDid('alice.com')).toBe(
      'did:plc:abcdefghijklmnopqrstuvwx',
    );
  });

  it('falls back to the HTTPS well-known when DNS has no record', async () => {
    vi.stubGlobal(
      'fetch',
      vi.fn(async (url) => {
        if (String(url).includes('dns-query')) {
          return { ok: true, json: async () => ({ Answer: [] }) };
        }
        expect(String(url)).toBe('https://alice.com/.well-known/atproto-did');
        return {
          ok: true,
          text: async () => 'did:plc:ab234567ab234567ab234567\n',
        };
      }),
    );
    expect(await makePds('example.com').resolveHandleDid('alice.com')).toBe(
      'did:plc:ab234567ab234567ab234567',
    );
  });

  it('returns null when the handle points nowhere', async () => {
    vi.stubGlobal(
      'fetch',
      vi.fn(async (url) =>
        String(url).includes('dns-query')
          ? { ok: true, json: async () => ({ Answer: [] }) }
          : { ok: false },
      ),
    );
    expect(
      await makePds('example.com').resolveHandleDid('nope.com'),
    ).toBeNull();
  });
});