WebClient: improve HTML escaping
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
4a34ae6662
commit
cbef217cfa
5 changed files with 65 additions and 32 deletions
|
@ -265,8 +265,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
<script src="{{.StaticURL}}/js/sb-admin-2.min.js"></script>
|
<script src="{{.StaticURL}}/js/sb-admin-2.min.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
function escapeHTML(str) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.appendChild(document.createTextNode(str));
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unescapeHTML(escapedStr) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.innerHTML = escapedStr;
|
||||||
|
var child = div.childNodes[0];
|
||||||
|
return child ? child.nodeValue : '';
|
||||||
|
}
|
||||||
|
|
||||||
function fixedEncodeURIComponent(str) {
|
function fixedEncodeURIComponent(str) {
|
||||||
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
return encodeURIComponent(unescapeHTML(str)).replace(/[!'()*]/g, function (c) {
|
||||||
return '%' + c.charCodeAt(0).toString(16);
|
return '%' + c.charCodeAt(0).toString(16);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,8 +219,30 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
<script src="{{.StaticURL}}/js/sb-admin-2.min.js"></script>
|
<script src="{{.StaticURL}}/js/sb-admin-2.min.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
function escapeHTML(str) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.appendChild(document.createTextNode(str));
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unescapeHTML(escapedStr) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.innerHTML = escapedStr;
|
||||||
|
var child = div.childNodes[0];
|
||||||
|
return child ? child.nodeValue : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHTMLForceSafe(str) {
|
||||||
|
return str
|
||||||
|
.replace(/&/g, '_')
|
||||||
|
.replace(/</g, '_')
|
||||||
|
.replace(/>/g, '_')
|
||||||
|
.replace(/\"/g, '_')
|
||||||
|
.replace(/\'/g, '_');
|
||||||
|
}
|
||||||
|
|
||||||
function fixedEncodeURIComponent(str) {
|
function fixedEncodeURIComponent(str) {
|
||||||
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
return encodeURIComponent(unescapeHTML(str)).replace(/[!'()*]/g, function (c) {
|
||||||
return '%' + c.charCodeAt(0).toString(16);
|
return '%' + c.charCodeAt(0).toString(16);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -229,13 +251,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
return str.replace(/\//g,'\u2215');
|
return str.replace(/\//g,'\u2215');
|
||||||
}
|
}
|
||||||
|
|
||||||
var escapeHTML = function ( t ) {
|
function b64EncodeUnicode(str) {
|
||||||
return t
|
return btoa(encodeURIComponent(str));
|
||||||
.replace( /&/g, '&' )
|
}
|
||||||
.replace( /</g, '<' )
|
|
||||||
.replace( />/g, '>' )
|
function UnicodeDecodeB64(str) {
|
||||||
.replace( /"/g, '"' );
|
return decodeURIComponent(atob(str));
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Page level plugins -->
|
<!-- Page level plugins -->
|
||||||
|
|
|
@ -239,7 +239,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
if (childReference == null || childReference.closed) {
|
if (childReference == null || childReference.closed) {
|
||||||
childProps.set('link', fileLink);
|
childProps.set('link', fileLink);
|
||||||
childProps.set('url', url);
|
childProps.set('url', url);
|
||||||
childProps.set('file_name', fileName);
|
childProps.set('file_name', UnicodeDecodeB64(fileName));
|
||||||
childReference = window.open(url, '_blank');
|
childReference = window.open(url, '_blank');
|
||||||
if (!checkerStarted){
|
if (!checkerStarted){
|
||||||
keepAlive();
|
keepAlive();
|
||||||
|
@ -366,7 +366,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
async function saveBlob() {
|
async function saveBlob() {
|
||||||
var errorMessage = "Error saving external file";
|
var errorMessage = "Error saving external file";
|
||||||
var uploadPath = '{{.FileURL}}?path={{.CurrentDir}}'+encodeURIComponent("/"+childProps.get('file_name'));
|
var uploadPath = '{{.FileURL}}?path={{.CurrentDir}}'+encodeURIComponent("/"+unescapeHTML(childProps.get('file_name')));
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await fetch(uploadPath, {
|
response = await fetch(uploadPath, {
|
||||||
|
@ -447,7 +447,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
}
|
}
|
||||||
|
|
||||||
function openVideoPlayer(name, url, videoType){
|
function openVideoPlayer(name, url, videoType){
|
||||||
$("#video_title").text(name);
|
$("#video_title").text(UnicodeDecodeB64(name));
|
||||||
$('#videoModal').modal('show');
|
$('#videoModal').modal('show');
|
||||||
player.src({
|
player.src({
|
||||||
type: videoType,
|
type: videoType,
|
||||||
|
@ -995,8 +995,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
var title = "";
|
var title = "";
|
||||||
var cssClass = "";
|
var cssClass = "";
|
||||||
var shortened = shortenData(data, 70);
|
var shortened = shortenData(data, 70);
|
||||||
|
data = escapeHTML(data);
|
||||||
if (shortened != data){
|
if (shortened != data){
|
||||||
title = escapeHTML(data);
|
title = data;
|
||||||
cssClass = "ellipsis";
|
cssClass = "ellipsis";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,7 +1018,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
{ "data": "edit_url",
|
{ "data": "edit_url",
|
||||||
"render": function (data, type, row) {
|
"render": function (data, type, row) {
|
||||||
if (type === 'display') {
|
if (type === 'display') {
|
||||||
var filename = row["name"];
|
var filename = escapeHTML(row["name"]);
|
||||||
var extension = filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
|
var extension = filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
|
||||||
if (data){
|
if (data){
|
||||||
if (extension == "csv" || extension == "bat" || CodeMirror.findModeByExtension(extension) != null){
|
if (extension == "csv" || extension == "bat" || CodeMirror.findModeByExtension(extension) != null){
|
||||||
|
@ -1039,15 +1040,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
case "svg":
|
case "svg":
|
||||||
case "ico":
|
case "ico":
|
||||||
var view_url = row['url']+"&inline=1";
|
var view_url = row['url']+"&inline=1";
|
||||||
return `<a href="${view_url}" data-lightbox="image-gallery" data-title="${filename}"><i class="fas fa-eye"></i></a>`;
|
var title = escapeHTMLForceSafe(row["name"])
|
||||||
|
return `<a href="${view_url}" data-lightbox="image-gallery" data-title="${title}"><i class="fas fa-eye"></i></a>`;
|
||||||
case "mp4":
|
case "mp4":
|
||||||
case "mov":
|
case "mov":
|
||||||
return `<a href="#" onclick="openVideoPlayer('${row["name"]}', '${row['url']}', 'video/mp4');"><i class="fas fa-eye"></i></a>`;
|
var name = b64EncodeUnicode(row["name"]);
|
||||||
|
return `<a href="#" onclick="openVideoPlayer('${name}', '${row['url']}', 'video/mp4');"><i class="fas fa-eye"></i></a>`;
|
||||||
case "webm":
|
case "webm":
|
||||||
return `<a href="#" onclick="openVideoPlayer('${row["name"]}', '${row['url']}', 'video/webm');"><i class="fas fa-eye"></i></a>`;
|
var name = b64EncodeUnicode(row["name"]);
|
||||||
|
return `<a href="#" onclick="openVideoPlayer('${name}', '${row['url']}', 'video/webm');"><i class="fas fa-eye"></i></a>`;
|
||||||
case "ogv":
|
case "ogv":
|
||||||
case "ogg":
|
case "ogg":
|
||||||
return `<a href="#" onclick="openVideoPlayer('${row["name"]}', '${row['url']}', 'video/ogg');"><i class="fas fa-eye"></i></a>`;
|
var name = b64EncodeUnicode(row["name"]);
|
||||||
|
return `<a href="#" onclick="openVideoPlayer('${name}}', '${row['url']}', 'video/ogg');"><i class="fas fa-eye"></i></a>`;
|
||||||
case "pdf":
|
case "pdf":
|
||||||
if (PDFObject.supportsPDFs){
|
if (PDFObject.supportsPDFs){
|
||||||
var view_url = row['url'];
|
var view_url = row['url'];
|
||||||
|
@ -1065,7 +1070,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
{{if .HasIntegrations}}
|
{{if .HasIntegrations}}
|
||||||
if (type === 'display') {
|
if (type === 'display') {
|
||||||
if (data){
|
if (data){
|
||||||
return `<a href="#" onclick="openExternalURL('${data}', '${row["ext_link"]}', '${row["name"]}');"><i class="fas fa-external-link-alt"></i></a>`;
|
var name = b64EncodeUnicode(escapeHTML(row["name"]));
|
||||||
|
return `<a href="#" onclick="openExternalURL('${data}', '${row["ext_link"]}', '${name}');"><i class="fas fa-external-link-alt"></i></a>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -94,26 +94,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
|
<script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||||
<script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
<script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
var escapeHTML = function ( t ) {
|
|
||||||
return t
|
|
||||||
.replace( /&/g, '&' )
|
|
||||||
.replace( /</g, '<' )
|
|
||||||
.replace( />/g, '>' )
|
|
||||||
.replace( /"/g, '"' );
|
|
||||||
};
|
|
||||||
|
|
||||||
function shortenData(d, cutoff) {
|
function shortenData(d, cutoff) {
|
||||||
if ( typeof d !== 'string' ) {
|
if ( typeof d !== 'string' ) {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( d.length <= cutoff ) {
|
if ( d.length <= cutoff ) {
|
||||||
return d;
|
return escapeHTML(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
var shortened = d.substr(0, cutoff-1);
|
var shortened = d.substr(0, cutoff-1);
|
||||||
return shortened+'…';
|
return escapeHTML(shortened)+'…';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIconForFile(filename) {
|
function getIconForFile(filename) {
|
||||||
|
@ -250,7 +241,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
var f = files[index];
|
var f = files[index];
|
||||||
var uploadPath = '{{.UploadBaseURL}}'+fixedEncodeURIComponent("/"+f.name);
|
var uploadPath = '{{.UploadBaseURL}}'+fixedEncodeURIComponent("/"+escapeHTML(f.name));
|
||||||
var lastModified;
|
var lastModified;
|
||||||
try {
|
try {
|
||||||
lastModified = f.lastModified;
|
lastModified = f.lastModified;
|
||||||
|
@ -384,6 +375,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
var title = "";
|
var title = "";
|
||||||
var cssClass = "";
|
var cssClass = "";
|
||||||
var shortened = shortenData(data, 70);
|
var shortened = shortenData(data, 70);
|
||||||
|
data = escapeHTML(data);
|
||||||
if (shortened != data){
|
if (shortened != data){
|
||||||
title = escapeHTML(data);
|
title = escapeHTML(data);
|
||||||
cssClass = "ellipsis";
|
cssClass = "ellipsis";
|
||||||
|
|
|
@ -99,7 +99,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
var f = files[index];
|
var f = files[index];
|
||||||
var uploadPath = '{{.UploadBasePath}}/'+fixedEncodeURIComponent(f.name);
|
var uploadPath = '{{.UploadBasePath}}/'+fixedEncodeURIComponent(escapeHTML(f.name));
|
||||||
var lastModified;
|
var lastModified;
|
||||||
try {
|
try {
|
||||||
lastModified = f.lastModified;
|
lastModified = f.lastModified;
|
||||||
|
|
Loading…
Reference in a new issue