fix(reader): allow dictionary APIs in CSP connect-src

The epub reader's "Define" feature relies on api.dictionaryapi.dev and
wiktionary.org. These domains were being blocked by the server's Content
Security Policy. Adding them to the connect-src directive allows the
client to successfully fetch word definitions.

Closes #403
This commit is contained in:
neon
2026-06-22 17:17:15 +00:00
parent f5079d5f04
commit 7661765853
3 changed files with 16 additions and 3 deletions
@@ -82,8 +82,6 @@ describe('cfiRangesOverlap', () => {
})
it('returns false when selection is entirely before annotation', () => {
const before = 'epubcfi(/6/4!/4/2,/2/1:0,/2/1:0)'
// 0:0 to 0:0 is before 0:0 to 0:20 only if no overlap; here they share start — overlap
const clearlyBefore = 'epubcfi(/6/2!/4/2,/2/1:0,/2/1:5)'
expect(cfiRangesOverlap(clearlyBefore, ann)).toBe(false)
})
@@ -167,6 +167,13 @@ describe('buildCspDirectives', () => {
expect(connectSrc).not.toContain('https://cloudflareinsights.com');
});
it('includes dictionary lookup endpoints used by the epub reader', () => {
const { connectSrc } = buildCspDirectives();
expect(connectSrc).toContain('https://api.dictionaryapi.dev');
expect(connectSrc).toContain('https://*.wiktionary.org');
});
});
describe('scriptSrc with Cloudflare Insights', () => {
+9 -1
View File
@@ -37,12 +37,20 @@ export interface CspOptions {
const CLOUDFLARE_INSIGHTS_SCRIPT_SRC = 'https://static.cloudflareinsights.com';
const CLOUDFLARE_INSIGHTS_CONNECT_SRC = 'https://cloudflareinsights.com';
const DICTIONARY_CONNECT_SRC = ['https://api.dictionaryapi.dev', 'https://*.wiktionary.org'];
export function buildCspDirectives(options: CspOptions = {}) {
const { allowCloudflareInsights = false } = options;
const scriptSrc = ["'self'", "'wasm-unsafe-eval'", ...(allowCloudflareInsights ? [CLOUDFLARE_INSIGHTS_SCRIPT_SRC] : [])];
const connectSrc = ["'self'", 'ws:', 'wss:', 'https://cdn.jsdelivr.net', ...(allowCloudflareInsights ? [CLOUDFLARE_INSIGHTS_CONNECT_SRC] : [])];
const connectSrc = [
"'self'",
'ws:',
'wss:',
'https://cdn.jsdelivr.net',
...DICTIONARY_CONNECT_SRC,
...(allowCloudflareInsights ? [CLOUDFLARE_INSIGHTS_CONNECT_SRC] : []),
];
return {
defaultSrc: ["'self'"],