Commit 6b381082 authored by Yifan Luo's avatar Yifan Luo Committed by Commit Bot

[Sanitizer API] Add Document and DocumentFragment as inputs on all methods

Add Document and DocumentFragment as inputs on both sanitize and
sanitizeToString methods.

Bug: 1116418
Change-Id: I06cd10dde9a5ca637140f7c4a71a302faa77abc2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2487085Reviewed-by: default avatarDaniel Vogelheim <vogelheim@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Commit-Queue: Yifan Luo <lyf@chromium.org>
Cr-Commit-Position: refs/heads/master@{#822147}
parent 28032a02
...@@ -97,6 +97,8 @@ bindings_modules_generated_union_type_files = [ ...@@ -97,6 +97,8 @@ bindings_modules_generated_union_type_files = [
"$bindings_modules_v8_output_dir/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.h", "$bindings_modules_v8_output_dir/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.h",
"$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.cc", "$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.cc",
"$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.h", "$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.h",
"$bindings_modules_v8_output_dir/string_or_document_fragment_or_document.cc",
"$bindings_modules_v8_output_dir/string_or_document_fragment_or_document.h",
"$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.cc", "$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.cc",
"$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.h", "$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.h",
"$bindings_modules_v8_output_dir/string_or_unsigned_long.cc", "$bindings_modules_v8_output_dir/string_or_unsigned_long.cc",
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
#include "sanitizer.h" #include "sanitizer.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_node_filter.h" #include "third_party/blink/renderer/bindings/core/v8/v8_node_filter.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_document_fragment_or_document.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_sanitizer_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_sanitizer_config.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_fragment.h" #include "third_party/blink/renderer/core/dom/document_fragment.h"
#include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node.h" #include "third_party/blink/renderer/core/dom/node.h"
...@@ -84,25 +86,35 @@ void Sanitizer::AttrFormatter( ...@@ -84,25 +86,35 @@ void Sanitizer::AttrFormatter(
Sanitizer::~Sanitizer() = default; Sanitizer::~Sanitizer() = default;
String Sanitizer::sanitizeToString(ScriptState* script_state, String Sanitizer::sanitizeToString(ScriptState* script_state,
const String& input, StringOrDocumentFragmentOrDocument& input,
ExceptionState& exception_state) { ExceptionState& exception_state) {
return CreateMarkup(sanitize(script_state, input, exception_state), return CreateMarkup(sanitize(script_state, input, exception_state),
kChildrenOnly); kChildrenOnly);
} }
DocumentFragment* Sanitizer::sanitize(ScriptState* script_state, DocumentFragment* Sanitizer::sanitize(ScriptState* script_state,
const String& input, StringOrDocumentFragmentOrDocument& input,
ExceptionState& exception_state) { ExceptionState& exception_state) {
DocumentFragment* fragment = nullptr;
LocalDOMWindow* window = LocalDOMWindow::From(script_state); LocalDOMWindow* window = LocalDOMWindow::From(script_state);
if (!window) { if (input.IsDocumentFragment()) {
fragment = input.GetAsDocumentFragment();
} else if (window) {
Document* document = window->document();
if (input.IsString() || input.IsNull()) {
fragment = document->createDocumentFragment();
DCHECK(document->QuerySelector("body"));
fragment->ParseHTML(input.GetAsString(), document->QuerySelector("body"));
} else {
fragment = document->createDocumentFragment();
fragment->appendChild(input.GetAsDocument()->documentElement());
}
} else {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Cannot find current DOM window."); "Cannot find current DOM window.");
return nullptr; return nullptr;
} }
Document* document = window->document();
DocumentFragment* fragment = document->createDocumentFragment();
DCHECK(document->QuerySelector("body"));
fragment->ParseHTML(input, document->QuerySelector("body"));
Node* node = fragment->firstChild(); Node* node = fragment->firstChild();
...@@ -155,6 +167,8 @@ DocumentFragment* Sanitizer::sanitize(ScriptState* script_state, ...@@ -155,6 +167,8 @@ DocumentFragment* Sanitizer::sanitize(ScriptState* script_state,
} }
} else { } else {
for (const auto& name : element->getAttributeNames()) { for (const auto& name : element->getAttributeNames()) {
// Attributes in drop list or not in allow list while allow list
// exists will be dropped.
bool drop = (drop_attributes_.Contains(name) && bool drop = (drop_attributes_.Contains(name) &&
(drop_attributes_.at(name).Contains("*") || (drop_attributes_.at(name).Contains("*") ||
drop_attributes_.at(name).Contains(node_name))) || drop_attributes_.at(name).Contains(node_name))) ||
......
...@@ -11,10 +11,12 @@ ...@@ -11,10 +11,12 @@
namespace blink { namespace blink {
class Document;
class DocumentFragment; class DocumentFragment;
class ExceptionState; class ExceptionState;
class SanitizerConfig; class SanitizerConfig;
class ScriptState; class ScriptState;
class StringOrDocumentFragmentOrDocument;
class MODULES_EXPORT Sanitizer final : public ScriptWrappable { class MODULES_EXPORT Sanitizer final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
...@@ -24,8 +26,12 @@ class MODULES_EXPORT Sanitizer final : public ScriptWrappable { ...@@ -24,8 +26,12 @@ class MODULES_EXPORT Sanitizer final : public ScriptWrappable {
explicit Sanitizer(const SanitizerConfig*); explicit Sanitizer(const SanitizerConfig*);
~Sanitizer() override; ~Sanitizer() override;
String sanitizeToString(ScriptState*, const String&, ExceptionState&); String sanitizeToString(ScriptState*,
DocumentFragment* sanitize(ScriptState*, const String&, ExceptionState&); StringOrDocumentFragmentOrDocument&,
ExceptionState&);
DocumentFragment* sanitize(ScriptState*,
StringOrDocumentFragmentOrDocument&,
ExceptionState&);
void Trace(Visitor*) const override; void Trace(Visitor*) const override;
......
...@@ -4,11 +4,13 @@ ...@@ -4,11 +4,13 @@
// https://github.com/WICG/sanitizer-api // https://github.com/WICG/sanitizer-api
typedef (DOMString or DocumentFragment or Document) SanitizerInput;
[ [
Exposed=Window, Exposed=Window,
RuntimeEnabled=SanitizerAPI RuntimeEnabled=SanitizerAPI
] interface Sanitizer { ] interface Sanitizer {
[RaisesException] constructor(optional SanitizerConfig config = {}); [RaisesException] constructor(optional SanitizerConfig config = {});
[CallWith=ScriptState, RaisesException] DOMString sanitizeToString(DOMString input); [CallWith=ScriptState, RaisesException] DOMString sanitizeToString(SanitizerInput input);
[CallWith=ScriptState, RaisesException] DocumentFragment sanitize(DOMString input); [CallWith=ScriptState, RaisesException] DocumentFragment sanitize(SanitizerInput input);
}; };
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
Exposed=Window Exposed=Window
] interface Sanitizer { ] interface Sanitizer {
constructor(optional SanitizerConfig sanitizerConfig = {}); constructor(optional SanitizerConfig sanitizerConfig = {});
DocumentFragment sanitize(DOMString input); DocumentFragment sanitize((DOMString or DocumentFragment or Document) input);
DOMString sanitizeToString(DOMString input); DOMString sanitizeToString((DOMString or DocumentFragment or Document) input);
}; };
dictionary SanitizerConfig { dictionary SanitizerConfig {
...@@ -13,6 +13,5 @@ dictionary SanitizerConfig { ...@@ -13,6 +13,5 @@ dictionary SanitizerConfig {
sequence<DOMString> blockElements; sequence<DOMString> blockElements;
sequence<DOMString> dropElements; sequence<DOMString> dropElements;
sequence<DOMString> allowAttributes; sequence<DOMString> allowAttributes;
sequence<DOMString> blockAttributes;
sequence<DOMString> dropAttributes; sequence<DOMString> dropAttributes;
}; };
This is a testharness.js-based test. This is a testharness.js-based test.
Found 104 tests; 101 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS SanitizerAPI sanitize function without argument should throw an error. PASS SanitizerAPI sanitize function without argument should throw an error.
PASS SanitizerAPI with config: string, sanitize function for string PASS SanitizerAPI sanitize function for null.
PASS SanitizerAPI with config: html fragment, sanitize function for html fragment PASS SanitizerAPI with config: string, sanitize from string function for string
PASS SanitizerAPI with config: broken html, sanitize function for broken html PASS SanitizerAPI with config: html fragment, sanitize from string function for html fragment
PASS SanitizerAPI with config: empty object, sanitize function for empty object PASS SanitizerAPI with config: broken html, sanitize from string function for broken html
PASS SanitizerAPI with config: number, sanitize function for number PASS SanitizerAPI with config: empty object, sanitize from string function for empty object
PASS SanitizerAPI with config: zeros, sanitize function for zeros PASS SanitizerAPI with config: number, sanitize from string function for number
PASS SanitizerAPI with config: arithmetic, sanitize function for arithmetic PASS SanitizerAPI with config: zeros, sanitize from string function for zeros
PASS SanitizerAPI with config: empty string, sanitize function for empty string PASS SanitizerAPI with config: arithmetic, sanitize from string function for arithmetic
PASS SanitizerAPI with config: undefined, sanitize function for undefined PASS SanitizerAPI with config: empty string, sanitize from string function for empty string
PASS SanitizerAPI with config: null, sanitize function for null PASS SanitizerAPI with config: undefined, sanitize from string function for undefined
PASS SanitizerAPI with config: document, sanitize function for document PASS SanitizerAPI with config: document, sanitize from string function for document
PASS SanitizerAPI with config: html without close tag, sanitize function for html without close tag PASS SanitizerAPI with config: html without close tag, sanitize from string function for html without close tag
PASS SanitizerAPI with config: scripts for default configs, sanitize function for scripts for default configs PASS SanitizerAPI with config: scripts for default configs, sanitize from string function for scripts for default configs
PASS SanitizerAPI with config: onclick scripts, sanitize function for onclick scripts PASS SanitizerAPI with config: onclick scripts, sanitize from string function for onclick scripts
PASS SanitizerAPI with config: invalid config_input, sanitize function for invalid config_input PASS SanitizerAPI with config: invalid config_input, sanitize from string function for invalid config_input
PASS SanitizerAPI with config: empty dropElements list, sanitize function for empty dropElements list PASS SanitizerAPI with config: empty dropElements list, sanitize from string function for empty dropElements list
PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitize function for test html without close tag with dropElements list ['div'] PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitize from string function for test html without close tag with dropElements list ['div']
PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitize function for test script with ["script"] as dropElements list PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitize from string function for test script with ["script"] as dropElements list
PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitize function for dropElements list ["test", "i"]} PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitize from string function for dropElements list ["test", "i"]}
PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitize function for dropElements list ["I", "AM"]} PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitize from string function for dropElements list ["I", "AM"]}
PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitize function for dropElements list ["am", "p"]} PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitize from string function for dropElements list ["am", "p"]}
PASS SanitizerAPI with config: dropElements list with invalid values}, sanitize function for dropElements list with invalid values} PASS SanitizerAPI with config: dropElements list with invalid values}, sanitize from string function for dropElements list with invalid values}
PASS SanitizerAPI with config: blockElements list with invalid values}, sanitize function for blockElements list with invalid values} PASS SanitizerAPI with config: blockElements list with invalid values}, sanitize from string function for blockElements list with invalid values}
PASS SanitizerAPI with config: allowElements list ["p"]., sanitize function for allowElements list ["p"]. PASS SanitizerAPI with config: allowElements list ["p"]., sanitize from string function for allowElements list ["p"].
PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitize function for allowElements list has no influence to dropElements. PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitize from string function for allowElements list has no influence to dropElements.
PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitize function for dropAttributes list {"style": ["p"]} with style attribute PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitize from string function for dropAttributes list {"style": ["p"]} with style attribute
PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitize function for dropAttributes list {"*": ["a"]} with style attribute PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitize from string function for dropAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitize function for empty dropAttributes list with id attribute PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitize from string function for empty dropAttributes list with id attribute
PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitize function for dropAttributes list {"id": ["*"]} with id attribute PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitize from string function for dropAttributes list {"id": ["*"]} with id attribute
PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitize function for dropAttributes list {"ID": ["*"]} with id attribute PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitize from string function for dropAttributes list {"ID": ["*"]} with id attribute
FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitize function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>" FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitize from string function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitize function for allowAttributes list {"id": ["div"]} with id attribute PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitize from string function for allowAttributes list {"id": ["div"]} with id attribute
PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitize function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitize from string function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitize function for allowAttributes list {"*": ["a"]} with style attribute PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitize from string function for allowAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitize function for allowAttributes list has no influence to dropAttributes PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitize from string function for allowAttributes list has no influence to dropAttributes
PASS SanitizerAPI with config: string, sanitize from document function for string
PASS SanitizerAPI with config: html fragment, sanitize from document function for html fragment
PASS SanitizerAPI with config: broken html, sanitize from document function for broken html
PASS SanitizerAPI with config: empty object, sanitize from document function for empty object
PASS SanitizerAPI with config: number, sanitize from document function for number
PASS SanitizerAPI with config: zeros, sanitize from document function for zeros
PASS SanitizerAPI with config: arithmetic, sanitize from document function for arithmetic
PASS SanitizerAPI with config: empty string, sanitize from document function for empty string
PASS SanitizerAPI with config: undefined, sanitize from document function for undefined
PASS SanitizerAPI with config: document, sanitize from document function for document
PASS SanitizerAPI with config: html without close tag, sanitize from document function for html without close tag
PASS SanitizerAPI with config: scripts for default configs, sanitize from document function for scripts for default configs
PASS SanitizerAPI with config: onclick scripts, sanitize from document function for onclick scripts
PASS SanitizerAPI with config: invalid config_input, sanitize from document function for invalid config_input
PASS SanitizerAPI with config: empty dropElements list, sanitize from document function for empty dropElements list
PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitize from document function for test html without close tag with dropElements list ['div']
PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitize from document function for test script with ["script"] as dropElements list
PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitize from document function for dropElements list ["test", "i"]}
PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitize from document function for dropElements list ["I", "AM"]}
PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitize from document function for dropElements list ["am", "p"]}
PASS SanitizerAPI with config: dropElements list with invalid values}, sanitize from document function for dropElements list with invalid values}
PASS SanitizerAPI with config: blockElements list with invalid values}, sanitize from document function for blockElements list with invalid values}
PASS SanitizerAPI with config: allowElements list ["p"]., sanitize from document function for allowElements list ["p"].
PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitize from document function for allowElements list has no influence to dropElements.
PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitize from document function for dropAttributes list {"style": ["p"]} with style attribute
PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitize from document function for dropAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitize from document function for empty dropAttributes list with id attribute
PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitize from document function for dropAttributes list {"id": ["*"]} with id attribute
PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitize from document function for dropAttributes list {"ID": ["*"]} with id attribute
FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitize from document function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitize from document function for allowAttributes list {"id": ["div"]} with id attribute
PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitize from document function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitize from document function for allowAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitize from document function for allowAttributes list has no influence to dropAttributes
PASS SanitizerAPI with config: string, sanitize from document fragment function for string
PASS SanitizerAPI with config: html fragment, sanitize from document fragment function for html fragment
PASS SanitizerAPI with config: broken html, sanitize from document fragment function for broken html
PASS SanitizerAPI with config: empty object, sanitize from document fragment function for empty object
PASS SanitizerAPI with config: number, sanitize from document fragment function for number
PASS SanitizerAPI with config: zeros, sanitize from document fragment function for zeros
PASS SanitizerAPI with config: arithmetic, sanitize from document fragment function for arithmetic
PASS SanitizerAPI with config: empty string, sanitize from document fragment function for empty string
PASS SanitizerAPI with config: undefined, sanitize from document fragment function for undefined
PASS SanitizerAPI with config: document, sanitize from document fragment function for document
PASS SanitizerAPI with config: html without close tag, sanitize from document fragment function for html without close tag
PASS SanitizerAPI with config: scripts for default configs, sanitize from document fragment function for scripts for default configs
PASS SanitizerAPI with config: onclick scripts, sanitize from document fragment function for onclick scripts
PASS SanitizerAPI with config: invalid config_input, sanitize from document fragment function for invalid config_input
PASS SanitizerAPI with config: empty dropElements list, sanitize from document fragment function for empty dropElements list
PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitize from document fragment function for test html without close tag with dropElements list ['div']
PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitize from document fragment function for test script with ["script"] as dropElements list
PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitize from document fragment function for dropElements list ["test", "i"]}
PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitize from document fragment function for dropElements list ["I", "AM"]}
PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitize from document fragment function for dropElements list ["am", "p"]}
PASS SanitizerAPI with config: dropElements list with invalid values}, sanitize from document fragment function for dropElements list with invalid values}
PASS SanitizerAPI with config: blockElements list with invalid values}, sanitize from document fragment function for blockElements list with invalid values}
PASS SanitizerAPI with config: allowElements list ["p"]., sanitize from document fragment function for allowElements list ["p"].
PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitize from document fragment function for allowElements list has no influence to dropElements.
PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitize from document fragment function for dropAttributes list {"style": ["p"]} with style attribute
PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitize from document fragment function for dropAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitize from document fragment function for empty dropAttributes list with id attribute
PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitize from document fragment function for dropAttributes list {"id": ["*"]} with id attribute
PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitize from document fragment function for dropAttributes list {"ID": ["*"]} with id attribute
FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitize from document fragment function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitize from document fragment function for allowAttributes list {"id": ["div"]} with id attribute
PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitize from document fragment function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitize from document fragment function for allowAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitize from document fragment function for allowAttributes list has no influence to dropAttributes
Harness: the test ran to completion. Harness: the test ran to completion.
...@@ -19,12 +19,46 @@ ...@@ -19,12 +19,46 @@
assert_throws_js(TypeError, _ => s.sanitize()); assert_throws_js(TypeError, _ => s.sanitize());
}, "SanitizerAPI sanitize function without argument should throw an error."); }, "SanitizerAPI sanitize function without argument should throw an error.");
test(t => {
let s = new Sanitizer({});
fragment = s.sanitize(null);
assert_true(fragment instanceof DocumentFragment);
assert_equals(getString(fragment), "null");
}, "SanitizerAPI sanitize function for null.");
testcases.forEach(c => test(t => { testcases.forEach(c => test(t => {
let s = new Sanitizer(c.config_input); let s = new Sanitizer(c.config_input);
fragment = s.sanitize(c.value); fragment = s.sanitize(c.value);
assert_true(fragment instanceof DocumentFragment); assert_true(fragment instanceof DocumentFragment);
assert_equals(getString(fragment), c.result); assert_equals(getString(fragment), c.result);
}, "SanitizerAPI with config: " + c.message + ", sanitize function for " + c.message)); }, "SanitizerAPI with config: " + c.message + ", sanitize from string function for " + c.message));
testcases.forEach(c => test(t => {
let s = new Sanitizer(c.config_input);
var dom = document.implementation.createHTMLDocument();
dom.documentElement.innerHTML = c.value;
fragment = s.sanitize(dom);
assert_true(fragment instanceof DocumentFragment);
let result = getString(fragment);
// Remove <html> and </html>
if (c.message != "document" && result.slice(0,12) == "<html><body>" && result.slice(result.length-14, result.length) == "</body></html>")
result = result.substr(12, result.length - 26);
if (c.message == "document") {
assert_equals(result, "<html><body>test</body></html>");
} else {
assert_equals(result, c.result);
}
}, "SanitizerAPI with config: " + c.message + ", sanitize from document function for " + c.message));
testcases.forEach(c => test(t => {
let s = new Sanitizer(c.config_input);
let tpl = document.createElement("template");
tpl.innerHTML = c.value;
fragment = s.sanitize(tpl.content);
assert_true(fragment instanceof DocumentFragment);
assert_equals(getString(fragment), c.result);
}, "SanitizerAPI with config: " + c.message + ", sanitize from document fragment function for " + c.message));
</script> </script>
</body> </body>
</html> </html>
This is a testharness.js-based test. This is a testharness.js-based test.
Found 104 tests; 101 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS SanitizerAPI sanitize function without argument should throw an error. PASS SanitizerAPI sanitize function without argument should throw an error.
PASS SanitizerAPI config: string, sanitizeToString function for string PASS SanitizerAPI sanitizeToString function for null.
PASS SanitizerAPI config: html fragment, sanitizeToString function for html fragment PASS SanitizerAPI config: string, sanitizeToString from string function for string
PASS SanitizerAPI config: broken html, sanitizeToString function for broken html PASS SanitizerAPI config: html fragment, sanitizeToString from string function for html fragment
PASS SanitizerAPI config: empty object, sanitizeToString function for empty object PASS SanitizerAPI config: broken html, sanitizeToString from string function for broken html
PASS SanitizerAPI config: number, sanitizeToString function for number PASS SanitizerAPI config: empty object, sanitizeToString from string function for empty object
PASS SanitizerAPI config: zeros, sanitizeToString function for zeros PASS SanitizerAPI config: number, sanitizeToString from string function for number
PASS SanitizerAPI config: arithmetic, sanitizeToString function for arithmetic PASS SanitizerAPI config: zeros, sanitizeToString from string function for zeros
PASS SanitizerAPI config: empty string, sanitizeToString function for empty string PASS SanitizerAPI config: arithmetic, sanitizeToString from string function for arithmetic
PASS SanitizerAPI config: undefined, sanitizeToString function for undefined PASS SanitizerAPI config: empty string, sanitizeToString from string function for empty string
PASS SanitizerAPI config: null, sanitizeToString function for null PASS SanitizerAPI config: undefined, sanitizeToString from string function for undefined
PASS SanitizerAPI config: document, sanitizeToString function for document PASS SanitizerAPI config: document, sanitizeToString from string function for document
PASS SanitizerAPI config: html without close tag, sanitizeToString function for html without close tag PASS SanitizerAPI config: html without close tag, sanitizeToString from string function for html without close tag
PASS SanitizerAPI config: scripts for default configs, sanitizeToString function for scripts for default configs PASS SanitizerAPI config: scripts for default configs, sanitizeToString from string function for scripts for default configs
PASS SanitizerAPI config: onclick scripts, sanitizeToString function for onclick scripts PASS SanitizerAPI config: onclick scripts, sanitizeToString from string function for onclick scripts
PASS SanitizerAPI config: invalid config_input, sanitizeToString function for invalid config_input PASS SanitizerAPI config: invalid config_input, sanitizeToString from string function for invalid config_input
PASS SanitizerAPI config: empty dropElements list, sanitizeToString function for empty dropElements list PASS SanitizerAPI config: empty dropElements list, sanitizeToString from string function for empty dropElements list
PASS SanitizerAPI config: test html without close tag with dropElements list ['div'], sanitizeToString function for test html without close tag with dropElements list ['div'] PASS SanitizerAPI config: test html without close tag with dropElements list ['div'], sanitizeToString from string function for test html without close tag with dropElements list ['div']
PASS SanitizerAPI config: test script with ["script"] as dropElements list, sanitizeToString function for test script with ["script"] as dropElements list PASS SanitizerAPI config: test script with ["script"] as dropElements list, sanitizeToString from string function for test script with ["script"] as dropElements list
PASS SanitizerAPI config: dropElements list ["test", "i"]}, sanitizeToString function for dropElements list ["test", "i"]} PASS SanitizerAPI config: dropElements list ["test", "i"]}, sanitizeToString from string function for dropElements list ["test", "i"]}
PASS SanitizerAPI config: dropElements list ["I", "AM"]}, sanitizeToString function for dropElements list ["I", "AM"]} PASS SanitizerAPI config: dropElements list ["I", "AM"]}, sanitizeToString from string function for dropElements list ["I", "AM"]}
PASS SanitizerAPI config: dropElements list ["am", "p"]}, sanitizeToString function for dropElements list ["am", "p"]} PASS SanitizerAPI config: dropElements list ["am", "p"]}, sanitizeToString from string function for dropElements list ["am", "p"]}
PASS SanitizerAPI config: dropElements list with invalid values}, sanitizeToString function for dropElements list with invalid values} PASS SanitizerAPI config: dropElements list with invalid values}, sanitizeToString from string function for dropElements list with invalid values}
PASS SanitizerAPI config: blockElements list with invalid values}, sanitizeToString function for blockElements list with invalid values} PASS SanitizerAPI config: blockElements list with invalid values}, sanitizeToString from string function for blockElements list with invalid values}
PASS SanitizerAPI config: allowElements list ["p"]., sanitizeToString function for allowElements list ["p"]. PASS SanitizerAPI config: allowElements list ["p"]., sanitizeToString from string function for allowElements list ["p"].
PASS SanitizerAPI config: allowElements list has no influence to dropElements., sanitizeToString function for allowElements list has no influence to dropElements. PASS SanitizerAPI config: allowElements list has no influence to dropElements., sanitizeToString from string function for allowElements list has no influence to dropElements.
PASS SanitizerAPI config: dropAttributes list {"style": ["p"]} with style attribute, sanitizeToString function for dropAttributes list {"style": ["p"]} with style attribute PASS SanitizerAPI config: dropAttributes list {"style": ["p"]} with style attribute, sanitizeToString from string function for dropAttributes list {"style": ["p"]} with style attribute
PASS SanitizerAPI config: dropAttributes list {"*": ["a"]} with style attribute, sanitizeToString function for dropAttributes list {"*": ["a"]} with style attribute PASS SanitizerAPI config: dropAttributes list {"*": ["a"]} with style attribute, sanitizeToString from string function for dropAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI config: empty dropAttributes list with id attribute, sanitizeToString function for empty dropAttributes list with id attribute PASS SanitizerAPI config: empty dropAttributes list with id attribute, sanitizeToString from string function for empty dropAttributes list with id attribute
PASS SanitizerAPI config: dropAttributes list {"id": ["*"]} with id attribute, sanitizeToString function for dropAttributes list {"id": ["*"]} with id attribute PASS SanitizerAPI config: dropAttributes list {"id": ["*"]} with id attribute, sanitizeToString from string function for dropAttributes list {"id": ["*"]} with id attribute
PASS SanitizerAPI config: dropAttributes list {"ID": ["*"]} with id attribute, sanitizeToString function for dropAttributes list {"ID": ["*"]} with id attribute PASS SanitizerAPI config: dropAttributes list {"ID": ["*"]} with id attribute, sanitizeToString from string function for dropAttributes list {"ID": ["*"]} with id attribute
FAIL SanitizerAPI config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitizeToString function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>" FAIL SanitizerAPI config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitizeToString from string function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
PASS SanitizerAPI config: allowAttributes list {"id": ["div"]} with id attribute, sanitizeToString function for allowAttributes list {"id": ["div"]} with id attribute PASS SanitizerAPI config: allowAttributes list {"id": ["div"]} with id attribute, sanitizeToString from string function for allowAttributes list {"id": ["div"]} with id attribute
PASS SanitizerAPI config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitizeToString function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts PASS SanitizerAPI config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitizeToString from string function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
PASS SanitizerAPI config: allowAttributes list {"*": ["a"]} with style attribute, sanitizeToString function for allowAttributes list {"*": ["a"]} with style attribute PASS SanitizerAPI config: allowAttributes list {"*": ["a"]} with style attribute, sanitizeToString from string function for allowAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI config: allowAttributes list has no influence to dropAttributes, sanitizeToString function for allowAttributes list has no influence to dropAttributes PASS SanitizerAPI config: allowAttributes list has no influence to dropAttributes, sanitizeToString from string function for allowAttributes list has no influence to dropAttributes
PASS SanitizerAPI with config: string, sanitizeToString from document function for string
PASS SanitizerAPI with config: html fragment, sanitizeToString from document function for html fragment
PASS SanitizerAPI with config: broken html, sanitizeToString from document function for broken html
PASS SanitizerAPI with config: empty object, sanitizeToString from document function for empty object
PASS SanitizerAPI with config: number, sanitizeToString from document function for number
PASS SanitizerAPI with config: zeros, sanitizeToString from document function for zeros
PASS SanitizerAPI with config: arithmetic, sanitizeToString from document function for arithmetic
PASS SanitizerAPI with config: empty string, sanitizeToString from document function for empty string
PASS SanitizerAPI with config: undefined, sanitizeToString from document function for undefined
PASS SanitizerAPI with config: document, sanitizeToString from document function for document
PASS SanitizerAPI with config: html without close tag, sanitizeToString from document function for html without close tag
PASS SanitizerAPI with config: scripts for default configs, sanitizeToString from document function for scripts for default configs
PASS SanitizerAPI with config: onclick scripts, sanitizeToString from document function for onclick scripts
PASS SanitizerAPI with config: invalid config_input, sanitizeToString from document function for invalid config_input
PASS SanitizerAPI with config: empty dropElements list, sanitizeToString from document function for empty dropElements list
PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitizeToString from document function for test html without close tag with dropElements list ['div']
PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitizeToString from document function for test script with ["script"] as dropElements list
PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitizeToString from document function for dropElements list ["test", "i"]}
PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitizeToString from document function for dropElements list ["I", "AM"]}
PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitizeToString from document function for dropElements list ["am", "p"]}
PASS SanitizerAPI with config: dropElements list with invalid values}, sanitizeToString from document function for dropElements list with invalid values}
PASS SanitizerAPI with config: blockElements list with invalid values}, sanitizeToString from document function for blockElements list with invalid values}
PASS SanitizerAPI with config: allowElements list ["p"]., sanitizeToString from document function for allowElements list ["p"].
PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitizeToString from document function for allowElements list has no influence to dropElements.
PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitizeToString from document function for dropAttributes list {"style": ["p"]} with style attribute
PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitizeToString from document function for dropAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitizeToString from document function for empty dropAttributes list with id attribute
PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitizeToString from document function for dropAttributes list {"id": ["*"]} with id attribute
PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitizeToString from document function for dropAttributes list {"ID": ["*"]} with id attribute
FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitizeToString from document function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitizeToString from document function for allowAttributes list {"id": ["div"]} with id attribute
PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitizeToString from document function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitizeToString from document function for allowAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitizeToString from document function for allowAttributes list has no influence to dropAttributes
PASS SanitizerAPI with config: string, sanitizeToString from document fragment function for string
PASS SanitizerAPI with config: html fragment, sanitizeToString from document fragment function for html fragment
PASS SanitizerAPI with config: broken html, sanitizeToString from document fragment function for broken html
PASS SanitizerAPI with config: empty object, sanitizeToString from document fragment function for empty object
PASS SanitizerAPI with config: number, sanitizeToString from document fragment function for number
PASS SanitizerAPI with config: zeros, sanitizeToString from document fragment function for zeros
PASS SanitizerAPI with config: arithmetic, sanitizeToString from document fragment function for arithmetic
PASS SanitizerAPI with config: empty string, sanitizeToString from document fragment function for empty string
PASS SanitizerAPI with config: undefined, sanitizeToString from document fragment function for undefined
PASS SanitizerAPI with config: document, sanitizeToString from document fragment function for document
PASS SanitizerAPI with config: html without close tag, sanitizeToString from document fragment function for html without close tag
PASS SanitizerAPI with config: scripts for default configs, sanitizeToString from document fragment function for scripts for default configs
PASS SanitizerAPI with config: onclick scripts, sanitizeToString from document fragment function for onclick scripts
PASS SanitizerAPI with config: invalid config_input, sanitizeToString from document fragment function for invalid config_input
PASS SanitizerAPI with config: empty dropElements list, sanitizeToString from document fragment function for empty dropElements list
PASS SanitizerAPI with config: test html without close tag with dropElements list ['div'], sanitizeToString from document fragment function for test html without close tag with dropElements list ['div']
PASS SanitizerAPI with config: test script with ["script"] as dropElements list, sanitizeToString from document fragment function for test script with ["script"] as dropElements list
PASS SanitizerAPI with config: dropElements list ["test", "i"]}, sanitizeToString from document fragment function for dropElements list ["test", "i"]}
PASS SanitizerAPI with config: dropElements list ["I", "AM"]}, sanitizeToString from document fragment function for dropElements list ["I", "AM"]}
PASS SanitizerAPI with config: dropElements list ["am", "p"]}, sanitizeToString from document fragment function for dropElements list ["am", "p"]}
PASS SanitizerAPI with config: dropElements list with invalid values}, sanitizeToString from document fragment function for dropElements list with invalid values}
PASS SanitizerAPI with config: blockElements list with invalid values}, sanitizeToString from document fragment function for blockElements list with invalid values}
PASS SanitizerAPI with config: allowElements list ["p"]., sanitizeToString from document fragment function for allowElements list ["p"].
PASS SanitizerAPI with config: allowElements list has no influence to dropElements., sanitizeToString from document fragment function for allowElements list has no influence to dropElements.
PASS SanitizerAPI with config: dropAttributes list {"style": ["p"]} with style attribute, sanitizeToString from document fragment function for dropAttributes list {"style": ["p"]} with style attribute
PASS SanitizerAPI with config: dropAttributes list {"*": ["a"]} with style attribute, sanitizeToString from document fragment function for dropAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: empty dropAttributes list with id attribute, sanitizeToString from document fragment function for empty dropAttributes list with id attribute
PASS SanitizerAPI with config: dropAttributes list {"id": ["*"]} with id attribute, sanitizeToString from document fragment function for dropAttributes list {"id": ["*"]} with id attribute
PASS SanitizerAPI with config: dropAttributes list {"ID": ["*"]} with id attribute, sanitizeToString from document fragment function for dropAttributes list {"ID": ["*"]} with id attribute
FAIL SanitizerAPI with config: dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access., sanitizeToString from document fragment function for dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access. assert_equals: expected "<p id=\"p\">Click.</p><script></script>" but got "<p id=\"p\">Click.</p>"
PASS SanitizerAPI with config: allowAttributes list {"id": ["div"]} with id attribute, sanitizeToString from document fragment function for allowAttributes list {"id": ["div"]} with id attribute
PASS SanitizerAPI with config: allowAttributes list {"id": ["*"]} with id attribute and onclick scripts, sanitizeToString from document fragment function for allowAttributes list {"id": ["*"]} with id attribute and onclick scripts
PASS SanitizerAPI with config: allowAttributes list {"*": ["a"]} with style attribute, sanitizeToString from document fragment function for allowAttributes list {"*": ["a"]} with style attribute
PASS SanitizerAPI with config: allowAttributes list has no influence to dropAttributes, sanitizeToString from document fragment function for allowAttributes list has no influence to dropAttributes
Harness: the test ran to completion. Harness: the test ran to completion.
...@@ -13,10 +13,38 @@ ...@@ -13,10 +13,38 @@
assert_throws_js(TypeError, _ => s.sanitizeToString()); assert_throws_js(TypeError, _ => s.sanitizeToString());
}, "SanitizerAPI sanitize function without argument should throw an error."); }, "SanitizerAPI sanitize function without argument should throw an error.");
test(t => {
let s = new Sanitizer({});
fragment = s.sanitize(null);
assert_equals(s.sanitizeToString(null), "null");
}, "SanitizerAPI sanitizeToString function for null.");
testcases.forEach(c => test(t => { testcases.forEach(c => test(t => {
let s = new Sanitizer(c.config_input); let s = new Sanitizer(c.config_input);
assert_equals(s.sanitizeToString(c.value), c.result); assert_equals(s.sanitizeToString(c.value), c.result);
}, "SanitizerAPI config: " + c.message + ", sanitizeToString function for " + c.message)); }, "SanitizerAPI config: " + c.message + ", sanitizeToString from string function for " + c.message));
testcases.forEach(c => test(t => {
let s = new Sanitizer(c.config_input);
var dom = document.implementation.createHTMLDocument();
dom.documentElement.innerHTML = c.value;
let result = s.sanitizeToString(dom);
// Remove <html> and </html>
if (c.message != "document" && result.slice(0,12) == "<html><body>" && result.slice(result.length-14, result.length) == "</body></html>")
result = result.substr(12, result.length - 26);
if (c.message == "document") {
assert_equals(result, "<html><body>test</body></html>");
} else {
assert_equals(result, c.result);
}
}, "SanitizerAPI with config: " + c.message + ", sanitizeToString from document function for " + c.message));
testcases.forEach(c => test(t => {
let s = new Sanitizer(c.config_input);
let tpl = document.createElement("template");
tpl.innerHTML = c.value;
assert_equals(s.sanitizeToString(tpl.content), c.result);
}, "SanitizerAPI with config: " + c.message + ", sanitizeToString from document fragment function for " + c.message));
</script> </script>
</body> </body>
</html> </html>
...@@ -8,7 +8,6 @@ const testcases = [ ...@@ -8,7 +8,6 @@ const testcases = [
{config_input: {}, value: 1+2, result: "3", message: "arithmetic"}, {config_input: {}, value: 1+2, result: "3", message: "arithmetic"},
{config_input: {}, value: "", result: "", message: "empty string"}, {config_input: {}, value: "", result: "", message: "empty string"},
{config_input: {}, value: undefined, result: "undefined", message: "undefined"}, {config_input: {}, value: undefined, result: "undefined", message: "undefined"},
{config_input: {}, value: null, result: "null", message: "null"},
{config_input: {}, value: "<html><head></head><body>test</body></html>", result: "test", message: "document"}, {config_input: {}, value: "<html><head></head><body>test</body></html>", result: "test", message: "document"},
{config_input: {}, value: "<div>test", result: "<div>test</div>", message: "html without close tag"}, {config_input: {}, value: "<div>test", result: "<div>test</div>", message: "html without close tag"},
{config_input: {}, value: "<script>alert('i am a test')<\/script>", result: "", message: "scripts for default configs"}, {config_input: {}, value: "<script>alert('i am a test')<\/script>", result: "", message: "scripts for default configs"},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment