more general solution addressing #554, kudos @rugk for the suggestions
This commit is contained in:
parent
6a3a8a395a
commit
2caddf985f
14 changed files with 241 additions and 151 deletions
31
js/common.js
31
js/common.js
|
@ -36,21 +36,6 @@ var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
|
|||
supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'],
|
||||
mimeTypes = ['image/png', 'application/octet-stream'],
|
||||
formats = ['plaintext', 'markdown', 'syntaxhighlighting'],
|
||||
/**
|
||||
* character to HTML entity lookup table
|
||||
*
|
||||
* @see {@link https://github.com/janl/mustache.js/blob/master/mustache.js#L60}
|
||||
*/
|
||||
entityMap = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/',
|
||||
'`': '`',
|
||||
'=': '='
|
||||
},
|
||||
logFile = fs.createWriteStream('test.log'),
|
||||
mimeFile = fs.createReadStream('/etc/mime.types'),
|
||||
mimeLine = '';
|
||||
|
@ -97,22 +82,6 @@ function parseMime(line) {
|
|||
|
||||
// common testing helper functions
|
||||
|
||||
/**
|
||||
* convert all applicable characters to HTML entities
|
||||
*
|
||||
* @see {@link https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content}
|
||||
* @name htmlEntities
|
||||
* @function
|
||||
* @param {string} str
|
||||
* @return {string} escaped HTML
|
||||
*/
|
||||
exports.htmlEntities = function(str) {
|
||||
return String(str).replace(
|
||||
/[&<>"'`=\/]/g, function(s) {
|
||||
return entityMap[s];
|
||||
});
|
||||
};
|
||||
|
||||
// provides random lowercase characters from a to z
|
||||
exports.jscA2zString = function() {
|
||||
return jsc.elements(a2zString);
|
||||
|
|
|
@ -267,6 +267,32 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* encode all applicable characters to HTML entities
|
||||
*
|
||||
* @see {@link https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html}
|
||||
*
|
||||
* @name Helper.htmlEntities
|
||||
* @function
|
||||
* @param string str
|
||||
* @return string escaped HTML
|
||||
*/
|
||||
me.htmlEntities = function(str) {
|
||||
// using textarea, since other tags may allow and execute scripts, even when detached from DOM
|
||||
let holder = document.createElement('textarea');
|
||||
holder.textContent = str;
|
||||
// as per OWASP recommendation, also encoding quotes and slash
|
||||
return holder.innerHTML.replace(
|
||||
/["'\/]/g,
|
||||
function(s) {
|
||||
return {
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/'
|
||||
}[s];
|
||||
});
|
||||
};
|
||||
|
||||
return me;
|
||||
})();
|
||||
|
||||
|
@ -419,17 +445,31 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
|
|||
args[0] = translations[messageId];
|
||||
}
|
||||
|
||||
// messageID may contain links, but should be from a trusted source (code or translation JSON files)
|
||||
let containsNoLinks = args[0].indexOf('<a') === -1;
|
||||
for (let i = 0; i < args.length; ++i) {
|
||||
// parameters (i > 0) may never contain HTML as they may come from untrusted parties
|
||||
if (i > 0 || containsNoLinks) {
|
||||
args[i] = Helper.htmlEntities(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// format string
|
||||
var output = Helper.sprintf.apply(this, args);
|
||||
|
||||
// if $element is given, apply text to element
|
||||
if ($element !== null) {
|
||||
// get last text node of element
|
||||
var content = $element.contents();
|
||||
if (content.length > 1) {
|
||||
content[content.length - 1].nodeValue = ' ' + output;
|
||||
} else {
|
||||
if (containsNoLinks) {
|
||||
// avoid HTML entity encoding if translation contains links
|
||||
$element.text(output);
|
||||
} else {
|
||||
// only allow tags/attributes we actually use in our translations
|
||||
$element.html(
|
||||
DOMPurify.sanitize(output, {
|
||||
ALLOWED_TAGS: ['a', 'br', 'i', 'span'],
|
||||
ALLOWED_ATTR: ['href', 'id']
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1052,28 +1092,35 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
|
|||
icon = null; // icons not supported in this case
|
||||
}
|
||||
}
|
||||
var $translationTarget = $element;
|
||||
|
||||
// handle icon
|
||||
if (icon !== null && // icon was passed
|
||||
icon !== currentIcon[id] // and it differs from current icon
|
||||
) {
|
||||
var $glyphIcon = $element.find(':first');
|
||||
// handle icon, if template uses one
|
||||
var $glyphIcon = $element.find(':first');
|
||||
if ($glyphIcon.length) {
|
||||
// if there is an icon, we need to provide an inner element
|
||||
// to translate the message into, instead of the parent
|
||||
$translationTarget = $('<span>');
|
||||
$element.html(' ').prepend($glyphIcon).append($translationTarget);
|
||||
|
||||
// remove (previous) icon
|
||||
$glyphIcon.removeClass(currentIcon[id]);
|
||||
if (icon !== null && // icon was passed
|
||||
icon !== currentIcon[id] // and it differs from current icon
|
||||
) {
|
||||
// remove (previous) icon
|
||||
$glyphIcon.removeClass(currentIcon[id]);
|
||||
|
||||
// any other thing as a string (e.g. 'null') (only) removes the icon
|
||||
if (typeof icon === 'string') {
|
||||
// set new icon
|
||||
currentIcon[id] = 'glyphicon-' + icon;
|
||||
$glyphIcon.addClass(currentIcon[id]);
|
||||
// any other thing as a string (e.g. 'null') (only) removes the icon
|
||||
if (typeof icon === 'string') {
|
||||
// set new icon
|
||||
currentIcon[id] = 'glyphicon-' + icon;
|
||||
$glyphIcon.addClass(currentIcon[id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// show text
|
||||
if (args !== null) {
|
||||
// add jQuery object to it as first parameter
|
||||
args.unshift($element);
|
||||
args.unshift($translationTarget);
|
||||
// pass it to I18n
|
||||
I18n._.apply(this, args);
|
||||
}
|
||||
|
@ -1764,9 +1811,9 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
|
|||
|
||||
// escape HTML entities, link URLs, sanitize
|
||||
var escapedLinkedText = Helper.urls2links(
|
||||
$('<div />').text(text).html()
|
||||
),
|
||||
sanitizedLinkedText = DOMPurify.sanitize(escapedLinkedText);
|
||||
Helper.htmlEntities(text)
|
||||
),
|
||||
sanitizedLinkedText = DOMPurify.sanitize(escapedLinkedText);
|
||||
$plainText.html(sanitizedLinkedText);
|
||||
$prettyPrint.html(sanitizedLinkedText);
|
||||
|
||||
|
@ -2894,7 +2941,7 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
|
|||
for (var i = 0; i < $head.length; i++) {
|
||||
newDoc.write($head[i].outerHTML);
|
||||
}
|
||||
newDoc.write('</head><body><pre>' + DOMPurify.sanitize(paste) + '</pre></body></html>');
|
||||
newDoc.write('</head><body><pre>' + DOMPurify.sanitize(Helper.htmlEntities(paste)) + '</pre></body></html>');
|
||||
newDoc.close();
|
||||
}
|
||||
|
||||
|
|
156
js/test/Alert.js
156
js/test/Alert.js
|
@ -3,21 +3,56 @@ var common = require('../common');
|
|||
|
||||
describe('Alert', function () {
|
||||
describe('showStatus', function () {
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'shows a status message',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
function (icon, message) {
|
||||
icon = icon.join('');
|
||||
message = message.join('');
|
||||
var expected = '<div id="status">' + message + '</div>';
|
||||
$('body').html(
|
||||
'<div id="status"></div>'
|
||||
);
|
||||
$.PrivateBin.Alert.init();
|
||||
$.PrivateBin.Alert.showStatus(message, icon);
|
||||
var result = $('body').html();
|
||||
return expected === result;
|
||||
}
|
||||
);
|
||||
|
||||
jsc.property(
|
||||
'shows a status message (bootstrap)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
function (message) {
|
||||
message = message.join('');
|
||||
var expected = '<div id="status" role="alert" ' +
|
||||
'class="statusmessage alert alert-info"><span ' +
|
||||
'class="glyphicon glyphicon-info-sign" ' +
|
||||
'aria-hidden="true"></span> <span>' + message + '</span></div>';
|
||||
$('body').html(
|
||||
'<div id="status" role="alert" class="statusmessage ' +
|
||||
'alert alert-info hidden"><span class="glyphicon ' +
|
||||
'glyphicon-info-sign" aria-hidden="true"></span> </div>'
|
||||
);
|
||||
$.PrivateBin.Alert.init();
|
||||
$.PrivateBin.Alert.showStatus(message);
|
||||
var result = $('body').html();
|
||||
return expected === result;
|
||||
}
|
||||
);
|
||||
|
||||
jsc.property(
|
||||
'shows a status message (bootstrap, custom icon)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
function (icon, message) {
|
||||
icon = icon.join('');
|
||||
message = message.join('');
|
||||
var expected = '<div id="status" role="alert" ' +
|
||||
'class="statusmessage alert alert-info"><span ' +
|
||||
'class="glyphicon glyphicon-' + icon +
|
||||
'" aria-hidden="true"></span> ' + message + '</div>';
|
||||
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
|
||||
$('body').html(
|
||||
'<div id="status" role="alert" class="statusmessage ' +
|
||||
'alert alert-info hidden"><span class="glyphicon ' +
|
||||
|
@ -32,12 +67,48 @@ describe('Alert', function () {
|
|||
});
|
||||
|
||||
describe('showError', function () {
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
jsc.property(
|
||||
'shows an error message (basic)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
function (icon, message) {
|
||||
icon = icon.join('');
|
||||
message = message.join('');
|
||||
var expected = '<div id="errormessage">' + message + '</div>';
|
||||
$('body').html(
|
||||
'<div id="errormessage"></div>'
|
||||
);
|
||||
$.PrivateBin.Alert.init();
|
||||
$.PrivateBin.Alert.showError(message, icon);
|
||||
var result = $('body').html();
|
||||
return expected === result;
|
||||
}
|
||||
);
|
||||
|
||||
jsc.property(
|
||||
'shows an error message',
|
||||
'shows an error message (bootstrap)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
function (icon, message) {
|
||||
message = message.join('');
|
||||
var expected = '<div id="errormessage" role="alert" ' +
|
||||
'class="statusmessage alert alert-danger"><span ' +
|
||||
'class="glyphicon glyphicon-alert" ' +
|
||||
'aria-hidden="true"></span> <span>' + message + '</span></div>';
|
||||
$('body').html(
|
||||
'<div id="errormessage" role="alert" class="statusmessage ' +
|
||||
'alert alert-danger hidden"><span class="glyphicon ' +
|
||||
'glyphicon-alert" aria-hidden="true"></span> </div>'
|
||||
);
|
||||
$.PrivateBin.Alert.init();
|
||||
$.PrivateBin.Alert.showError(message);
|
||||
var result = $('body').html();
|
||||
return expected === result;
|
||||
}
|
||||
);
|
||||
|
||||
jsc.property(
|
||||
'shows an error message (bootstrap, custom icon)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
function (icon, message) {
|
||||
|
@ -46,7 +117,7 @@ describe('Alert', function () {
|
|||
var expected = '<div id="errormessage" role="alert" ' +
|
||||
'class="statusmessage alert alert-danger"><span ' +
|
||||
'class="glyphicon glyphicon-' + icon +
|
||||
'" aria-hidden="true"></span> ' + message + '</div>';
|
||||
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
|
||||
$('body').html(
|
||||
'<div id="errormessage" role="alert" class="statusmessage ' +
|
||||
'alert alert-danger hidden"><span class="glyphicon ' +
|
||||
|
@ -61,12 +132,27 @@ describe('Alert', function () {
|
|||
});
|
||||
|
||||
describe('showRemaining', function () {
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
jsc.property(
|
||||
'shows remaining time (basic)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
'integer',
|
||||
function (message, string, number) {
|
||||
message = message.join('');
|
||||
string = string.join('');
|
||||
var expected = '<div id="remainingtime" class="">' + string + message + number + '</div>';
|
||||
$('body').html(
|
||||
'<div id="remainingtime" class="hidden"></div>'
|
||||
);
|
||||
$.PrivateBin.Alert.init();
|
||||
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
|
||||
var result = $('body').html();
|
||||
return expected === result;
|
||||
}
|
||||
);
|
||||
|
||||
jsc.property(
|
||||
'shows remaining time',
|
||||
'shows remaining time (bootstrap)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
'integer',
|
||||
|
@ -76,7 +162,7 @@ describe('Alert', function () {
|
|||
var expected = '<div id="remainingtime" role="alert" ' +
|
||||
'class="alert alert-info"><span ' +
|
||||
'class="glyphicon glyphicon-fire" aria-hidden="true">' +
|
||||
'</span> ' + string + message + number + '</div>';
|
||||
'</span> <span>' + string + message + number + '</span></div>';
|
||||
$('body').html(
|
||||
'<div id="remainingtime" role="alert" class="hidden ' +
|
||||
'alert alert-info"><span class="glyphicon ' +
|
||||
|
@ -91,12 +177,30 @@ describe('Alert', function () {
|
|||
});
|
||||
|
||||
describe('showLoading', function () {
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
jsc.property(
|
||||
'shows a loading message (basic)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
function (message, icon) {
|
||||
message = message.join('');
|
||||
icon = icon.join('');
|
||||
var defaultMessage = 'Loading…';
|
||||
if (message.length === 0) {
|
||||
message = defaultMessage;
|
||||
}
|
||||
var expected = '<div id="loadingindicator" class="">' + message + '</div>';
|
||||
$('body').html(
|
||||
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>'
|
||||
);
|
||||
$.PrivateBin.Alert.init();
|
||||
$.PrivateBin.Alert.showLoading(message, icon);
|
||||
var result = $('body').html();
|
||||
return expected === result;
|
||||
}
|
||||
);
|
||||
|
||||
jsc.property(
|
||||
'shows a loading message',
|
||||
'shows a loading message (bootstrap)',
|
||||
jsc.array(common.jscAlnumString()),
|
||||
jsc.array(common.jscAlnumString()),
|
||||
function (message, icon) {
|
||||
|
@ -109,7 +213,7 @@ describe('Alert', function () {
|
|||
var expected = '<ul class="nav navbar-nav"><li ' +
|
||||
'id="loadingindicator" class="navbar-text"><span ' +
|
||||
'class="glyphicon glyphicon-' + icon +
|
||||
'" aria-hidden="true"></span> ' + message + '</li></ul>';
|
||||
'" aria-hidden="true"></span> <span>' + message + '</span></li></ul>';
|
||||
$('body').html(
|
||||
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
|
||||
'class="navbar-text hidden"><span class="glyphicon ' +
|
||||
|
@ -125,10 +229,6 @@ describe('Alert', function () {
|
|||
});
|
||||
|
||||
describe('hideLoading', function () {
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it(
|
||||
'hides the loading message',
|
||||
function() {
|
||||
|
@ -150,10 +250,6 @@ describe('Alert', function () {
|
|||
});
|
||||
|
||||
describe('hideMessages', function () {
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it(
|
||||
'hides all messages',
|
||||
function() {
|
||||
|
@ -176,10 +272,6 @@ describe('Alert', function () {
|
|||
});
|
||||
|
||||
describe('setCustomHandler', function () {
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'calls a given handler function',
|
||||
'nat 3',
|
||||
|
|
|
@ -4,9 +4,6 @@ var common = require('../common');
|
|||
describe('AttachmentViewer', function () {
|
||||
describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () {
|
||||
this.timeout(30000);
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'displays & hides data as requested',
|
||||
|
@ -24,7 +21,8 @@ describe('AttachmentViewer', function () {
|
|||
mimeType.substring(0, 6) === 'video/' ||
|
||||
mimeType.match(/\/pdf/i)
|
||||
),
|
||||
results = [];
|
||||
results = [],
|
||||
result = '';
|
||||
prefix = prefix.replace(/%(s|d)/g, '%%');
|
||||
postfix = postfix.replace(/%(s|d)/g, '%%');
|
||||
$('body').html(
|
||||
|
@ -72,13 +70,19 @@ describe('AttachmentViewer', function () {
|
|||
!$('#attachment').hasClass('hidden') &&
|
||||
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
|
||||
);
|
||||
var element = $('<div></div>');
|
||||
let element = $('<div>');
|
||||
$.PrivateBin.AttachmentViewer.moveAttachmentTo(element, prefix + '%s' + postfix);
|
||||
// messageIDs with links get a relaxed treatment
|
||||
if (prefix.indexOf('<a') === -1 && postfix.indexOf('<a') === -1) {
|
||||
result = $.PrivateBin.Helper.htmlEntities(prefix + filename + postfix);
|
||||
} else {
|
||||
result = $('<div>').html(prefix + $.PrivateBin.Helper.htmlEntities(filename) + postfix).html();
|
||||
}
|
||||
if (filename.length) {
|
||||
results.push(
|
||||
element.children()[0].href === data &&
|
||||
element.children()[0].getAttribute('download') === filename &&
|
||||
element.children()[0].text === prefix + filename + postfix
|
||||
element.children()[0].text === result
|
||||
);
|
||||
} else {
|
||||
results.push(element.children()[0].href === data);
|
||||
|
|
|
@ -4,9 +4,6 @@ var common = require('../common');
|
|||
describe('DiscussionViewer', function () {
|
||||
describe('handleNotification, prepareNewDiscussion, addComment, finishDiscussion, getReplyMessage, getReplyNickname, getReplyCommentId & highlightComment', function () {
|
||||
this.timeout(30000);
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'displays & hides comments as requested',
|
||||
|
|
|
@ -4,9 +4,6 @@ require('../common');
|
|||
describe('Editor', function () {
|
||||
describe('show, hide, getText, setText & isPreview', function () {
|
||||
this.timeout(30000);
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'returns text fed into the textarea, handles editor tabs',
|
||||
|
|
|
@ -3,10 +3,6 @@ var common = require('../common');
|
|||
|
||||
describe('Helper', function () {
|
||||
describe('secondsToHuman', function () {
|
||||
after(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property('returns an array with a number and a word', 'integer', function (number) {
|
||||
var result = $.PrivateBin.Helper.secondsToHuman(number);
|
||||
return Array.isArray(result) &&
|
||||
|
@ -57,11 +53,11 @@ describe('Helper', function () {
|
|||
'nearray string',
|
||||
function (ids, contents) {
|
||||
var html = '',
|
||||
result = true;
|
||||
result = true,
|
||||
clean = jsdom(html);
|
||||
ids.forEach(function(item, i) {
|
||||
html += '<div id="' + item.join('') + '">' + common.htmlEntities(contents[i] || contents[0]) + '</div>';
|
||||
html += '<div id="' + item.join('') + '">' + $.PrivateBin.Helper.htmlEntities(contents[i] || contents[0]) + '</div>';
|
||||
});
|
||||
var clean = jsdom(html);
|
||||
// TODO: As per https://github.com/tmpvar/jsdom/issues/321 there is no getSelection in jsdom, yet.
|
||||
// Once there is one, uncomment the block below to actually check the result.
|
||||
/*
|
||||
|
@ -77,8 +73,8 @@ describe('Helper', function () {
|
|||
});
|
||||
|
||||
describe('urls2links', function () {
|
||||
after(function () {
|
||||
cleanup();
|
||||
before(function () {
|
||||
cleanup = jsdom();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
|
@ -97,11 +93,11 @@ describe('Helper', function () {
|
|||
jsc.array(common.jscHashString()),
|
||||
'string',
|
||||
function (prefix, schema, address, query, fragment, postfix) {
|
||||
var query = query.join(''),
|
||||
var query = query.join(''),
|
||||
fragment = fragment.join(''),
|
||||
url = schema + '://' + address.join('') + '/?' + query + '#' + fragment,
|
||||
prefix = common.htmlEntities(prefix),
|
||||
postfix = ' ' + common.htmlEntities(postfix);
|
||||
url = schema + '://' + address.join('') + '/?' + query + '#' + fragment,
|
||||
prefix = $.PrivateBin.Helper.htmlEntities(prefix),
|
||||
postfix = ' ' + $.PrivateBin.Helper.htmlEntities(postfix);
|
||||
|
||||
// special cases: When the query string and fragment imply the beginning of an HTML entity, eg. � or &#x
|
||||
if (
|
||||
|
@ -122,19 +118,15 @@ describe('Helper', function () {
|
|||
jsc.array(common.jscQueryString()),
|
||||
'string',
|
||||
function (prefix, query, postfix) {
|
||||
var url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm,''),
|
||||
prefix = common.htmlEntities(prefix),
|
||||
postfix = common.htmlEntities(postfix);
|
||||
var url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm,''),
|
||||
prefix = $.PrivateBin.Helper.htmlEntities(prefix),
|
||||
postfix = $.PrivateBin.Helper.htmlEntities(postfix);
|
||||
return prefix + '<a href="' + url + '" rel="nofollow">' + url + '</a> ' + postfix === $.PrivateBin.Helper.urls2links(prefix + url + ' ' + postfix);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('sprintf', function () {
|
||||
after(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'replaces %s in strings with first given parameter',
|
||||
'string',
|
||||
|
@ -211,6 +203,10 @@ describe('Helper', function () {
|
|||
|
||||
describe('getCookie', function () {
|
||||
this.timeout(30000);
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'returns the requested cookie',
|
||||
'nearray asciinestring',
|
||||
|
@ -261,16 +257,16 @@ describe('Helper', function () {
|
|||
});
|
||||
|
||||
describe('htmlEntities', function () {
|
||||
after(function () {
|
||||
cleanup();
|
||||
before(function () {
|
||||
cleanup = jsdom();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'removes all HTML entities from any given string',
|
||||
'string',
|
||||
function (string) {
|
||||
var result = common.htmlEntities(string);
|
||||
return !(/[<>"'`=\/]/.test(result)) && !(string.indexOf('&') > -1 && !(/&/.test(result)));
|
||||
var result = $.PrivateBin.Helper.htmlEntities(string);
|
||||
return !(/[<>]/.test(result)) && !(string.indexOf('&') > -1 && !(/&/.test(result)));
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -32,6 +32,7 @@ describe('I18n', function () {
|
|||
var fakeAlias = $.PrivateBin.I18n._(fake);
|
||||
$.PrivateBin.I18n.reset();
|
||||
|
||||
messageId = $.PrivateBin.Helper.htmlEntities(messageId);
|
||||
return messageId === result && messageId === alias &&
|
||||
messageId === pluralResult && messageId === pluralAlias &&
|
||||
messageId === fakeResult && messageId === fakeAlias;
|
||||
|
@ -46,7 +47,7 @@ describe('I18n', function () {
|
|||
prefix = prefix.replace(/%(s|d)/g, '%%');
|
||||
params[0] = params[0].replace(/%(s|d)/g, '%%');
|
||||
postfix = postfix.replace(/%(s|d)/g, '%%');
|
||||
var translation = prefix + params[0] + postfix;
|
||||
var translation = $.PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
|
||||
params.unshift(prefix + '%s' + postfix);
|
||||
var result = $.PrivateBin.I18n.translate.apply(this, params);
|
||||
$.PrivateBin.I18n.reset();
|
||||
|
|
|
@ -5,18 +5,18 @@ describe('Model', function () {
|
|||
describe('getExpirationDefault', function () {
|
||||
before(function () {
|
||||
$.PrivateBin.Model.reset();
|
||||
cleanup();
|
||||
cleanup = jsdom();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'returns the contents of the element with id "pasteExpiration"',
|
||||
'array asciinestring',
|
||||
'nearray asciinestring',
|
||||
'string',
|
||||
'small nat',
|
||||
function (keys, value, key) {
|
||||
keys = keys.map(common.htmlEntities);
|
||||
value = common.htmlEntities(value);
|
||||
var content = keys.length > key ? keys[key] : (keys.length > 0 ? keys[0] : 'null'),
|
||||
keys = keys.map($.PrivateBin.Helper.htmlEntities);
|
||||
value = $.PrivateBin.Helper.htmlEntities(value);
|
||||
var content = keys.length > key ? keys[key] : keys[0],
|
||||
contents = '<select id="pasteExpiration" name="pasteExpiration">';
|
||||
keys.forEach(function(item) {
|
||||
contents += '<option value="' + item + '"';
|
||||
|
@ -27,7 +27,7 @@ describe('Model', function () {
|
|||
});
|
||||
contents += '</select>';
|
||||
$('body').html(contents);
|
||||
var result = common.htmlEntities(
|
||||
var result = $.PrivateBin.Helper.htmlEntities(
|
||||
$.PrivateBin.Model.getExpirationDefault()
|
||||
);
|
||||
$.PrivateBin.Model.reset();
|
||||
|
@ -39,18 +39,20 @@ describe('Model', function () {
|
|||
describe('getFormatDefault', function () {
|
||||
before(function () {
|
||||
$.PrivateBin.Model.reset();
|
||||
});
|
||||
after(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'returns the contents of the element with id "pasteFormatter"',
|
||||
'array asciinestring',
|
||||
'nearray asciinestring',
|
||||
'string',
|
||||
'small nat',
|
||||
function (keys, value, key) {
|
||||
keys = keys.map(common.htmlEntities);
|
||||
value = common.htmlEntities(value);
|
||||
var content = keys.length > key ? keys[key] : (keys.length > 0 ? keys[0] : 'null'),
|
||||
keys = keys.map($.PrivateBin.Helper.htmlEntities);
|
||||
value = $.PrivateBin.Helper.htmlEntities(value);
|
||||
var content = keys.length > key ? keys[key] : keys[0],
|
||||
contents = '<select id="pasteFormatter" name="pasteFormatter">';
|
||||
keys.forEach(function(item) {
|
||||
contents += '<option value="' + item + '"';
|
||||
|
@ -61,7 +63,7 @@ describe('Model', function () {
|
|||
});
|
||||
contents += '</select>';
|
||||
$('body').html(contents);
|
||||
var result = common.htmlEntities(
|
||||
var result = $.PrivateBin.Helper.htmlEntities(
|
||||
$.PrivateBin.Model.getFormatDefault()
|
||||
);
|
||||
$.PrivateBin.Model.reset();
|
||||
|
@ -74,7 +76,6 @@ describe('Model', function () {
|
|||
this.timeout(30000);
|
||||
before(function () {
|
||||
$.PrivateBin.Model.reset();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
|
@ -185,7 +186,6 @@ describe('Model', function () {
|
|||
describe('getTemplate', function () {
|
||||
before(function () {
|
||||
$.PrivateBin.Model.reset();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
|
|
|
@ -39,9 +39,6 @@ describe('PasteStatus', function () {
|
|||
|
||||
describe('showRemainingTime', function () {
|
||||
this.timeout(30000);
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'shows burn after reading message or remaining time',
|
||||
|
@ -84,10 +81,6 @@ describe('PasteStatus', function () {
|
|||
});
|
||||
|
||||
describe('hideMessages', function () {
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it(
|
||||
'hides all messages',
|
||||
function() {
|
||||
|
|
|
@ -4,9 +4,6 @@ var common = require('../common');
|
|||
describe('PasteViewer', function () {
|
||||
describe('run, hide, getText, setText, getFormat, setFormat & isPrettyPrinted', function () {
|
||||
this.timeout(30000);
|
||||
before(function () {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'displays text according to format',
|
||||
|
|
|
@ -6,10 +6,6 @@ describe('Prompt', function () {
|
|||
// in nodejs -> replace the prompt in the "page" template with a modal
|
||||
describe('requestPassword & getPassword', function () {
|
||||
this.timeout(30000);
|
||||
before(function () {
|
||||
$.PrivateBin.Model.reset();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
jsc.property(
|
||||
'returns the password fed into the dialog',
|
||||
|
@ -26,6 +22,7 @@ describe('Prompt', function () {
|
|||
'password"></div><button type="submit">Decrypt</button>' +
|
||||
'</form></div></div></div></div>'
|
||||
);
|
||||
$.PrivateBin.Model.reset();
|
||||
$.PrivateBin.Model.init();
|
||||
$.PrivateBin.Prompt.init();
|
||||
$.PrivateBin.Prompt.requestPassword();
|
||||
|
|
|
@ -75,7 +75,7 @@ if ($MARKDOWN):
|
|||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.7.js" integrity="sha512-XjNEK1xwh7SJ/7FouwV4VZcGW9cMySL3SwNpXgrURLBcXXQYtZdqhGoNdEwx9vwLvFjUGDQVNgpOrTsXlSTiQg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-5xT6WHyurvC0LFESbkycBMAjhsi0KL/Xhx2oU+d0bqiJPkWK6ZAZgZ7I02oQiXaLtFSLf7UqpBo5XEePlfhH7Q==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-XauVNDkk7v8lwDf2WmHWzloKuejJKJpfEvjBBf4bJV45VRP2SX6tg7ngNhmywIay8vNgoFhVBZZoe3y9tEio8Q==" crossorigin="anonymous"></script>
|
||||
<!--[if lt IE 10]>
|
||||
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
|
||||
<![endif]-->
|
||||
|
|
|
@ -53,7 +53,7 @@ if ($MARKDOWN):
|
|||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.7.js" integrity="sha512-XjNEK1xwh7SJ/7FouwV4VZcGW9cMySL3SwNpXgrURLBcXXQYtZdqhGoNdEwx9vwLvFjUGDQVNgpOrTsXlSTiQg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-5xT6WHyurvC0LFESbkycBMAjhsi0KL/Xhx2oU+d0bqiJPkWK6ZAZgZ7I02oQiXaLtFSLf7UqpBo5XEePlfhH7Q==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-XauVNDkk7v8lwDf2WmHWzloKuejJKJpfEvjBBf4bJV45VRP2SX6tg7ngNhmywIay8vNgoFhVBZZoe3y9tEio8Q==" crossorigin="anonymous"></script>
|
||||
<!--[if lt IE 10]>
|
||||
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
|
||||
<![endif]-->
|
||||
|
|
Loading…
Reference in a new issue