From 3489a748551bac617c00281a8a84b6c60391a90a Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Sun, 8 Feb 2026 21:52:44 +0100 Subject: [PATCH] [feat](trx-frontend-http): display non-ASCII bytes as yellow hex in APRS info Render non-ASCII characters in decoded APRS info text as yellow [0xNN] hex tags. Printable ASCII is HTML-escaped to prevent XSS. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Stanislaw Grams --- .../assets/web/plugins/aprs.js | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js index 7d5508d..cae8edd 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js @@ -429,6 +429,25 @@ function parseAprsLon(s) { return Math.round(lon * 1e6) / 1e6; } +function escapeAprsInfo(str) { + let out = ""; + for (let i = 0; i < str.length; i++) { + const code = str.charCodeAt(i); + if (code >= 0x20 && code <= 0x7e) { + const ch = str[i]; + if (ch === "<") out += "<"; + else if (ch === ">") out += ">"; + else if (ch === "&") out += "&"; + else if (ch === '"') out += """; + else out += ch; + } else { + const hex = code.toString(16).toUpperCase().padStart(2, "0"); + out += `[0x${hex}]`; + } + } + return out; +} + function addAprsPacket(pkt) { const tag = pkt.crcOk ? "[APRS]" : "[APRS-CRC-FAIL]"; console.log(tag, `${pkt.srcCall}>${pkt.destCall}${pkt.path ? "," + pkt.path : ""}: ${pkt.info}`, pkt); @@ -453,7 +472,7 @@ function addAprsPacket(pkt) { const osmUrl = `https://www.openstreetmap.org/?mlat=${pkt.lat}&mlon=${pkt.lon}#map=15/${pkt.lat}/${pkt.lon}`; posHtml = ` ${pkt.lat.toFixed(4)}, ${pkt.lon.toFixed(4)}`; } - row.innerHTML = `${ts}${symbolHtml}${pkt.srcCall}>${pkt.destCall}${pkt.path ? "," + pkt.path : ""}: ${pkt.info}${posHtml}${crcTag}`; + row.innerHTML = `${ts}${symbolHtml}${pkt.srcCall}>${pkt.destCall}${pkt.path ? "," + pkt.path : ""}: ${escapeAprsInfo(pkt.info)}${posHtml}${crcTag}`; if (pkt.lat != null && pkt.lon != null && window.aprsMapAddStation) { window.aprsMapAddStation(pkt.srcCall, pkt.lat, pkt.lon, pkt.info, pkt.symbolTable, pkt.symbolCode); }