Validate UserCSS meta colors. Fixes #554 (#559)

* Validate UserCSS meta colors. Fixes #554

* Add suggestions & optimize code

* Fix parsePercentage return value

* cleanup

* Fix: remove unused variable

* Fix: validate function should return a boolean

* Revert indent

* Fix: cleaner validateRGB

* Fix: validateHSL

* Fix: validateAlpha

* Cleanup

* Fix: remove invalid comment

* Limit color channels to integers
This commit is contained in:
Rob Garrison 2018-11-18 22:05:38 -06:00 committed by GitHub
parent 7261a074cd
commit 7ea0200234
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -42,6 +42,41 @@ const colorConverter = (() => {
}
}
// Copied from _hexcolor() in parserlib.js
function validateHex(color) {
return /^#[a-f\d]+$/i.test(color) && [4, 5, 7, 9].some(n => color.length === n);
}
function validateRGB(nums) {
const isPercentage = nums[0].endsWith('%');
const valid = isPercentage ? validatePercentage : validateNum;
return nums.slice(0, 3).every(valid);
}
function validatePercentage(s) {
const match = s.match(/^(\d+|\d*\.\d+)%$/);
return match && Number(match[1]) >= 0 && Number(match[1]) <= 100;
}
function validateNum(s) {
return /^\d+$/.test(s) && Number(s) >= 0 && Number(s) <= 255;
}
function validateHSL(nums) {
return validateAngle(nums[0]) && nums.slice(1, 3).every(validatePercentage);
}
function validateAngle(s) {
return /^-?(\d+|\d*\.\d+)(deg|grad|rad|turn)?$/i.test(s);
}
function validateAlpha(alpha) {
if (alpha.endsWith('%')) {
return validatePercentage(alpha);
}
return Number(alpha) >= 0 && Number(alpha) <= 1;
}
function parse(str) {
if (typeof str !== 'string') return;
str = str.trim();
@ -54,6 +89,9 @@ const colorConverter = (() => {
}
if (str[0] === '#') {
if (!validateHex(str)) {
return null;
}
str = str.slice(1);
const [r, g, b, a = 255] = str.length <= 4 ?
str.match(/(.)/g).map(c => parseInt(c + c, 16)) :
@ -67,16 +105,23 @@ const colorConverter = (() => {
const comma = value.includes(',') && !value.includes('/');
const num = value.split(comma ? /\s*,\s*/ : /\s+(?!\/)|\s*\/\s*/);
if (num.length < 3 || num.length > 4) return;
if (num[3] && !validateAlpha(num[3])) return null;
let a = !num[3] ? 1 : parseFloat(num[3]) / (num[3].endsWith('%') ? 100 : 1);
if (isNaN(a)) a = 1;
const first = num[0];
if (/rgb/i.test(type)) {
if (!validateRGB(num)) {
return null;
}
const k = first.endsWith('%') ? 2.55 : 1;
const [r, g, b] = num.map(s => parseFloat(s) * k);
const [r, g, b] = num.map(s => Math.round(parseFloat(s) * k));
return {type: 'rgb', r, g, b, a};
} else {
if (!validateHSL(num)) {
return null;
}
let h = parseFloat(first);
if (first.endsWith('grad')) h *= 360 / 400;
else if (first.endsWith('rad')) h *= 180 / Math.PI;