Skip to content

Commit 4609028

Browse files
Merge pull request #346 from appdevforall/fix/ADFA-5042-zim-download-project-subdir
ADFA-5042: build the ZIM download URL from the project subdir; bump to 1.1.2
2 parents 15148fe + 44fba27 commit 4609028

3 files changed

Lines changed: 21 additions & 8 deletions

File tree

‎static/dashboard/package-lock.json‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎static/dashboard/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dashboard-console",
3-
"version": "1.1.1",
3+
"version": "1.1.2",
44
"description": "",
55
"main": "index.js",
66
"scripts": {

‎static/dashboard/sockets/kiwix.exec.ts‎

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import fs from 'fs';
1111
import path from 'path';
1212

1313
const ZIMS_DIR = '/library/zims/content/';
14-
const BASE_URL = 'https://download.kiwix.org/zim/wikipedia/';
14+
// ADFA-5042: root of the Kiwix ZIM mirror. Each requested id MUST carry its own project subdirectory
15+
// (e.g. "zimit/foo.zim", "other/bar.zim", "gutenberg/baz.zim") — ZIMs are not all under wikipedia/.
16+
const BASE_URL = 'https://download.kiwix.org/zim/';
17+
// Allowed id shape: subdir segment(s) + filename. Guards the outbound URL (no "..", no traversal).
18+
const SAFE_ID = /^[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/;
1519
const INDEXER = '/usr/bin/iiab-make-kiwix-lib';
1620
const SAFETY_BUFFER_BYTES = 5 * 1024 * 1024 * 1024; // keep >=5 GB free
1721

@@ -75,15 +79,24 @@ function cleanupMetadata(): void {
7579
}
7680

7781
const kiwixRunner: (ctx: RunnerContext) => Promise<void> = async (ctx) => {
78-
const zims = ctx.ids.map((z) => path.basename(z)).filter((z) => z.endsWith('.zim'));
79-
if (zims.length === 0) throw new Error('no ZIMs requested');
82+
// ADFA-5042: keep each id's project subdir for the URL; use basename only for the local file/display.
83+
const ids = ctx.ids.map(String).map((z) => z.replace(/^\/+/, '')).filter((z) => z.endsWith('.zim'));
84+
if (ids.length === 0) throw new Error('no ZIMs requested');
85+
for (const id of ids) {
86+
// Require the project subdir — every ZIM on the mirror lives under one (/zim/<project>/…).
87+
if (id.includes('..') || !id.includes('/') || !SAFE_ID.test(id)) {
88+
throw new Error(`invalid ZIM id (expected "<project>/<file>.zim"): ${id}`);
89+
}
90+
}
91+
const files = ids.map((z) => path.basename(z));
8092

8193
assertFreeSpace();
8294
ctx.throwIfCanceled();
8395

8496
// --- Download phase -----------------------------------------------------
85-
ctx.update({ phase: 'downloading', percent: 0, speed: 0, detail: zims.join(', ') });
86-
const urls = zims.map((z) => BASE_URL + z);
97+
ctx.update({ phase: 'downloading', percent: 0, speed: 0, detail: files.join(', ') });
98+
// Each id already carries its project subdir on the mirror (/zim/<project>/<file>).
99+
const urls = ids.map((z) => BASE_URL + z);
87100

88101
await new Promise<void>((resolve, reject) => {
89102
const dl = ctx.spawn('/usr/bin/aria2c', [...ARIA2_ARGS, ...urls]);

0 commit comments

Comments
 (0)