diff --git a/classes/CMS.php b/classes/CMS.php index 176d3d61b..db9d69d52 100644 --- a/classes/CMS.php +++ b/classes/CMS.php @@ -53,7 +53,7 @@ class CMSCore extends ObjectModel 'meta_keywords' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255), 'meta_title' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 128), 'link_rewrite' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isLinkRewrite', 'required' => true, 'size' => 128), - 'content' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString', 'size' => 3999999999999), + 'content' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml', 'size' => 3999999999999), ), ); diff --git a/classes/Category.php b/classes/Category.php index 55982d2a2..35cbdb0f4 100644 --- a/classes/Category.php +++ b/classes/Category.php @@ -109,7 +109,7 @@ class CategoryCore extends ObjectModel // Lang fields 'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCatalogName', 'required' => true, 'size' => 64), 'link_rewrite' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isLinkRewrite', 'required' => true, 'size' => 64), - 'description' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString'), + 'description' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml'), 'meta_title' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 128), 'meta_description' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255), 'meta_keywords' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255), diff --git a/classes/Hook.php b/classes/Hook.php index 74d95142c..420d5b798 100644 --- a/classes/Hook.php +++ b/classes/Hook.php @@ -64,10 +64,10 @@ class HookCore extends ObjectModel 'primary' => 'id_hook', 'fields' => array( 'name' => array('type' => self::TYPE_STRING, 'validate' => 'isHookName', 'required' => true, 'size' => 64), - 'title' => array('type' => self::TYPE_STRING), - 'description' => array('type' => self::TYPE_HTML), - 'position' => array('type' => self::TYPE_BOOL), - 'live_edit' => array('type' => self::TYPE_BOOL), + 'title' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'), + 'description' => array('type' => self::TYPE_HTML, 'validate' => 'isCleanHtml'), + 'position' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), + 'live_edit' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), ), ); diff --git a/classes/Manufacturer.php b/classes/Manufacturer.php index 285f802e1..df79245a8 100644 --- a/classes/Manufacturer.php +++ b/classes/Manufacturer.php @@ -78,8 +78,8 @@ class ManufacturerCore extends ObjectModel 'date_upd' => array('type' => self::TYPE_DATE), // Lang fields - 'description' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString'), - 'short_description' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString', 'size' => 254), + 'description' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml'), + 'short_description' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml', 'size' => 254), 'meta_title' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 128), 'meta_description' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255), 'meta_keywords' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName'), diff --git a/classes/ObjectModel.php b/classes/ObjectModel.php index 27e1560db..ca2d1c608 100644 --- a/classes/ObjectModel.php +++ b/classes/ObjectModel.php @@ -939,8 +939,23 @@ abstract class ObjectModelCore if (!method_exists('Validate', $data['validate'])) throw new PrestaShopException('Validation function not found. '.$data['validate']); - if (!empty($value) && !call_user_func(array('Validate', $data['validate']), $value)) - return 'Property '.get_class($this).'->'.$field.' is not valid'; + if (!empty($value)) + { + $res = true; + if (Tools::strtolower($data['validate']) == 'isCleanHtml') + { + d('in'); + if (!call_user_func(array('Validate', $data['validate']), $value, (int)Configuration::get('PS_ALLOW_HTML_IFRAME'))) + $res = false; + } + else + { + if (!call_user_func(array('Validate', $data['validate']), $value)) + $res = false; + } + if (!$res) + return 'Property '.get_class($this).'->'.$field.' is not valid'; + } } return true; diff --git a/classes/Product.php b/classes/Product.php index d14d49294..eefa229e1 100644 --- a/classes/Product.php +++ b/classes/Product.php @@ -297,8 +297,8 @@ class ProductCore extends ObjectModel 'meta_title' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 128), 'link_rewrite' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isLinkRewrite', 'required' => true, 'size' => 128), 'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCatalogName', 'required' => true, 'size' => 128), - 'description' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString'), - 'description_short' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString'), + 'description' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml'), + 'description_short' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml'), 'available_now' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255), 'available_later' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'IsGenericName', 'size' => 255), ), diff --git a/classes/Validate.php b/classes/Validate.php index cee80bd01..dc308b857 100644 --- a/classes/Validate.php +++ b/classes/Validate.php @@ -389,7 +389,7 @@ class ValidateCore * @param string $html HTML field to validate * @return boolean Validity is ok or not */ - public static function isCleanHtml($html) + public static function isCleanHtml($html, $allow_iframe = false) { $events = 'onmousedown|onmousemove|onmmouseup|onmouseover|onmouseout|onload|onunload|onfocus|onblur|onchange'; $events .= '|onsubmit|ondblclick|onclick|onkeydown|onkeyup|onkeypress|onmouseenter|onmouseleave|onerror|onselect|onreset|onabort|ondragdrop|onresize|onactivate|onafterprint|onmoveend'; @@ -398,7 +398,14 @@ class ValidateCore $events .= '|ondragleave|ondragover|ondragstart|ondrop|onerrorupdate|onfilterchange|onfinish|onfocusin|onfocusout|onhashchange|onhelp|oninput|onlosecapture|onmessage|onmouseup|onmovestart'; $events .= '|onoffline|ononline|onpaste|onpropertychange|onreadystatechange|onresizeend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onsearch|onselectionchange'; $events .= '|onselectstart|onstart|onstop'; - return (!preg_match('/<[ \t\n]*script/ims', $html) && !preg_match('/('.$events.')[ \t\n]*=/ims', $html) && !preg_match('/.*script\:/ims', $html) && !preg_match('/<[ \t\n]*i?frame/ims', $html)); + + if (preg_match('/<[ \t\n]*script/ims', $html) || preg_match('/('.$events.')[ \t\n]*=/ims', $html) || preg_match('/.*script\:/ims', $html)) + return false; + + if (!$allow_iframe && preg_match('/<[ \t\n]*(i?frame|form|input|embed|object)/ims', $html)) + return false; + + return true; } /** diff --git a/controllers/admin/AdminPreferencesController.php b/controllers/admin/AdminPreferencesController.php index 5df23eae9..f878f69fc 100644 --- a/controllers/admin/AdminPreferencesController.php +++ b/controllers/admin/AdminPreferencesController.php @@ -95,6 +95,14 @@ class AdminPreferencesControllerCore extends AdminController 'default' => '0', 'visibility' => Shop::CONTEXT_ALL ), + 'PS_ALLOW_HTML_IFRAME' => array( + 'title' => $this->l('Allow iframes on html fields'), + 'desc' => $this->l('Allow iframes on fields like product description. We recommend that you leave this option disabled'), + 'validation' => 'isBool', + 'cast' => 'intval', + 'type' => 'bool', + 'default' => '0' + ), 'PS_PRICE_ROUND_MODE' => array( 'title' => $this->l('Round mode'), 'desc' => $this->l('You can choose how to round prices: Always round superior, always round inferior or classic rounding.'), diff --git a/controllers/admin/AdminProductsController.php b/controllers/admin/AdminProductsController.php index 003226a23..50d141c3a 100644 --- a/controllers/admin/AdminProductsController.php +++ b/controllers/admin/AdminProductsController.php @@ -2058,17 +2058,28 @@ class AdminProductsControllerCore extends AdminController // Check fields validity foreach ($rules['validate'] as $field => $function) if ($this->isProductFieldUpdated($field) && ($value = Tools::getValue($field))) - if (!Validate::$function($value)) + { + $res = true; + if (Tools::strtolower($function) == 'isCleanHtml') + { + if (!Validate::$function($value, (int)Configuration::get('PS_ALLOW_HTML_IFRAME'))) + $res = false; + } + else + if (!Validate::$function($value)) + $res = false; + + if (!$res) $this->errors[] = sprintf( Tools::displayError('The %s field is invalid.'), call_user_func(array($className, 'displayFieldName'), $field, $className) ); - + } // Check multilingual fields validity foreach ($rules['validateLang'] as $fieldLang => $function) foreach ($languages as $language) if ($this->isProductFieldUpdated('description_short', $language['id_lang']) && ($value = Tools::getValue($fieldLang.'_'.$language['id_lang']))) - if (!Validate::$function($value)) + if (!Validate::$function($value, (int)Configuration::get('PS_ALLOW_HTML_IFRAME'))) $this->errors[] = sprintf( Tools::displayError('The %1$s field (%2$s) is invalid.'), call_user_func(array($className, 'displayFieldName'), $fieldLang, $className),