Skip to content

Commit b6f5a9b

Browse files
committed
site/worker.js: allow year-month archive index pages
The hardening commit f2939e7 introduced a path allowlist but forgot to allow the YYYY/MM/index.html archive pages generated by rss._generate_month_pages. Existing pages on R2 became invisible: every monthly archive URL returned 404 even though the underlying object was present. Add a regex match for the year-month archive pattern and rewrite bare directory URLs (/2026/04/) to their index.html since the publish-site only uploads at the explicit key. The pattern is tight: only [0-9]{4}/[0-9]{2}/(index.html)? matches. Single-digit months, nested paths, and arbitrary files under year-month directories are still rejected. Add tests covering both the index.html and bare directory forms, plus negative cases for malformed paths. Generated-by: Claude AI Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
1 parent 83739a2 commit b6f5a9b

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

site/worker.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ const DENIED_PREFIXES = [
4646
'manifest.json',
4747
];
4848

49+
// Year-month archive pages: YYYY/MM/index.html (e.g. 2026/04/index.html)
50+
// Generated by rss._generate_month_pages and uploaded by gen-podcast
51+
// publish-site. Allowed only as exact index.html or bare directory.
52+
const ARCHIVE_MONTH_RE = /^[0-9]{4}\/[0-9]{2}\/(index\.html)?$/;
53+
4954
function isAllowedPath(key) {
5055
// Deny-first: block sensitive prefixes
5156
for (const denied of DENIED_PREFIXES) {
@@ -60,6 +65,9 @@ function isAllowedPath(key) {
6065
if (key.startsWith(prefix)) return true;
6166
}
6267

68+
// Year-month archive pages
69+
if (ARCHIVE_MONTH_RE.test(key)) return true;
70+
6371
return false;
6472
}
6573

@@ -96,6 +104,13 @@ export default {
96104
return new Response('Not found', { status: 404 });
97105
}
98106

107+
// Rewrite bare year-month directory URLs to their index.html.
108+
// /2026/04/ -> 2026/04/index.html. The publish-site only uploads
109+
// archive pages at the explicit index.html key.
110+
if (/^[0-9]{4}\/[0-9]{2}\/$/.test(key)) {
111+
key = key + 'index.html';
112+
}
113+
99114
// Support Range requests for audio seeking
100115
const rangeHeader = request.headers.get('Range');
101116
let object;

site/worker.test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,40 @@ test('missing objects return 404 even if path is allowed', async () => {
234234
const resp = await worker.fetch(req, env);
235235
assert.equal(resp.status, 404);
236236
});
237+
238+
239+
test('year-month archive index.html is served', async () => {
240+
const env = makeEnv({
241+
'2026/04/index.html': '<html>April 2026 archive</html>',
242+
});
243+
const req = makeRequest('/2026/04/index.html');
244+
const resp = await worker.fetch(req, env);
245+
assert.equal(resp.status, 200);
246+
const body = await resp.text();
247+
assert.ok(body.includes('April 2026 archive'));
248+
});
249+
250+
251+
test('year-month archive bare directory rewrites to index.html', async () => {
252+
const env = makeEnv({
253+
'2026/04/index.html': '<html>April 2026 archive</html>',
254+
});
255+
const req = makeRequest('/2026/04/');
256+
const resp = await worker.fetch(req, env);
257+
assert.equal(resp.status, 200);
258+
const body = await resp.text();
259+
assert.ok(body.includes('April 2026 archive'));
260+
});
261+
262+
263+
test('isAllowedPath accepts year-month archive paths', () => {
264+
assert.ok(isAllowedPath('2026/04/index.html'));
265+
assert.ok(isAllowedPath('2025/12/index.html'));
266+
assert.ok(isAllowedPath('2026/04/'));
267+
// Reject malformed year-month paths
268+
assert.ok(!isAllowedPath('2026/4/index.html')); // single-digit month
269+
assert.ok(!isAllowedPath('2026/04/something.html')); // non-index file
270+
assert.ok(!isAllowedPath('2026/04/secrets.json')); // non-index file
271+
assert.ok(!isAllowedPath('20266/04/index.html')); // 5-digit year
272+
assert.ok(!isAllowedPath('2026/04/sub/index.html')); // nested
273+
});

0 commit comments

Comments
 (0)