* do not allow urls and any html elements in task title (escape all); format the note in php (not js) using mttMarkup_v1

This commit is contained in:
Max Pozdeev 2020-10-21 23:47:32 +03:00
parent 8760404245
commit f035fa3464
5 changed files with 39 additions and 22 deletions

View file

@ -231,7 +231,7 @@ elseif(isset($_GET['editNote']))
$db->dq("UPDATE {$db->prefix}todolist SET note=?,d_edited=? WHERE id=$id", array($note, time()) );
$t = array();
$t['total'] = 1;
$t['list'][] = array('id'=>$id, 'note'=>nl2br(escapeTags($note)), 'noteText'=>(string)$note);
$t['list'][] = array('id'=>$id, 'note'=>mttMarkup_v1($note), 'noteText'=>(string)$note);
jsonExit($t);
}
elseif(isset($_GET['editTask']))
@ -544,7 +544,7 @@ function prepareTaskRow($r)
return array(
'id' => $r['id'],
'title' => escapeTags($r['title']),
'title' => htmlspecialchars( $r['title'] ),
'listId' => $r['list_id'],
'date' => htmlarray($dCreated),
'dateInt' => (int)$r['d_created'],
@ -556,7 +556,7 @@ function prepareTaskRow($r)
'dateCompletedInlineTitle' => htmlarray(sprintf($lang->get('taskdate_inline_completed'), $dCompleted)),
'compl' => (int)$r['compl'],
'prio' => $r['prio'],
'note' => nl2br(escapeTags($r['note'])),
'note' => mttMarkup_v1($r['note']),
'noteText' => (string)$r['note'],
'ow' => (int)$r['ow'],
'tags' => htmlarray($r['tags']),

View file

@ -226,8 +226,8 @@ li.task-completed .task-note-block .task-note { text-decoration:line-through; }
.invisible { visibility:hidden; }
.in500 { width:500px; color:#444444; }
.in100 { width:100px; color:#444444; }
.task-note span a { color:#777777; }
.task-note span a:hover { color:#af0000; }
.task-note a { color:#777777; }
.task-note a:hover { color:#af0000; }
.task-prio { padding-left:2px; padding-right:2px; margin-left:0px; margin-right:5px; cursor:default; }
.prio-neg { background-color:#3377ff; color:#ffffff; }

View file

@ -58,9 +58,9 @@ while($r = $q->fetch_assoc($q))
}
if($r['tags'] != '') $a[] = $lang->get('tags'). ": ". str_replace(',', ', ', $r['tags']);
if($r['compl']) $a[] = $lang->get('taskdate_completed'). ": ". timestampToDatetime($r['d_completed']);
$r['title'] = strip_tags($r['title']);
$r['note'] = escapeTags($r['note']);
$r['_descr'] = nl2br($r['note']). ($a && $r['note']!='' ? "<br/><br/>" : ""). implode("<br/>", htmlarray($a));
$r['title'] = htmlspecialchars( $r['title'] );
$r['note'] = mttMarkup_v1($r['note']);
$r['_descr'] = $r['note']. ($a && $r['note']!='' ? "<br/><br/>" : ""). implode("<br/>", htmlarray($a));
$data[] = $r;
}
@ -81,7 +81,7 @@ function printRss($listData, $data)
$d = gmdate('r', $v[$listData['_uid_field']]);
$guid = $listData['id'].'-'.$v['id'].'-'.$v[$listData['_uid_field']];
$s .= "<item>\n<title><![CDATA[". str_replace("]]>", "]]]]><![CDATA[>", $v['title']). "]]></title>\n".
$s .= "<item>\n<title>${v['title']}</title>\n".
"<link>$link</link>\n".
"<pubDate>$d</pubDate>\n".
"<description><![CDATA[". $v['_descr']. "]]></description>\n".

View file

@ -212,15 +212,26 @@ function url_dir($url, $onlyPath = 1)
return '/';
}
function escapeTags($s)
// Convert note's raw text to html with allowed elements (b,i,u,s and raw urls)
function mttMarkup_v1($s)
{
//hide allowed elements from escaping
$c1 = chr(1);
$c2 = chr(2);
$s = preg_replace("~<b>([\s\S]*?)</b>~i", "${c1}b${c2}\$1${c1}/b${c2}", $s);
$s = preg_replace("~<i>([\s\S]*?)</i>~i", "${c1}i${c2}\$1${c1}/i${c2}", $s);
$s = preg_replace("~<u>([\s\S]*?)</u>~i", "${c1}u${c2}\$1${c1}/u${c2}", $s);
$s = preg_replace("~<s>([\s\S]*?)</s>~i", "${c1}s${c2}\$1${c1}/s${c2}", $s);
$s = str_replace(array($c1, $c2), array('<','>'), htmlspecialchars($s));
$s = htmlspecialchars($s); //escape all elements, except above
$s = str_replace( [$c1, $c2], ['<','>'], $s ); //unhide
$s = nl2br($s);
// make links from text starting with 'www.'
$s = preg_replace( "/(^|\s|>)(www\.([\w\#$%&~\/.\-\+;:=,\?\[\]@]+?))(,|\.|:|)?(?=\s|&quot;|&lt;|&gt;|\"|<|>|$)/i" , '$1<a href="http://$2" target="_blank">$2</a>$4' , $s );
// make link from text starting with protocol like 'http://'
$s = preg_replace( "/(^|\s|>)([a-z]+:\/\/([\w\#$%&~\/.\-\+;:=,\?\[\]@]+?))(,|\.|:|)?(?=\s|&quot;|&lt;|&gt;|\"|<|>|$)/i" , '$1<a href="$2" target="_blank">$2</a>$4' , $s);
return $s;
}

View file

@ -956,7 +956,7 @@ function loadTasks(opts)
function prepareTaskStr(item, noteExp)
{
return '<li id="taskrow_'+item.id+'" class="task-row ' + (item.compl?'task-completed ':'') + item.dueClass + (item.note!=''?' task-has-note':'') +
((curList.showNotes && item.note != '') || noteExp ? ' task-expanded' : '') + prepareTagsClass(item.tags_ids) + '"><div class="task-container">' +
((curList.showNotes && item.note != '') || noteExp ? ' task-expanded' : '') + prepareDomClassOfTags(item.tags_ids) + '"><div class="task-container">' +
prepareTaskBlocks(item) + "</div></li>\n";
};
_mtt.prepareTaskStr = prepareTaskStr;
@ -975,7 +975,7 @@ function prepareTaskBlocks(item)
'<div class="task-middle-top">' +
'<div class="task-through">' +
preparePrio(item.prio,id) +
'<span class="task-title">' + prepareHtml(item.title) + '</span> ' +
'<span class="task-title">' + prepareTaskTitleInlineHtml(item.title) + '</span> ' +
(curList.id == -1 ? '<span class="task-listname">'+ tabLists.get(item.listId).name +'</span>' : '') +
prepareTagsStr(item) +
'<span class="task-date">'+item.dateInlineTitle+'</span>' +
@ -984,7 +984,7 @@ function prepareTaskBlocks(item)
'</div>' +
'<div class="task-note-block">' +
'<div id="tasknote'+id+'" class="task-note"><span>'+prepareHtml(item.note)+'</span></div>' +
'<div id="tasknote' + id + '" class="task-note">' + prepareTaskNoteInlineHtml(item.note) + '</div>' +
'<div id="tasknotearea'+id+'" class="task-note-area"><textarea id="notetext'+id+'"></textarea>'+
'<span class="task-note-actions"><a href="#" class="mtt-action-note-save">'+_mtt.lang.get('actionNoteSave') +
'</a> | <a href="#" class="mtt-action-note-cancel">'+_mtt.lang.get('actionNoteCancel')+'</a></span>' +
@ -996,13 +996,19 @@ function prepareTaskBlocks(item)
};
_mtt.prepareTaskBlocks = prepareTaskBlocks;
function prepareHtml(s)
function prepareTaskTitleInlineHtml(s)
{
// make URLs clickable
s = s.replace(/(^|\s|>)(www\.([\w\#$%&~\/.\-\+;:=,\?\[\]@]+?))(,|\.|:|)?(?=\s|&quot;|&lt;|&gt;|\"|<|>|$)/gi, '$1<a href="http://$2" target="_blank">$2</a>$4');
return s.replace(/(^|\s|>)((?:http|https|ftp):\/\/([\w\#$%&~\/.\-\+;:=,\?\[\]@]+?))(,|\.|:|)?(?=\s|&quot;|&lt;|&gt;|\"|<|>|$)/ig, '$1<a href="$2" target="_blank">$2</a>$4');
// Task title is already escaped on php back-end
return s;
}
_mtt.prepareTaskTitleInlineHtml = prepareTaskTitleInlineHtml;
function prepareTaskNoteInlineHtml(s)
{
// Task note is already escaped on php back-end
return s;
};
_mtt.prepareHtml = prepareHtml;
_mtt.prepareTaskNoteInlineHtml = prepareTaskNoteInlineHtml;
function preparePrio(prio,id)
{
@ -1027,7 +1033,7 @@ function prepareTagsStr(item)
};
_mtt.prepareTagsStr = prepareTagsStr;
function prepareTagsClass(ids)
function prepareDomClassOfTags(ids)
{
if(!ids || ids == '') return '';
var a = ids.split(',');
@ -1037,7 +1043,7 @@ function prepareTagsClass(ids)
}
return ' '+a.join(' ');
};
_mtt.prepareTagsClass = prepareTagsClass;
_mtt.prepareDomClassOfTags = prepareDomClassOfTags;
function prepareDueDate(item)
{
@ -1456,7 +1462,7 @@ function saveTaskNote(id)
var item = json.list[0];
taskList[id].note = item.note;
taskList[id].noteText = item.noteText;
$('#tasknote'+id+'>span').html(prepareHtml(item.note));
$('#tasknote'+id).html(prepareTaskNoteInlineHtml(item.note));
if(item.note == '') $('#taskrow_'+id).removeClass('task-has-note task-expanded');
else $('#taskrow_'+id).addClass('task-has-note task-expanded');
cancelTaskNote(id);