aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsilverwind <me@silverwind.io>2020-07-31 04:14:04 +0200
committerGitHub <noreply@github.com>2020-07-30 22:14:04 -0400
commit11dcc177637a234fd624db5d766746dea992bcd4 (patch)
tree457c6a6be21298c41c23761356a036d41d4f6767
parent24f86257900866ced5aa6b470d05f6d9f1a82de0 (diff)
downloadgitea-11dcc177637a234fd624db5d766746dea992bcd4.tar.gz
gitea-11dcc177637a234fd624db5d766746dea992bcd4.zip
Improve HTML escaping helper (#12383)
The previous method did not escape single quotes which under some circumstances can lead to XSS vulnerabilites and the fact that it depends on jQuery is also not ideal. Replace it with a lightweight module. Co-authored-by: techknowlogick <techknowlogick@gitea.io>
-rw-r--r--package-lock.json5
-rw-r--r--package.json1
-rw-r--r--web_src/js/index.js17
3 files changed, 13 insertions, 10 deletions
diff --git a/package-lock.json b/package-lock.json
index d145009323..415fb38016 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4372,6 +4372,11 @@
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz",
"integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ=="
},
+ "escape-goat": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz",
+ "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw=="
+ },
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
diff --git a/package.json b/package.json
index 3597ed6a5a..d2980e9303 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"css-loader": "4.0.0",
"cssnano-webpack-plugin": "1.0.3",
"dropzone": "5.7.2",
+ "escape-goat": "3.0.0",
"fast-glob": "3.2.4",
"file-loader": "6.0.0",
"fomantic-ui": "2.8.6",
diff --git a/web_src/js/index.js b/web_src/js/index.js
index 30a3d26ce4..32fb340dcb 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -4,6 +4,7 @@
import './publicpath.js';
import Vue from 'vue';
+import {htmlEscape} from 'escape-goat';
import 'jquery.are-you-sure';
import './vendor/semanticdropdown.js';
@@ -25,10 +26,6 @@ import {svg, svgs} from './svg.js';
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;
-function htmlEncode(text) {
- return jQuery('<div />').text(text).html();
-}
-
let previewFileModes;
const commentMDEditors = {};
@@ -528,12 +525,12 @@ function initCommentForm() {
switch (input_id) {
case '#milestone_id':
$list.find('.selected').html(`<a class="item" href=${$(this).data('href')}>${
- htmlEncode($(this).text())}</a>`);
+ htmlEscape($(this).text())}</a>`);
break;
case '#assignee_id':
$list.find('.selected').html(`<a class="item" href=${$(this).data('href')}>` +
`<img class="ui avatar image" src=${$(this).data('avatar')}>${
- htmlEncode($(this).text())}</a>`);
+ htmlEscape($(this).text())}</a>`);
}
$(`.ui${select_id}.list .no-select`).addClass('hide');
$(input_id).val($(this).data('id'));
@@ -1944,7 +1941,7 @@ function searchUsers() {
$.each(response.data, (_i, item) => {
let title = item.login;
if (item.full_name && item.full_name.length > 0) {
- title += ` (${htmlEncode(item.full_name)})`;
+ title += ` (${htmlEscape(item.full_name)})`;
}
items.push({
title,
@@ -2220,7 +2217,7 @@ function initTemplateSearch() {
// Parse the response from the api to work with our dropdown
$.each(response.data, (_r, repo) => {
filteredResponse.results.push({
- name: htmlEncode(repo.full_name),
+ name: htmlEscape(repo.full_name),
value: repo.id
});
});
@@ -3500,8 +3497,8 @@ function initIssueList() {
return;
}
filteredResponse.results.push({
- name: `#${issue.number} ${htmlEncode(issue.title)
- }<div class="text small dont-break-out">${htmlEncode(issue.repository.full_name)}</div>`,
+ name: `#${issue.number} ${htmlEscape(issue.title)
+ }<div class="text small dont-break-out">${htmlEscape(issue.repository.full_name)}</div>`,
value: issue.id
});
});