openvibers/openvibe.work Commits

Work: escaped HTML in a board's description (Arbeitnow) is stripped too, so excerpts never show markup as words

OP OpenVibers committed 8 Oct 2026 · 8208526589 · 2 files, +12 −3


Changes

ddiff --git a/server/jobs/text.js b/server/jobs/text.js
iindex 5227497..cc8deb9 100644
---- a/server/jobs/text.js
++++ b/server/jobs/text.js
@@@ -27,15 +27,22 @@ function decode(text) {
}
/** The description as plain text: no tags, no script or style content, whitespace collapsed. */
--function stripHtml(html) {
-- let s = String(html == null ? '' : html);
++function stripOnce(s) {
s = s.replace(/<!--[\s\S]*?-->/g, ' ');
// A script or style element's content is code, not prose; drop it with its tags.
s = s.replace(/<(script|style|noscript|template|svg)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, ' ');
// Block boundaries become a space so words either side do not run together.
s = s.replace(/<\/?(br|p|div|li|ul|ol|tr|td|th|h[1-6]|section|article|header|footer|blockquote|pre|figure|hr)\b[^>]*>/gi, ' ');
s = s.replace(/<[^>]*>/g, ' ');
-- s = decode(s);
++ return decode(s);
++}
++
++function stripHtml(html) {
++ let s = stripOnce(String(html == null ? '' : html));
++ // Some boards send their HTML escaped (Arbeitnow: "&lt;div class=&quot;…&quot;&gt;&lt;p&gt;…"): one decode brings the
++ // markup back, so it is stripped a second time. Two passes at most: a third layer is not a description.
++ // Only real HTML tags count as markup coming back; "&lt;ok&gt;" in prose stays the text "ok".
++ if (/<\/?(p|div|span|br|ul|ol|li|a|b|i|em|strong|h[1-6]|table|tr|td|section|article|blockquote|pre|code|img|hr|script|style)\b[^>]*>/i.test(s)) s = stripOnce(s);
// An unmatched '<' left by broken markup is not something a listing should show.
s = s.replace(/<[^>]*$/g, ' ').replace(/[<>]/g, ' ');
return s.replace(/\s+/g, ' ').trim();
ddiff --git a/test/ingest.test.js b/test/ingest.test.js
iindex 413b30c..574503f 100644
---- a/test/ingest.test.js
++++ b/test/ingest.test.js
@@@ -80,6 +80,8 @@ const DAY = 86_400_000;
assert.strictEqual(stripHtml('<style>p{color:red}</style><p>real</p>'), 'real');
assert.strictEqual(stripHtml('<script>alert(1)</script>'), '');
assert.strictEqual(stripHtml(null), '');
++ // Arbeitnow sends some descriptions as escaped HTML: the markup must not show up as words.
++ assert.strictEqual(stripHtml('&lt;div class=&quot;content-intro&quot;&gt;&lt;p&gt;GitLab is here.&lt;/p&gt;&lt;script&gt;x()&lt;/script&gt;'), 'GitLab is here.');
// A doubly-encoded tag decodes to text and is then dropped, never re-formed into markup.
assert.ok(!stripHtml('&lt;script&gt;alert(1)&lt;/script&gt;').includes('<'));
assert.strictEqual(excerpt('<p>short</p>'), 'short');