mattrguerra/meridian-ops-boardmainPrivate on GitHub, published here in full

headers.test.ts

Language TypeScript2.6 KB60 lines

apps/worker/test/headers.test.ts

  1. /**
  2. * The CSP must permit every data: URI kind the page actually embeds.
  3. *
  4. * The brand fonts are embedded as data: URIs. Without a font-src, `default-src
  5. * 'none'` blocks them for everyone, and nobody with the fonts installed locally
  6. * can see it, because the browser resolves the family name from the OS and
  7. * renders the intended face anyway. A blocked embed masked by a local install is
  8. * invisible on exactly the machines that build and review the page, so this is
  9. * pinned by a test rather than by eyeballing.
  10. */
  11. import { describe, expect, it } from 'vitest'
  12. import { MESSAGE_PAGE_HEADERS, PAGE_HEADERS } from '../src/index.js'
  13. describe('page CSP vs what the page embeds', () => {
  14. const csp = PAGE_HEADERS['content-security-policy']
  15. it('permits data: fonts, because the brand fonts are data: URIs', () => {
  16. expect(csp).toContain('font-src data:')
  17. })
  18. it('permits data: images, which the surfaces use for inline SVG', () => {
  19. expect(csp).toContain('img-src data:')
  20. })
  21. it('still defaults closed for everything unlisted', () => {
  22. expect(csp).toContain("default-src 'none'")
  23. })
  24. })
  25. /**
  26. * The reply feature needs no CSP directive, and that is a design decision worth
  27. * pinning rather than a happy accident.
  28. *
  29. * A modal submitting with fetch() would need `connect-src 'self'`. The compose
  30. * window is a native <dialog> around a plain form POST instead, so the page
  31. * still cannot open a connection to anywhere, including back to itself. If a future change adds one, this test should be
  32. * changed deliberately, with the reason written down.
  33. */
  34. describe('the compose window needs no new CSP directive', () => {
  35. it('has no connect-src at all: the page cannot open a connection anywhere', () => {
  36. expect(PAGE_HEADERS['content-security-policy']).not.toContain('connect-src')
  37. expect(MESSAGE_PAGE_HEADERS['content-security-policy']).not.toContain('connect-src')
  38. })
  39. it('permits a same-origin frame on the message page and nowhere wider', () => {
  40. // The message frame and the signature preview both live here.
  41. expect(MESSAGE_PAGE_HEADERS['content-security-policy']).toContain("frame-src 'self'")
  42. expect(MESSAGE_PAGE_HEADERS['content-security-policy']).not.toMatch(/frame-src[^;]*\*/)
  43. })
  44. it('still permits a same-origin form POST and nothing wider', () => {
  45. // Reply, mark-read, filter and signatures are all plain form POSTs.
  46. expect(PAGE_HEADERS['content-security-policy']).toContain("form-action 'self'")
  47. })
  48. it('the board page itself still cannot grow a frame', () => {
  49. expect(PAGE_HEADERS['content-security-policy']).not.toContain('frame-src')
  50. })
  51. })