Skip to content

Commit 66e54e8

Browse files
committed
fix: resolve code scanning warnings and harden error handling
1 parent 6d23bad commit 66e54e8

1 file changed

Lines changed: 35 additions & 10 deletions

File tree

server.js

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,36 @@ function escapeForJsString(input) {
5656
.replaceAll('\r', '');
5757
}
5858

59+
function decodeHtmlAttributeValue(input) {
60+
return String(input)
61+
.replace(/&(?:amp|quot|lt|gt|#39);/g, (entity) => {
62+
switch (entity) {
63+
case '&':
64+
return '&';
65+
case '"':
66+
return '"';
67+
case '<':
68+
return '<';
69+
case '&gt;':
70+
return '>';
71+
case '&#39;':
72+
return "'";
73+
default:
74+
return entity;
75+
}
76+
});
77+
}
78+
79+
function toPublicErrorMessage(err, fallback = 'Request failed') {
80+
const message = err instanceof Error ? err.message : String(err || '');
81+
const clean = message.replace(/\s+/g, ' ').trim();
82+
if (!clean) return fallback;
83+
if (clean.includes('\n') || /\bat\s+\S+/.test(clean) || clean.startsWith('Error:')) {
84+
return fallback;
85+
}
86+
return clean;
87+
}
88+
5989
function sendJson(res, status, data) {
6090
const body = JSON.stringify(data);
6191
res.writeHead(status, {
@@ -234,7 +264,7 @@ function parseAttributes(tag) {
234264
let m;
235265
while ((m = re.exec(attrSlice))) {
236266
const key = m[1].toLowerCase();
237-
const value = m[2] ?? m[3] ?? m[4] ?? '';
267+
const value = decodeHtmlAttributeValue(m[2] ?? m[3] ?? m[4] ?? '');
238268
attrs[key] = value;
239269
}
240270
return attrs;
@@ -287,12 +317,7 @@ function resolveUrl(raw, base) {
287317
const clean = raw
288318
.trim()
289319
.replace(/^url\((.*)\)$/i, '$1')
290-
.replace(/^['"]|['"]$/g, '')
291-
.replaceAll('&amp;', '&')
292-
.replaceAll('&quot;', '"')
293-
.replaceAll('&#39;', "'")
294-
.replaceAll('&lt;', '<')
295-
.replaceAll('&gt;', '>');
320+
.replace(/^['"]|['"]$/g, '');
296321
try {
297322
return new URL(clean, base).toString();
298323
} catch {
@@ -582,7 +607,7 @@ async function handleExtract(req, res, reqUrl) {
582607
groups,
583608
});
584609
} catch (err) {
585-
return sendJson(res, 400, { error: String(err.message || err) });
610+
return sendJson(res, 400, { error: toPublicErrorMessage(err, 'Unable to extract images from that URL') });
586611
}
587612
}
588613

@@ -615,7 +640,7 @@ async function handleAsset(req, res, reqUrl) {
615640
});
616641
res.end(buf);
617642
} catch (err) {
618-
return sendJson(res, 400, { error: String(err.message || err) });
643+
return sendJson(res, 400, { error: toPublicErrorMessage(err, 'Unable to fetch that asset') });
619644
}
620645
}
621646

@@ -657,7 +682,7 @@ const server = http.createServer(async (req, res) => {
657682
});
658683
res.end(rendered);
659684
} catch (err) {
660-
sendText(res, 500, String(err.message || err));
685+
sendText(res, 500, 'Internal Server Error');
661686
}
662687
return;
663688
}

0 commit comments

Comments
 (0)