An unescaped quote ended the onclick attribute early, so clicking an error line did nothing
This commit is contained in:
@@ -1159,6 +1159,15 @@ function vvEscHtml(s) {
|
||||
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
|
||||
// For text going INSIDE a double-quoted attribute, which vvEscHtml does not cover: it leaves "
|
||||
// alone, and a quote there ends the attribute early and silently destroys the handler after it.
|
||||
// That is not a theoretical hazard — it shipped, and an onclick built from JSON.stringify() output
|
||||
// was truncated to "vvErrOpenAtLine(" and did nothing at all when clicked.
|
||||
function vvEscAttr(s) {
|
||||
return String(s).replace(/&/g,'&').replace(/"/g,'"')
|
||||
.replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
|
||||
function vvPost(url, data) {
|
||||
const params = new URLSearchParams({csrf_token, ...data});
|
||||
return fetch(url, {
|
||||
@@ -2787,16 +2796,20 @@ function vvUpdateErrors(errors) {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
let html = '<div class="vv-errors-list">';
|
||||
for (const e of unacked) {
|
||||
const jobId = "'" + (e.script + '.sh').replace(/\\/g,"\\\\").replace(/'/g,"\\'") + "'";
|
||||
// JSON.stringify rather than the hand-rolled quote escaping above: this one is embedded in an
|
||||
// attribute alongside the error text, which is arbitrary log output and not to be trusted to
|
||||
// contain no quotes.
|
||||
const scriptJs = vvEscHtml(JSON.stringify(e.script));
|
||||
const lineJs = vvEscHtml(JSON.stringify(e.line));
|
||||
// JSON.stringify for correct JS literals, then attribute-escaped: the error text is arbitrary
|
||||
// log output and absolutely will contain quotes eventually.
|
||||
const scriptJs = vvEscAttr(JSON.stringify(e.script));
|
||||
const lineJs = vvEscAttr(JSON.stringify(e.line));
|
||||
const label = e.script.split('/').pop().replace(/_/g, ' ');
|
||||
html += '<div class="vv-err-row">'
|
||||
+ '<div class="vv-err-top">'
|
||||
+ '<span class="vv-err-script" onclick="vvOpenRight(' + jobId + ')" style="cursor:pointer" title="' + vvEscHtml(e.script) + '">' + vvEscHtml(label) + '</span>'
|
||||
// The name goes to the same place as the text below it. Two clickable halves of one row
|
||||
// behaving differently — one acking, one not — is how an error looks acknowledged when
|
||||
// it is not, which is worse than either behaviour on its own.
|
||||
+ '<span class="vv-err-script" style="cursor:pointer"'
|
||||
+ ' title="' + vvEscAttr(e.script) + ' — opens the log at this line and acknowledges it"'
|
||||
+ ' onclick="vvErrOpenAtLine(' + scriptJs + ',' + e.ts + ',' + lineJs + ',this)">'
|
||||
+ vvEscHtml(label) + '</span>'
|
||||
+ '<span class="vv-err-age">' + vvFmtAge(now - e.ts) + '</span>'
|
||||
+ '<button class="vv-btn-sm vv-ack-btn" onclick="vvAckError(\'' + e.script.replace(/\\/g,"\\\\").replace(/'/g,"\\'") + "'," + e.ts + ',this)">Ack</button>'
|
||||
+ '</div>'
|
||||
|
||||
Reference in New Issue
Block a user