Skip to content

Commit

Permalink
Implement value sanitization algorithms for several input types
Browse files Browse the repository at this point in the history
  • Loading branch information
Zirro authored and domenic committed Apr 29, 2017
1 parent b2bfc3d commit ac49743
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 5 deletions.
39 changes: 39 additions & 0 deletions lib/jsdom/living/helpers/form-controls.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use strict";

const { isValidSimpleColor, stripLeadingAndTrailingASCIIWhitespace, stripNewlines } = require("./strings");

const submittableLocalNames = new Set(["button", "input", "keygen", "object", "select", "textarea"]);

exports.isDisabled = formControl => {
Expand Down Expand Up @@ -41,3 +43,40 @@ exports.normalizeToCRLF = string => {
.replace(/([^\r])\n/g, "$1\r\n")
.replace(/^\n/, "\r\n");
};

exports.sanitizeValueByType = (input, val) => {
switch (input.type.toLowerCase()) {
case "password":
case "search":
case "tel":
case "text":
val = stripNewlines(val);
break;

case "color":
// https://html.spec.whatwg.org/multipage/forms.html#color-state-(type=color):value-sanitization-algorithm
val = isValidSimpleColor(val) ? val.toLowerCase() : "#000000";
break;

case "email":
// https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email):value-sanitization-algorithm
// https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email):value-sanitization-algorithm-2
if (input.hasAttribute("multiple")) {
val = val.split(",").map(token => stripLeadingAndTrailingASCIIWhitespace(token)).join(",");
} else {
val = stripNewlines(val);
val = stripLeadingAndTrailingASCIIWhitespace(val);
}
break;

case "url":
// https://html.spec.whatwg.org/multipage/forms.html#url-state-(type=url):value-sanitization-algorithm
val = stripNewlines(val);
val = stripLeadingAndTrailingASCIIWhitespace(val);
break;
}

// TODO: Sanitize values for date, datetime-local, month, number, range, time and week.

return val;
};
15 changes: 15 additions & 0 deletions lib/jsdom/living/helpers/strings.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
"use strict";

// https://infra.spec.whatwg.org/#strip-newlines
exports.stripNewlines = s => {
return s.replace(/[\n\r]+/g, "");
};

// https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace
exports.stripLeadingAndTrailingASCIIWhitespace = s => {
return s.replace(/^[ \t\n\f\r]+/, "").replace(/[ \t\n\f\r]+$/, "");
};

// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
exports.stripAndCollapseASCIIWhitespace = s => {
return s.replace(/[ \t\n\f\r]+/g, " ").replace(/^[ \t\n\f\r]+/, "").replace(/[ \t\n\f\r]+$/, "");
};

// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-simple-colour
exports.isValidSimpleColor = s => {
return /^#[a-fA-F\d]{6}$/.test(s);
};
7 changes: 4 additions & 3 deletions lib/jsdom/living/nodes/HTMLInputElement-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const domSymbolTree = internalConstants.domSymbolTree;
const cloningSteps = internalConstants.cloningSteps;
const closest = require("../helpers/traversal").closest;
const isDisabled = require("../helpers/form-controls").isDisabled;
const sanitizeValueByType = require("../helpers/form-controls").sanitizeValueByType;

const filesSymbol = Symbol("files");

Expand Down Expand Up @@ -93,7 +94,7 @@ class HTMLInputElementImpl extends HTMLElementImpl {
_attrModified(name) {
const wrapper = idlUtils.wrapperForImpl(this);
if (!this._dirtyValue && name === "value") {
this._value = wrapper.defaultValue;
this._value = sanitizeValueByType(this, wrapper.defaultValue);
}
if (!this._dirtyCheckedness && name === "checked") {
this._checkedness = wrapper.defaultChecked;
Expand All @@ -112,7 +113,7 @@ class HTMLInputElementImpl extends HTMLElementImpl {
}
_formReset() {
const wrapper = idlUtils.wrapperForImpl(this);
this._value = wrapper.defaultValue;
this._value = sanitizeValueByType(this, wrapper.defaultValue);
this._dirtyValue = false;
this._checkedness = wrapper.defaultChecked;
this._dirtyCheckedness = false;
Expand Down Expand Up @@ -192,7 +193,7 @@ class HTMLInputElementImpl extends HTMLElementImpl {
if (val === null) {
this._value = null;
} else {
this._value = String(val);
this._value = sanitizeValueByType(this, String(val));
}

this._selectionStart = 0;
Expand Down
5 changes: 5 additions & 0 deletions test/web-platform-tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,12 @@ describe("Web Platform Tests", () => {
"html/editing/focus/sequential-focus-navigation-and-the-tabindex-attribute/focus-tabindex-default-value.html",
// "html/infrastructure/urls/terminology-0/document-base-url.html", // we don't support srcdoc <base> correctly
"html/semantics/forms/attributes-common-to-form-controls/disabled-elements-01.html",
"html/semantics/forms/the-input-element/color.html",
"html/semantics/forms/the-input-element/password.html",
"html/semantics/forms/the-input-element/search_input.html",
"html/semantics/forms/the-input-element/selection.html",
"html/semantics/forms/the-input-element/telephone.html",
"html/semantics/forms/the-input-element/url.html",
"html/semantics/forms/the-option-element/option-form.html",
// "html/semantics/forms/the-option-element/option-label.html", // our impl is wrong; see comments in HTMLOptionElement-impl.js
"html/semantics/forms/the-option-element/option-selected.html",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
input2.name = "submit-me-\r19\n";
input2.value = "value\n\r";
assert_equals(input2.name, "submit-me-\r19\n", "input.name accepts \\r and \\n");
assert_equals(input2.value, "value\n\r", "input.value accepts \\n followed by \\r");
assert_equals(input2.value, "value", "input.value when type=text should not contain newlines");
form.appendChild(input2);

const formData = new FormData(form);
Expand All @@ -126,7 +126,7 @@
["dirname-is-special", "dirname-value"],
["submit-me-17", "ltr"],
["submit-me-18-\uFFFD", "value-\uFFFD"],
["submit-me-\r\n19\r\n", "value\r\n\r\n"]
["submit-me-\r\n19\r\n", "value"]
];

for (const t of expected) {
Expand Down

0 comments on commit ac49743

Please sign in to comment.