Skip to content

fix: CORS + rate-limit + readonly pad IDs on /export/markdown#183

Open
JohnMcLear wants to merge 3 commits intomasterfrom
fix/export-cors-header-139
Open

fix: CORS + rate-limit + readonly pad IDs on /export/markdown#183
JohnMcLear wants to merge 3 commits intomasterfrom
fix/export-cors-header-139

Conversation

@JohnMcLear
Copy link
Copy Markdown
Member

@JohnMcLear JohnMcLear commented Apr 19, 2026

Summary

Brings the /export/markdown routes in line with the protections that Etherpad core applies to its native /export/:type routes (see importexport.ts):

  1. CORS header (Access-Control-Allow-Origin: *) on both export routes — fixes the error reported in importExportRateLimiting setting ignored, CORS header ‘Access-Control-Allow-Origin’ missing #139 (browsers block repeated or cross-origin fetches).
  2. Rate limiting via the core settings.importExportRateLimiting + the shared express-rate-limit module. Without this, callers could sidestep export throttling by switching format to markdown. Matches the exact middleware pattern used in core.
  3. Readonly pad IDs (r.*) are now resolved through ReadOnlyManager before padManager.getPad is called. Previously getPad('r.xxx') created an empty pad under the readonly ID and the export returned nothing.

Supersedes / incorporates the ideas from #142 (which did the same three things, but against the pre-TypeScript codebase and is therefore stale).

Files

  • express.ts — CORS header, rate-limit middleware for both route variants
  • exportMarkdown.ts — readonly pad ID resolution in getPadMarkdownDocument
  • package.json — adds express-rate-limit as a peerDependency (core already ships it, this just documents the requirement)

Test plan

  • pnpm run lint clean
  • /p/:padId/export/markdown from a different origin: response has Access-Control-Allow-Origin: *
  • Burst of requests to /export/markdown beyond importExportRateLimiting.max gets 429 + warning in logs
  • Request against an r.* readonly pad returns the underlying pad's markdown (previously returned empty)

Closes #139, supersedes #142.

JohnMcLear and others added 2 commits April 19, 2026 17:20
Mirrors the Access-Control-Allow-Origin header that Etherpad core sets
on its native /export/* routes (see etherpad-lite's
src/node/hooks/express/importexport.ts). Without this, browsers block
repeated fetches of /p/:padId/export/markdown with a CORS error —
which integrators hit when rate-limited exports get retried or when
the export is initiated from a different origin than the pad.

Closes #139

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expands the previous CORS-only change so that /p/:padId/export/markdown
and /p/:padId/:revNum/export/markdown now match the full set of
protections that Etherpad core applies to its native /export/:type
routes (src/node/hooks/express/importexport.ts):

- Rate limit both routes with the core `importExportRateLimiting`
  settings, using the shared `express-rate-limit` module. Without this,
  a caller can bypass export throttling by switching from pdf/doc/txt/
  html/etc. to markdown.
- Resolve readonly pad IDs (`r.*`) through ReadOnlyManager before
  loading the pad. Previously padManager.getPad('r.xxx') would create
  an empty pad under the readonly ID and the export returned nothing.

`express-rate-limit` is already shipped by Etherpad core; declared here
as a peerDependency so the requirement is explicit.

Refs #139 (CORS), #142 (prior attempt that bundled rate limit +
readonly fix + CORS — this commit brings its ideas into the current
TS-based codebase).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JohnMcLear JohnMcLear changed the title fix: set Access-Control-Allow-Origin on /export/markdown routes fix: CORS + rate-limit + readonly pad IDs on /export/markdown Apr 19, 2026
ReadOnlyManager uses `export default { ... }`, so under CommonJS require()
the methods live on `.default` — `readOnlyManager.isReadOnlyId` was
undefined and `/export/markdown` threw 500. Unwrap explicitly so the
readonly-pad path actually resolves.

Caught by backend test "Import and Export markdown returns ok" on
the new resolvePadId call path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

importExportRateLimiting setting ignored, CORS header ‘Access-Control-Allow-Origin’ missing

1 participant