diff --git a/api/src/routes/icons.js b/api/src/routes/icons.js index 2b29bc7a..d7eb1652 100644 --- a/api/src/routes/icons.js +++ b/api/src/routes/icons.js @@ -54,6 +54,13 @@ const ICON_CACHE_TTL = 24 * 60 * 60 * 1000; on('GET', '/api/icons/search', async (req, res) => { const q = (new URL(req.url, 'http://x').searchParams.get('q') || '').trim(); if (!q) return json(res, 200, { results: [] }); + if (IS_DEMO) { + return json(res, 403, { + error: 'Outbound requests are disabled in demo mode', + kind: KIND.BLOCKED, + code: 'blocked.demo', + }); + } try { json(res, 200, { results: await searchIcons(q) }); } catch (e) { diff --git a/api/test/demo-routes.test.js b/api/test/demo-routes.test.js index e7a8d62e..1d99c238 100644 --- a/api/test/demo-routes.test.js +++ b/api/test/demo-routes.test.js @@ -98,3 +98,18 @@ test('no demo write reached the disk', () => { assert.equal(fs.existsSync(process.env.CONFIG_PATH), false); assert.deepEqual(fs.readdirSync(process.env.ICONS_PATH), []); }); + +test('icon search answers the demo refusal instead of failing on the blocked catalogues', async () => { + const r = await new Promise((resolve, reject) => { + http + .get(`${base}/api/icons/search?q=plex`, res => { + let raw = ''; + res.on('data', c => (raw += c)); + res.on('end', () => resolve({ status: res.statusCode, body: JSON.parse(raw) })); + }) + .on('error', reject); + }); + assert.equal(r.status, 403); + assert.equal(r.body.code, 'blocked.demo'); + assert.equal(r.body.kind, 'blocked'); +}); diff --git a/ui/admin/index.html b/ui/admin/index.html index 28a56421..cc9e837a 100644 --- a/ui/admin/index.html +++ b/ui/admin/index.html @@ -302,6 +302,6 @@