diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 0af24a0a86..51e8ae82f9 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,3 +1,13 @@ +==== 1.9.4.3 ==== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +] NOTE: Current Release Notes are maintained at: [ +] [ +] http://devdocs.magento.com/guides/m1x/ce19-ee114/ce1.9_release-notes.html [ +] [ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ==== 1.9.4.2 ==== ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/app/Mage.php b/app/Mage.php index e2ae8a242a..09b8df2e6e 100644 --- a/app/Mage.php +++ b/app/Mage.php @@ -174,7 +174,7 @@ public static function getVersionInfo() 'major' => '1', 'minor' => '9', 'revision' => '4', - 'patch' => '2', + 'patch' => '3', 'stability' => '', 'number' => '', ); diff --git a/app/code/core/Mage/Admin/Model/User.php b/app/code/core/Mage/Admin/Model/User.php index c651195035..b2b27ebb50 100644 --- a/app/code/core/Mage/Admin/Model/User.php +++ b/app/code/core/Mage/Admin/Model/User.php @@ -74,14 +74,25 @@ class Mage_Admin_Model_User extends Mage_Core_Model_Abstract /** * Minimum length of admin password + * @deprecated Use getMinAdminPasswordLength() method instead */ - const MIN_PASSWORD_LENGTH = 7; + const MIN_PASSWORD_LENGTH = 14; + + /** + * Configuration path for minimum length of admin password + */ + const XML_PATH_MIN_ADMIN_PASSWORD_LENGTH = 'admin/security/min_admin_password_length'; /** * Length of salt */ const HASH_SALT_LENGTH = 32; + /** + * Empty hash salt + */ + const HASH_SALT_EMPTY = null; + /** * Model event prefix * @@ -459,7 +470,7 @@ public function hasAssigned2Role($user) */ protected function _getEncodedPassword($password) { - return $this->_getHelper('core')->getHash($password, self::HASH_SALT_LENGTH); + return $this->_getHelper('core')->getHashPassword($password, self::HASH_SALT_LENGTH); } /** @@ -569,17 +580,23 @@ public function validate() } if ($this->hasNewPassword()) { - if (Mage::helper('core/string')->strlen($this->getNewPassword()) < self::MIN_PASSWORD_LENGTH) { - $errors[] = Mage::helper('adminhtml')->__('Password must be at least of %d characters.', self::MIN_PASSWORD_LENGTH); + $password = $this->getNewPassword(); + } elseif ($this->hasPassword()) { + $password = $this->getPassword(); + } + if (isset($password)) { + $minAdminPasswordLength = $this->getMinAdminPasswordLength(); + if (Mage::helper('core/string')->strlen($password) < $minAdminPasswordLength) { + $errors[] = Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', $minAdminPasswordLength); } - if (!preg_match('/[a-z]/iu', $this->getNewPassword()) - || !preg_match('/[0-9]/u', $this->getNewPassword()) - ) { - $errors[] = Mage::helper('adminhtml')->__('Password must include both numeric and alphabetic characters.'); + if (!preg_match('/[a-z]/iu', $password) || !preg_match('/[0-9]/u', $password)) { + $errors[] = Mage::helper('adminhtml') + ->__('Password must include both numeric and alphabetic characters.'); } - if ($this->hasPasswordConfirmation() && $this->getNewPassword() != $this->getPasswordConfirmation()) { + if ($this->hasPasswordConfirmation() && $password != $this->getPasswordConfirmation()) { $errors[] = Mage::helper('adminhtml')->__('Password confirmation must be same as password.'); } @@ -745,4 +762,16 @@ public function getUserCreateAdditionalEmail() $emails = str_replace(' ', '', Mage::getStoreConfig(self::XML_PATH_ADDITIONAL_EMAILS)); return explode(',', $emails); } + + /** + * Retrieve minimum length of admin password + * + * @return int + */ + public function getMinAdminPasswordLength() + { + $minLength = (int)Mage::getStoreConfig(self::XML_PATH_MIN_ADMIN_PASSWORD_LENGTH); + $absoluteMinLength = Mage_Core_Model_App::ABSOLUTE_MIN_PASSWORD_LENGTH; + return ($minLength < $absoluteMinLength) ? $absoluteMinLength : $minLength; + } } diff --git a/app/code/core/Mage/Admin/etc/config.xml b/app/code/core/Mage/Admin/etc/config.xml index ad751d5773..e26d160f73 100644 --- a/app/code/core/Mage/Admin/etc/config.xml +++ b/app/code/core/Mage/Admin/etc/config.xml @@ -28,7 +28,7 @@ - 1.6.1.2 + 1.6.1.3 diff --git a/app/code/core/Mage/Admin/sql/admin_setup/upgrade-1.6.1.2-1.6.1.3.php b/app/code/core/Mage/Admin/sql/admin_setup/upgrade-1.6.1.2-1.6.1.3.php new file mode 100644 index 0000000000..9c5a6cdf4c --- /dev/null +++ b/app/code/core/Mage/Admin/sql/admin_setup/upgrade-1.6.1.2-1.6.1.3.php @@ -0,0 +1,43 @@ +startSetup(); + +//Increase password field length +$installer->getConnection()->changeColumn( + $installer->getTable('admin/user'), + 'password', + 'password', + array( + 'type' => Varien_Db_Ddl_Table::TYPE_TEXT, + 'length' => 255, + 'comment' => 'User Password', + ) +); + +$installer->endSetup(); diff --git a/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Main.php b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Main.php index 8bab5216bf..beb1bdc4cb 100644 --- a/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Main.php +++ b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Main.php @@ -96,13 +96,16 @@ protected function _prepareForm() ) ); + $minPasswordLength = Mage::getModel('customer/customer')->getMinPasswordLength(); if ($model->getUserId()) { $fieldset->addField('password', 'password', array( 'name' => 'new_api_key', 'label' => Mage::helper('adminhtml')->__('New API Key'), 'id' => 'new_pass', 'title' => Mage::helper('adminhtml')->__('New API Key'), - 'class' => 'input-text validate-password', + 'class' => 'input-text validate-password min-pass-length-' . $minPasswordLength, + 'note' => Mage::helper('adminhtml') + ->__('API Key must be at least of %d characters.', $minPasswordLength), )); $fieldset->addField('confirmation', 'password', array( @@ -113,15 +116,17 @@ protected function _prepareForm() )); } else { - $fieldset->addField('password', 'password', array( + $fieldset->addField('password', 'password', array( 'name' => 'api_key', 'label' => Mage::helper('adminhtml')->__('API Key'), 'id' => 'customer_pass', 'title' => Mage::helper('adminhtml')->__('API Key'), - 'class' => 'input-text required-entry validate-password', + 'class' => 'input-text required-entry validate-password min-pass-length-' . $minPasswordLength, 'required' => true, + 'note' => Mage::helper('adminhtml') + ->__('API Key must be at least of %d characters.', $minPasswordLength), )); - $fieldset->addField('confirmation', 'password', array( + $fieldset->addField('confirmation', 'password', array( 'name' => 'api_key_confirmation', 'label' => Mage::helper('adminhtml')->__('API Key Confirmation'), 'id' => 'confirmation', diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main.php index 64011bac0a..cabce58bac 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Set/Main.php @@ -93,10 +93,13 @@ protected function _prepareLayout() 'class' => 'save' ))); + $deleteConfirmMessage = $this->jsQuoteEscape(Mage::helper('catalog') + ->__('All products of this set will be deleted! Are you sure you want to delete this attribute set?')); + $deleteUrl = $this->getUrlSecure('*/*/delete', array('id' => $setId)); $this->setChild('delete_button', $this->getLayout()->createBlock('adminhtml/widget_button')->setData(array( 'label' => Mage::helper('catalog')->__('Delete Attribute Set'), - 'onclick' => 'deleteConfirm(\''. $this->jsQuoteEscape(Mage::helper('catalog')->__('All products of this set will be deleted! Are you sure you want to delete this attribute set?')) . '\', \'' . $this->getUrl('*/*/delete', array('id' => $setId)) . '\')', + 'onclick' => 'deleteConfirm(\'' . $deleteConfirmMessage . '\', \'' . $deleteUrl . '\')', 'class' => 'delete' ))); diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Newpass.php b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Newpass.php index 5a354af54a..509280b932 100644 --- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Newpass.php +++ b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Newpass.php @@ -45,7 +45,11 @@ public function render(Varien_Data_Form_Element_Abstract $element) { $html = ''; $html .= '' . $element->getLabelHtml() . ''; - $html .= '' . $element->getElementHtml() . ''; + $html .= '' . $element->getElementHtml(); + if ($element->getNote()) { + $html .= '

' . $element->getNote() . '

'; + } + $html .= ''; $html .= '' . "\n"; $html .= ''; $html .= ''; diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Account.php b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Account.php index c9a0be0a17..05afa727ab 100644 --- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Account.php +++ b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Account.php @@ -163,6 +163,7 @@ function(v, elem){ } } + $minPasswordLength = Mage::getModel('customer/customer')->getMinPasswordLength(); if ($customer->getId()) { if (!$customer->isReadonly()) { // Add password management fieldset @@ -175,7 +176,9 @@ function(v, elem){ array( 'label' => Mage::helper('customer')->__('New Password'), 'name' => 'new_password', - 'class' => 'validate-new-password' + 'class' => 'validate-new-password min-pass-length-' . $minPasswordLength, + 'note' => Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', $minPasswordLength), ) ); $field->setRenderer($this->getLayout()->createBlock('adminhtml/customer_edit_renderer_newpass')); @@ -224,9 +227,11 @@ function(v, elem){ $field = $newFieldset->addField('password', 'text', array( 'label' => Mage::helper('customer')->__('Password'), - 'class' => 'input-text required-entry validate-password', + 'class' => 'input-text required-entry validate-password min-pass-length-' . $minPasswordLength, 'name' => 'password', - 'required' => true + 'required' => true, + 'note' => Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', $minPasswordLength), ) ); $field->setRenderer($this->getLayout()->createBlock('adminhtml/customer_edit_renderer_newpass')); diff --git a/app/code/core/Mage/Adminhtml/Block/Newsletter/Queue/Preview.php b/app/code/core/Mage/Adminhtml/Block/Newsletter/Queue/Preview.php index ff437b3065..b67829209b 100644 --- a/app/code/core/Mage/Adminhtml/Block/Newsletter/Queue/Preview.php +++ b/app/code/core/Mage/Adminhtml/Block/Newsletter/Queue/Preview.php @@ -75,6 +75,9 @@ protected function _toHtml() $templateProcessed = "
" . htmlspecialchars($templateProcessed) . "
"; } + $templateProcessed = Mage::getSingleton('core/input_filter_maliciousCode') + ->linkFilter($templateProcessed); + Varien_Profiler::stop("newsletter_queue_proccessing"); return $templateProcessed; diff --git a/app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Edit.php b/app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Edit.php index fae5a1adb9..a51832dde8 100644 --- a/app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Edit.php +++ b/app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Edit.php @@ -315,7 +315,7 @@ public function isTextType() */ public function getDeleteUrl() { - return $this->getUrl('*/*/delete', array('id' => $this->getRequest()->getParam('id'))); + return $this->getUrlSecure('*/*/delete', array('id' => $this->getRequest()->getParam('id'))); } /** diff --git a/app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Preview.php b/app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Preview.php index fb580619ec..0da27fd020 100644 --- a/app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Preview.php +++ b/app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Preview.php @@ -74,6 +74,9 @@ protected function _toHtml() $templateProcessed = "
" . htmlspecialchars($templateProcessed) . "
"; } + $templateProcessed = Mage::getSingleton('core/input_filter_maliciousCode') + ->linkFilter($templateProcessed); + Varien_Profiler::stop("newsletter_template_proccessing"); return $templateProcessed; diff --git a/app/code/core/Mage/Adminhtml/Block/Permissions/Tab/Useredit.php b/app/code/core/Mage/Adminhtml/Block/Permissions/Tab/Useredit.php index fc3cef88fd..6879c81e46 100644 --- a/app/code/core/Mage/Adminhtml/Block/Permissions/Tab/Useredit.php +++ b/app/code/core/Mage/Adminhtml/Block/Permissions/Tab/Useredit.php @@ -85,6 +85,7 @@ protected function _prepareForm() ) ); + $minPasswordLength = Mage::getModel('customer/customer')->getMinPasswordLength(); if ($user->getUserId()) { $fieldset->addField('password', 'password', array( @@ -92,7 +93,9 @@ protected function _prepareForm() 'label' => Mage::helper('adminhtml')->__('New Password'), 'id' => 'new_pass', 'title' => Mage::helper('adminhtml')->__('New Password'), - 'class' => 'input-text validate-password', + 'class' => 'input-text validate-password min-pass-length-' . $minPasswordLength, + 'note' => Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', $minPasswordLength), ) ); @@ -112,8 +115,10 @@ protected function _prepareForm() 'label' => Mage::helper('adminhtml')->__('Password'), 'id' => 'customer_pass', 'title' => Mage::helper('adminhtml')->__('Password'), - 'class' => 'input-text required-entry validate-password', + 'class' => 'input-text required-entry validate-password min-pass-length-' . $minPasswordLength, 'required' => true, + 'note' => Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', $minPasswordLength), ) ); $fieldset->addField('confirmation', 'password', diff --git a/app/code/core/Mage/Adminhtml/Block/Permissions/User/Edit/Tab/Main.php b/app/code/core/Mage/Adminhtml/Block/Permissions/User/Edit/Tab/Main.php index 5edc53fdc4..a93d308e46 100644 --- a/app/code/core/Mage/Adminhtml/Block/Permissions/User/Edit/Tab/Main.php +++ b/app/code/core/Mage/Adminhtml/Block/Permissions/User/Edit/Tab/Main.php @@ -97,13 +97,16 @@ protected function _prepareForm() 'required' => true, )); + $minAdminPasswordLength = Mage::getModel('admin/user')->getMinAdminPasswordLength(); if ($model->getUserId()) { $fieldset->addField('password', 'password', array( 'name' => 'new_password', 'label' => Mage::helper('adminhtml')->__('New Password'), 'id' => 'new_pass', 'title' => Mage::helper('adminhtml')->__('New Password'), - 'class' => 'input-text validate-admin-password', + 'class' => 'input-text validate-admin-password min-admin-pass-length-' . $minAdminPasswordLength, + 'note' => Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', $minAdminPasswordLength), )); $fieldset->addField('confirmation', 'password', array( @@ -114,15 +117,18 @@ protected function _prepareForm() )); } else { - $fieldset->addField('password', 'password', array( + $fieldset->addField('password', 'password', array( 'name' => 'password', 'label' => Mage::helper('adminhtml')->__('Password'), 'id' => 'customer_pass', 'title' => Mage::helper('adminhtml')->__('Password'), - 'class' => 'input-text required-entry validate-admin-password', + 'class' => 'input-text required-entry validate-admin-password min-admin-pass-length-' + . $minAdminPasswordLength, 'required' => true, + 'note' => Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', $minAdminPasswordLength), )); - $fieldset->addField('confirmation', 'password', array( + $fieldset->addField('confirmation', 'password', array( 'name' => 'password_confirmation', 'label' => Mage::helper('adminhtml')->__('Password Confirmation'), 'id' => 'confirmation', diff --git a/app/code/core/Mage/Adminhtml/Block/Sales/Order/View.php b/app/code/core/Mage/Adminhtml/Block/Sales/Order/View.php index ea97b9890d..ec642e203e 100644 --- a/app/code/core/Mage/Adminhtml/Block/Sales/Order/View.php +++ b/app/code/core/Mage/Adminhtml/Block/Sales/Order/View.php @@ -246,7 +246,7 @@ public function getEmailUrl() public function getCancelUrl() { - return $this->getUrl('*/*/cancel'); + return $this->getUrlSecure('*/*/cancel'); } public function getInvoiceUrl() diff --git a/app/code/core/Mage/Adminhtml/Block/System/Account/Edit/Form.php b/app/code/core/Mage/Adminhtml/Block/System/Account/Edit/Form.php index 509cc8278d..0883169ce3 100644 --- a/app/code/core/Mage/Adminhtml/Block/System/Account/Edit/Form.php +++ b/app/code/core/Mage/Adminhtml/Block/System/Account/Edit/Form.php @@ -90,11 +90,14 @@ protected function _prepareForm() ) ); + $minAdminPasswordLength = Mage::getModel('admin/user')->getMinAdminPasswordLength(); $fieldset->addField('password', 'password', array( 'name' => 'new_password', 'label' => Mage::helper('adminhtml')->__('New Password'), 'title' => Mage::helper('adminhtml')->__('New Password'), - 'class' => 'input-text validate-admin-password', + 'class' => 'input-text validate-admin-password min-admin-pass-length-' . $minAdminPasswordLength, + 'note' => Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', $minAdminPasswordLength), ) ); diff --git a/app/code/core/Mage/Adminhtml/Block/System/Email/Template/Edit.php b/app/code/core/Mage/Adminhtml/Block/System/Email/Template/Edit.php index b55cef9017..b099dc1939 100644 --- a/app/code/core/Mage/Adminhtml/Block/System/Email/Template/Edit.php +++ b/app/code/core/Mage/Adminhtml/Block/System/Email/Template/Edit.php @@ -267,7 +267,7 @@ public function isTextType() */ public function getDeleteUrl() { - return $this->getUrl('*/*/delete', array('_current' => true)); + return $this->getUrlSecure('*/*/delete', array('_current' => true)); } /** diff --git a/app/code/core/Mage/Adminhtml/Block/Widget/Grid.php b/app/code/core/Mage/Adminhtml/Block/Widget/Grid.php index 57b25a37b3..0331712b43 100644 --- a/app/code/core/Mage/Adminhtml/Block/Widget/Grid.php +++ b/app/code/core/Mage/Adminhtml/Block/Widget/Grid.php @@ -464,7 +464,7 @@ protected function _addColumnFilterToCollection($column) { if ($this->getCollection()) { $field = ( $column->getFilterIndex() ) ? $column->getFilterIndex() : $column->getIndex(); - if ($column->getFilterConditionCallback()) { + if ($column->getFilterConditionCallback() && $column->getFilterConditionCallback()[0] instanceof self) { call_user_func($column->getFilterConditionCallback(), $this->getCollection(), $column); } else { $cond = $column->getFilter()->getCondition(); diff --git a/app/code/core/Mage/Adminhtml/Model/Config/Data.php b/app/code/core/Mage/Adminhtml/Model/Config/Data.php index 90ab946160..4d5cc62f00 100644 --- a/app/code/core/Mage/Adminhtml/Model/Config/Data.php +++ b/app/code/core/Mage/Adminhtml/Model/Config/Data.php @@ -34,6 +34,10 @@ class Mage_Adminhtml_Model_Config_Data extends Varien_Object { + const SCOPE_DEFAULT = 'default'; + const SCOPE_WEBSITES = 'websites'; + const SCOPE_STORES = 'stores'; + /** * Config data for sections * @@ -268,15 +272,15 @@ protected function _validate() protected function _getScope() { if ($this->getStore()) { - $scope = 'stores'; + $scope = self::SCOPE_STORES; $scopeId = (int)Mage::getConfig()->getNode('stores/' . $this->getStore() . '/system/store/id'); $scopeCode = $this->getStore(); } elseif ($this->getWebsite()) { - $scope = 'websites'; + $scope = self::SCOPE_WEBSITES; $scopeId = (int)Mage::getConfig()->getNode('websites/' . $this->getWebsite() . '/system/website/id'); $scopeCode = $this->getWebsite(); } else { - $scope = 'default'; + $scope = self::SCOPE_DEFAULT; $scopeId = 0; $scopeCode = ''; } @@ -363,4 +367,100 @@ public function getConfigRoot() } return $this->_configRoot; } + + /** + * Secure set groups + * + * @param array $groups + * @return Mage_Adminhtml_Model_Config_Data + * @throws Mage_Core_Exception + */ + public function setGroupsSecure($groups) + { + $this->_validate(); + $this->_getScope(); + + $groupsSecure = array(); + $section = $this->getSection(); + $sections = Mage::getModel('adminhtml/config')->getSections(); + + foreach ($groups as $group => $groupData) { + $groupConfig = $sections->descend($section . '/groups/' . $group); + foreach ($groupData['fields'] as $field => $fieldData) { + $fieldName = $field; + if ($groupConfig && $groupConfig->clone_fields) { + if ($groupConfig->clone_model) { + $cloneModel = Mage::getModel((string)$groupConfig->clone_model); + } else { + Mage::throwException( + $this->__('Config form fieldset clone model required to be able to clone fields') + ); + } + foreach ($cloneModel->getPrefixes() as $prefix) { + if (strpos($field, $prefix['field']) === 0) { + $field = substr($field, strlen($prefix['field'])); + } + } + } + $fieldConfig = $sections->descend($section . '/groups/' . $group . '/fields/' . $field); + if (!$fieldConfig) { + $node = $sections->xpath($section . '//' . $group . '[@type="group"]/fields/' . $field); + if ($node) { + $fieldConfig = $node[0]; + } + } + if (($groupConfig ? !$groupConfig->dynamic_group : true) && !$this->_isValidField($fieldConfig)) { + Mage::throwException(Mage::helper('adminhtml')->__('Wrong field specified.')); + } + $groupsSecure[$group]['fields'][$fieldName] = $fieldData; + } + } + + $this->setGroups($groupsSecure); + + return $this; + } + + /** + * Check field visibility by scope + * + * @param Mage_Core_Model_Config_Element $field + * @return bool + */ + protected function _isValidField($field) + { + if (!$field) { + return false; + } + + switch ($this->getScope()) { + case self::SCOPE_DEFAULT: + return (bool)(int)$field->show_in_default; + break; + case self::SCOPE_WEBSITES: + return (bool)(int)$field->show_in_website; + break; + case self::SCOPE_STORES: + return (bool)(int)$field->show_in_store; + break; + } + + return true; + } + + /** + * Select group setter is secure or not based on the configuration + * + * @param array $groups + * @return Mage_Adminhtml_Model_Config_Data + * @throws Mage_Core_Exception + */ + public function setGroupsSelector($groups) + { + if (Mage::getStoreConfigFlag('admin/security/secure_system_configuration_save_disabled')) { + return $this->setGroups($groups); + } + + return $this->setGroupsSecure($groups); + } } diff --git a/app/code/core/Mage/Adminhtml/Model/LayoutUpdate/Validator.php b/app/code/core/Mage/Adminhtml/Model/LayoutUpdate/Validator.php index 2a160e9d52..aceabd17d8 100644 --- a/app/code/core/Mage/Adminhtml/Model/LayoutUpdate/Validator.php +++ b/app/code/core/Mage/Adminhtml/Model/LayoutUpdate/Validator.php @@ -53,33 +53,26 @@ class Mage_Adminhtml_Model_LayoutUpdate_Validator extends Zend_Validate_Abstract * * @var array */ - protected $_disallowedXPathExpressions = array( - '*//template', - '*//@template', - '//*[@method=\'setTemplate\']', - '//*[@method=\'setDataUsingMethod\']//*[contains(translate(text(), - \'ABCDEFGHIJKLMNOPQRSTUVWXYZ\', \'abcdefghijklmnopqrstuvwxyz\'), \'template\')]/../*', - ); + protected $_disallowedXPathExpressions = array(); /** * Disallowed template name * * @var array */ - protected $_disallowedBlock = array( - 'Mage_Install_Block_End', - 'Mage_Rss_Block_Order_New', - 'Mage_Core_Block_Template_Zend', - ); + protected $_disallowedBlock = array(); + + /** + * @var Mage_Core_Model_Layout_Validator + */ + protected $_validator; /** * Protected expressions * * @var array */ - protected $_protectedExpressions = array( - self::PROTECTED_ATTR_HELPER_IN_TAG_ACTION_VAR => '//action/*[@helper]', - ); + protected $_protectedExpressions = array(); /** * Construct @@ -87,27 +80,17 @@ class Mage_Adminhtml_Model_LayoutUpdate_Validator extends Zend_Validate_Abstract public function __construct() { $this->_initMessageTemplates(); + $this->_initValidator(); } /** - * Initialize messages templates with translating + * Returns array of validation failure messages * - * @return Mage_Adminhtml_Model_LayoutUpdate_Validator + * @return array */ - protected function _initMessageTemplates() + public function getMessages() { - if (!$this->_messageTemplates) { - $this->_messageTemplates = array( - self::PROTECTED_ATTR_HELPER_IN_TAG_ACTION_VAR => - Mage::helper('adminhtml')->__('Helper attributes should not be used in custom layout updates.'), - self::XML_INVALID => Mage::helper('adminhtml')->__('XML data is invalid.'), - self::INVALID_TEMPLATE_PATH => Mage::helper('adminhtml')->__( - 'Invalid template path used in layout update.' - ), - self::INVALID_BLOCK_NAME => Mage::helper('adminhtml')->__('Disallowed block name for frontend.'), - ); - } - return $this; + return $this->_validator->getMessages(); } /** @@ -124,43 +107,42 @@ protected function _initMessageTemplates() */ public function isValid($value) { - if (is_string($value)) { - $value = trim($value); - try { - //wrap XML value in the "config" tag because config cannot - //contain multiple root tags - $value = new Varien_Simplexml_Element('' . $value . ''); - } catch (Exception $e) { - $this->_error(self::XML_INVALID); - return false; - } - } elseif (!($value instanceof Varien_Simplexml_Element)) { - throw new Exception( - Mage::helper('adminhtml')->__('XML object is not instance of "Varien_Simplexml_Element".')); - } + return $this->_validator->isValid($value); + } - if ($value->xpath($this->_getXpathBlockValidationExpression())) { - $this->_error(self::INVALID_BLOCK_NAME); - return false; - } - // if layout update declare custom templates then validate their paths - if ($templatePaths = $value->xpath($this->_getXpathValidationExpression())) { - try { - $this->_validateTemplatePath($templatePaths); - } catch (Exception $e) { - $this->_error(self::INVALID_TEMPLATE_PATH); - return false; - } - } - $this->_setValue($value); + /** + * Initialize the validator instance with populated template messages + */ + protected function _initValidator() + { + $this->_validator = Mage::getModel('core/layout_validator'); + $this->_disallowedBlock = $this->_validator->getDisallowedBlocks(); + $this->_protectedExpressions = $this->_validator->getProtectedExpressions(); + $this->_disallowedXPathExpressions = $this->_validator->getDisallowedXpathValidationExpression(); + $this->_validator->setMessages($this->_messageTemplates); + } - foreach ($this->_protectedExpressions as $key => $xpr) { - if ($this->_value->xpath($xpr)) { - $this->_error($key); - return false; - } + /** + * Initialize messages templates with translating + * + * @return Mage_Adminhtml_Model_LayoutUpdate_Validator + */ + protected function _initMessageTemplates() + { + if (!$this->_messageTemplates) { + $this->_messageTemplates = array( + self::PROTECTED_ATTR_HELPER_IN_TAG_ACTION_VAR => + Mage::helper('adminhtml')->__('Helper attributes should not be used in custom layout updates.'), + self::XML_INVALID => Mage::helper('adminhtml')->__('XML data is invalid.'), + self::INVALID_TEMPLATE_PATH => Mage::helper('adminhtml')->__( + 'Invalid template path used in layout update.' + ), + self::INVALID_BLOCK_NAME => Mage::helper('adminhtml')->__('Disallowed block name for frontend.'), + Mage_Core_Model_Layout_Validator::INVALID_XML_OBJECT_EXCEPTION => + Mage::helper('adminhtml')->__('XML object is not instance of "Varien_Simplexml_Element".'), + ); } - return true; + return $this; } /** @@ -168,8 +150,9 @@ public function isValid($value) * * @return string xPath for validate incorrect path to template */ - protected function _getXpathValidationExpression() { - return implode(" | ", $this->_disallowedXPathExpressions); + protected function _getXpathValidationExpression() + { + return $this->_validator->getXpathValidationExpression(); } /** @@ -177,16 +160,9 @@ protected function _getXpathValidationExpression() { * * @return string xPath for validate incorrect block name */ - protected function _getXpathBlockValidationExpression() { - $xpath = ""; - if (count($this->_disallowedBlock)) { - foreach ($this->_disallowedBlock as $key => $value) { - $xpath .= $key > 0 ? " | " : ''; - $xpath .= "//block[translate(@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = "; - $xpath .= "translate('$value', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')]"; - } - } - return $xpath; + protected function _getXpathBlockValidationExpression() + { + return $this->_validator->getXpathBlockValidationExpression(); } /** @@ -197,14 +173,6 @@ protected function _getXpathBlockValidationExpression() { */ protected function _validateTemplatePath(array $templatePaths) { - /**@var $path Varien_Simplexml_Element */ - foreach ($templatePaths as $path) { - if ($path->hasChildren()) { - $path = stripcslashes(trim((string) $path->children(), '"')); - } - if (strpos($path, '..' . DS) !== false) { - throw new Exception(); - } - } + $this->_validator->validateTemplatePath($templatePaths); } } diff --git a/app/code/core/Mage/Adminhtml/Model/Sales/Order/Create.php b/app/code/core/Mage/Adminhtml/Model/Sales/Order/Create.php index 9faffae798..5a8b0ef3a1 100644 --- a/app/code/core/Mage/Adminhtml/Model/Sales/Order/Create.php +++ b/app/code/core/Mage/Adminhtml/Model/Sales/Order/Create.php @@ -1557,7 +1557,7 @@ public function createOrder() if ((!$customer->getId() || !$customer->isInStore($this->getSession()->getStore())) && !$quote->getCustomerIsGuest() ) { - $customer->setCreatedAt($order->getCreatedAt()); + $customer->setCreatedAt($order->getCreatedAtStoreDate()); $customer ->save() ->sendNewAccountEmail('registered', '', $quote->getStoreId());; diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Locale.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Locale.php index 04dcfd8134..63429a21a4 100644 --- a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Locale.php +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Locale.php @@ -45,6 +45,39 @@ protected function _beforeSave() $allCurrenciesOptions = Mage::getSingleton('adminhtml/system_config_source_locale_currency_all') ->toOptionArray(true); + if (!function_exists('array_column')) { + function array_column(array $allCurrenciesOptions, $columnKey, $indexKey = null) + { + $array = array(); + foreach ($allCurrenciesOptions as $allCurrenciesOption) { + if (!array_key_exists($columnKey, $allCurrenciesOption)) { + Mage::getSingleton('adminhtml/session')->addError( + Mage::helper('adminhtml')->__("Key %s does not exist in array", $columnKey) + ); + return false; + } + if (is_null($indexKey)) { + $array[] = $allCurrenciesOption[$columnKey]; + } else { + if (!array_key_exists($indexKey, $allCurrenciesOption)) { + Mage::getSingleton('adminhtml/session')->addError( + Mage::helper('adminhtml')->__("Key %s does not exist in array", $indexKey) + ); + return false; + } + if (!is_scalar($allCurrenciesOption[$indexKey])) { + Mage::getSingleton('adminhtml/session')->addError( + Mage::helper('adminhtml')->__("Key %s does not contain scalar value", $indexKey) + ); + return false; + } + $array[$allCurrenciesOption[$indexKey]] = $allCurrenciesOption[$columnKey]; + } + } + return $array; + } + } + $allCurrenciesValues = array_column($allCurrenciesOptions, 'value'); foreach ($this->getValue() as $currency) { diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Passwordlength.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Passwordlength.php new file mode 100644 index 0000000000..a2793373a8 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Passwordlength.php @@ -0,0 +1,50 @@ + + */ +class Mage_Adminhtml_Model_System_Config_Backend_Passwordlength extends Mage_Core_Model_Config_Data +{ + /** + * Before save processing + * + * @throws Mage_Core_Exception + * @return Mage_Adminhtml_Model_System_Config_Backend_Passwordlength + */ + protected function _beforeSave() + { + if ((int)$this->getValue() < Mage_Core_Model_App::ABSOLUTE_MIN_PASSWORD_LENGTH) { + Mage::throwException(Mage::helper('adminhtml') + ->__('Password must be at least of %d characters.', Mage_Core_Model_App::ABSOLUTE_MIN_PASSWORD_LENGTH)); + } + return $this; + } +} diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Currency/Service.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Currency/Service.php index f8d2aa9ec7..b0ae11091e 100644 --- a/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Currency/Service.php +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Currency/Service.php @@ -33,8 +33,12 @@ public function toOptionArray($isMultiselect) { if (!$this->_options) { $services = Mage::getConfig()->getNode('global/currency/import/services')->asArray(); + $currencyConfig = Mage::getStoreConfig('currency'); $this->_options = array(); - foreach( $services as $_code => $_options ) { + foreach ($services as $_code => $_options) { + if (isset($currencyConfig[$_code]['active']) && '0' === $currencyConfig[$_code]['active']) { + continue; + } $this->_options[] = array( 'label' => $_options['name'], 'value' => $_code, diff --git a/app/code/core/Mage/Adminhtml/controllers/Api/UserController.php b/app/code/core/Mage/Adminhtml/controllers/Api/UserController.php index a6d475756d..2ad3d086dc 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Api/UserController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Api/UserController.php @@ -123,6 +123,19 @@ public function saveAction() $this->getRequest()->setParam('current_password', null); unset($data['current_password']); $result = $this->_validateCurrentPassword($currentPassword); + $model->setData($data); + + if ($model->hasNewApiKey() && $model->getNewApiKey() === '') { + $model->unsNewApiKey(); + } + + if ($model->hasApiKeyConfirmation() && $model->getApiKeyConfirmation() === '') { + $model->unsApiKeyConfirmation(); + } + + if (!is_array($result)) { + $result = $model->validate(); + } if (is_array($result)) { foreach ($result as $error) { @@ -138,7 +151,6 @@ public function saveAction() return; } - $model->setData($data); try { $model->save(); if ( $uRoles = $this->getRequest()->getParam('roles', false) ) { diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php index d22cff8f12..9ef2a4a11f 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php @@ -509,4 +509,15 @@ protected function _isAllowed() { return Mage::getSingleton('admin/session')->isAllowed('catalog/categories'); } + + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete'); + return parent::preDispatch(); + } } diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/AttributeController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/AttributeController.php index c390a873e9..e5372435c8 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/AttributeController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/AttributeController.php @@ -253,6 +253,7 @@ public function saveAction() return; } + $data['backend_model'] = $model->getBackendModel(); $data['attribute_code'] = $model->getAttributeCode(); $data['is_user_defined'] = $model->getIsUserDefined(); $data['frontend_input'] = $model->getFrontendInput(); @@ -342,7 +343,7 @@ public function deleteAction() // entity type check $model->load($id); - if ($model->getEntityTypeId() != $this->_entityTypeId) { + if ($model->getEntityTypeId() != $this->_entityTypeId || !$model->getIsUserDefined()) { Mage::getSingleton('adminhtml/session')->addError( Mage::helper('catalog')->__('This attribute cannot be deleted.')); $this->_redirect('*/*/'); diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/SetController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/SetController.php index 40ef549a8c..0ab855e2b6 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/SetController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/SetController.php @@ -208,6 +208,17 @@ public function deleteAction() } } + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete'); + return parent::preDispatch(); + } + /** * Define in register catalog_product entity type code as entityType * diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/SearchController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/SearchController.php index 8a36bc8b6c..e3257fbaeb 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/SearchController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/SearchController.php @@ -125,6 +125,9 @@ public function saveAction() $model->addData($data); $model->setIsProcessed(0); $model->save(); + $this->_getSession()->addSuccess( + Mage::helper('catalog')->__('You saved the search term.') + ); } catch (Mage_Core_Exception $e) { $this->_getSession()->addError($e->getMessage()); @@ -188,6 +191,17 @@ public function massDeleteAction() $this->_redirect('*/*/index'); } + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete', 'massDelete'); + return parent::preDispatch(); + } + protected function _isAllowed() { return Mage::getSingleton('admin/session')->isAllowed('catalog/search'); diff --git a/app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php b/app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php index d217477806..c40f7bd3a7 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php @@ -215,6 +215,17 @@ public function deleteAction() $this->_redirect('*/*/'); } + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete'); + return parent::preDispatch(); + } + /** * Check the permission to run it * diff --git a/app/code/core/Mage/Adminhtml/controllers/CustomerController.php b/app/code/core/Mage/Adminhtml/controllers/CustomerController.php index 0e6e126c74..9c10f1cd86 100644 --- a/app/code/core/Mage/Adminhtml/controllers/CustomerController.php +++ b/app/code/core/Mage/Adminhtml/controllers/CustomerController.php @@ -360,9 +360,15 @@ public function saveAction() } if (!empty($data['account']['new_password'])) { - $newPassword = $data['account']['new_password']; + $newPassword = trim($data['account']['new_password']); if ($newPassword == 'auto') { $newPassword = $customer->generatePassword(); + } else { + $minPasswordLength = Mage::getModel('customer/customer')->getMinPasswordLength(); + if (Mage::helper('core/string')->strlen($newPassword) < $minPasswordLength) { + Mage::throwException(Mage::helper('customer') + ->__('The minimum password length is %s', $minPasswordLength)); + } } $customer->changePassword($newPassword); $customer->sendPasswordReminderEmail(); diff --git a/app/code/core/Mage/Adminhtml/controllers/IndexController.php b/app/code/core/Mage/Adminhtml/controllers/IndexController.php index 3e730f85fe..4c349daf8b 100644 --- a/app/code/core/Mage/Adminhtml/controllers/IndexController.php +++ b/app/code/core/Mage/Adminhtml/controllers/IndexController.php @@ -287,7 +287,8 @@ public function resetPasswordAction() $this->_validateResetPasswordLinkToken($userId, $resetPasswordLinkToken); $data = array( 'userId' => $userId, - 'resetPasswordLinkToken' => $resetPasswordLinkToken + 'resetPasswordLinkToken' => $resetPasswordLinkToken, + 'minAdminPasswordLength' => $this->_getModel('admin/user')->getMinAdminPasswordLength() ); $this->_outTemplate('resetforgottenpassword', $data); } catch (Exception $exception) { @@ -342,7 +343,8 @@ public function resetPasswordPostAction() } $data = array( 'userId' => $userId, - 'resetPasswordLinkToken' => $resetPasswordLinkToken + 'resetPasswordLinkToken' => $resetPasswordLinkToken, + 'minAdminPasswordLength' => $this->_getModel('admin/user')->getMinAdminPasswordLength() ); $this->_outTemplate('resetforgottenpassword', $data); return; @@ -359,7 +361,8 @@ public function resetPasswordPostAction() $this->_getSession()->addError($exception->getMessage()); $data = array( 'userId' => $userId, - 'resetPasswordLinkToken' => $resetPasswordLinkToken + 'resetPasswordLinkToken' => $resetPasswordLinkToken, + 'minAdminPasswordLength' => $this->_getModel('admin/user')->getMinAdminPasswordLength() ); $this->_outTemplate('resetforgottenpassword', $data); return; diff --git a/app/code/core/Mage/Adminhtml/controllers/Newsletter/TemplateController.php b/app/code/core/Mage/Adminhtml/controllers/Newsletter/TemplateController.php index c28df8c192..769b8be536 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Newsletter/TemplateController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Newsletter/TemplateController.php @@ -249,4 +249,15 @@ public function previewAction () $this->getLayout()->getBlock('preview_form')->setFormData($data); $this->renderLayout(); } + + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete'); + return parent::preDispatch(); + } } diff --git a/app/code/core/Mage/Adminhtml/controllers/Permissions/BlockController.php b/app/code/core/Mage/Adminhtml/controllers/Permissions/BlockController.php index 3162e3553d..a43718325f 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Permissions/BlockController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Permissions/BlockController.php @@ -204,6 +204,17 @@ public function blockGridAction() ); } + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete'); + return parent::preDispatch(); + } + /** * Check permissions before allow edit list of blocks * diff --git a/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php b/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php index 7bdbbce2a4..6ce501399d 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php @@ -778,4 +778,15 @@ public function addressSaveAction() $this->_redirect('*/*/'); } } + + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('cancel', 'massCancel'); + return parent::preDispatch(); + } } diff --git a/app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php b/app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php index 4951e6ba74..179e16d955 100644 --- a/app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php +++ b/app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php @@ -161,7 +161,7 @@ public function saveAction() ->setSection($section) ->setWebsite($website) ->setStore($store) - ->setGroups($groups) + ->setGroupsSelector($groups) ->save(); // reinit configuration diff --git a/app/code/core/Mage/Adminhtml/controllers/System/Email/TemplateController.php b/app/code/core/Mage/Adminhtml/controllers/System/Email/TemplateController.php index 4e3de6cbbe..bab1aa8e42 100644 --- a/app/code/core/Mage/Adminhtml/controllers/System/Email/TemplateController.php +++ b/app/code/core/Mage/Adminhtml/controllers/System/Email/TemplateController.php @@ -129,7 +129,7 @@ public function saveAction() } try { - $allowedHtmlTags = ['template_text', 'styles']; + $allowedHtmlTags = ['template_text', 'styles', 'variables']; if (Mage::helper('adminhtml')->hasTags($request->getParams(), $allowedHtmlTags)) { Mage::throwException(Mage::helper('adminhtml')->__('Invalid template data.')); } @@ -229,6 +229,17 @@ public function defaultTemplateAction() $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($template->getData())); } + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete'); + return parent::preDispatch(); + } + /** * Load email template from request * diff --git a/app/code/core/Mage/Adminhtml/controllers/Tax/RuleController.php b/app/code/core/Mage/Adminhtml/controllers/Tax/RuleController.php index 765d2779d6..29b1ae64c9 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Tax/RuleController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Tax/RuleController.php @@ -250,4 +250,15 @@ protected function _getHelperModel($className) { return Mage::helper($className); } + + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete'); + return parent::preDispatch(); + } } diff --git a/app/code/core/Mage/Api/Model/User.php b/app/code/core/Mage/Api/Model/User.php index 954e8c2348..d5800e7c30 100644 --- a/app/code/core/Mage/Api/Model/User.php +++ b/app/code/core/Mage/Api/Model/User.php @@ -342,7 +342,7 @@ public function hasAssigned2Role($user) */ protected function _getEncodedApiKey($apiKey) { - return $this->_getHelper('core')->getHash($apiKey, Mage_Admin_Model_User::HASH_SALT_LENGTH); + return $this->_getHelper('core')->getHashPassword($apiKey, Mage_Admin_Model_User::HASH_SALT_LENGTH); } /** @@ -355,4 +355,75 @@ protected function _getHelper($helperName) { return Mage::helper($helperName); } + + /** + * Validate user attribute values. + * + * @return array|bool + * @throws Zend_Validate_Exception + */ + public function validate() + { + $errors = new ArrayObject(); + + if (!Zend_Validate::is($this->getUsername(), 'NotEmpty')) { + $errors[] = $this->_getHelper('api')->__('User Name is required field.'); + } + + if (!Zend_Validate::is($this->getFirstname(), 'NotEmpty')) { + $errors[] = $this->_getHelper('api')->__('First Name is required field.'); + } + + if (!Zend_Validate::is($this->getLastname(), 'NotEmpty')) { + $errors[] = $this->_getHelper('api')->__('Last Name is required field.'); + } + + if (!Zend_Validate::is($this->getEmail(), 'EmailAddress')) { + $errors[] = $this->_getHelper('api')->__('Please enter a valid email.'); + } + + if ($this->hasNewApiKey()) { + $apiKey = $this->getNewApiKey(); + } elseif ($this->hasApiKey()) { + $apiKey = $this->getApiKey(); + } + + if (isset($apiKey)) { + $minCustomerPasswordLength = $this->_getMinCustomerPasswordLength(); + if (strlen($apiKey) < $minCustomerPasswordLength) { + $errors[] = $this->_getHelper('api') + ->__('Api Key must be at least of %d characters.', $minCustomerPasswordLength); + } + + if (!preg_match('/[a-z]/iu', $apiKey) || !preg_match('/[0-9]/u', $apiKey)) { + $errors[] = $this->_getHelper('api') + ->__('Api Key must include both numeric and alphabetic characters.'); + } + + if ($this->hasApiKeyConfirmation() && $apiKey != $this->getApiKeyConfirmation()) { + $errors[] = $this->_getHelper('api')->__('Api Key confirmation must be same as Api Key.'); + } + } + + if ($this->userExists()) { + $errors[] = $this->_getHelper('api') + ->__('A user with the same user name or email already exists.'); + } + + if (count($errors) === 0) { + return true; + } + + return (array) $errors; + } + + /** + * Get min customer password length + * + * @return int + */ + protected function _getMinCustomerPasswordLength() + { + return Mage::getSingleton('customer/customer')->getMinPasswordLength(); + } } diff --git a/app/code/core/Mage/Api/etc/config.xml b/app/code/core/Mage/Api/etc/config.xml index a69229b3b8..fb28d8d3a3 100644 --- a/app/code/core/Mage/Api/etc/config.xml +++ b/app/code/core/Mage/Api/etc/config.xml @@ -28,7 +28,7 @@ - 1.6.0.1 + 1.6.0.2 diff --git a/app/code/core/Mage/Api/sql/api_setup/mysql4-upgrade-1.6.0.1-1.6.0.2.php b/app/code/core/Mage/Api/sql/api_setup/mysql4-upgrade-1.6.0.1-1.6.0.2.php new file mode 100644 index 0000000000..63b039e054 --- /dev/null +++ b/app/code/core/Mage/Api/sql/api_setup/mysql4-upgrade-1.6.0.1-1.6.0.2.php @@ -0,0 +1,41 @@ +startSetup(); + +$this->getConnection()->changeColumn( + $this->getTable('api/user'), + 'api_key', + 'api_key', + array( + 'type' => Varien_Db_Ddl_Table::TYPE_TEXT, + 'length' => 255, + 'comment' => 'Api key' + ) +); + +$this->endSetup(); diff --git a/app/code/core/Mage/Authorizenet/Model/Directpost.php b/app/code/core/Mage/Authorizenet/Model/Directpost.php index 196f6d1082..3b5881b23e 100644 --- a/app/code/core/Mage/Authorizenet/Model/Directpost.php +++ b/app/code/core/Mage/Authorizenet/Model/Directpost.php @@ -389,7 +389,8 @@ public function setResponseData(array $postData) public function validateResponse() { $response = $this->getResponse(); - $hashConfigKey = !empty($response->getData('x_SHA2_Hash')) ? 'signature_key' : 'trans_md5'; + $xSHA2Hash = $response->getData('x_SHA2_Hash'); + $hashConfigKey = !empty($xSHA2Hash) ? 'signature_key' : 'trans_md5'; //hash check if (!$this->getConfigData($hashConfigKey) diff --git a/app/code/core/Mage/Authorizenet/Model/Directpost/Request.php b/app/code/core/Mage/Authorizenet/Model/Directpost/Request.php index 09d5831e26..6d93ccc7a6 100644 --- a/app/code/core/Mage/Authorizenet/Model/Directpost/Request.php +++ b/app/code/core/Mage/Authorizenet/Model/Directpost/Request.php @@ -186,7 +186,8 @@ public function setDataFromOrder(Mage_Sales_Model_Order $order, Mage_Authorizene public function signRequestData() { $fpTimestamp = time(); - if (!empty($this->_getSignatureKey())) { + $signatureKey = $this->_getSignatureKey(); + if (!empty($signatureKey)) { $hash = $this->_generateSha2RequestSign( $this->getXLogin(), $this->_getSignatureKey(), diff --git a/app/code/core/Mage/Authorizenet/Model/Directpost/Response.php b/app/code/core/Mage/Authorizenet/Model/Directpost/Response.php index 98bc80dc87..e7af3d1ede 100644 --- a/app/code/core/Mage/Authorizenet/Model/Directpost/Response.php +++ b/app/code/core/Mage/Authorizenet/Model/Directpost/Response.php @@ -56,14 +56,17 @@ public function generateHash($merchantMd5, $merchantApiLogin, $amount, $transact */ public function isValidHash($storedHash, $merchantApiLogin) { - if (empty($this->getData('x_amount'))) { + $xAmount = $this->getData('x_amount'); + if (empty($xAmount)) { $this->setData('x_amount', '0.00'); } - if (!empty($this->getData('x_SHA2_Hash'))) { + $xSHA2Hash = $this->getData('x_SHA2_Hash'); + $xMD5Hash = $this->getData('x_MD5_Hash'); + if (!empty($xSHA2Hash)) { $hash = $this->generateSha2Hash($storedHash); return $hash == $this->getData('x_SHA2_Hash'); - } elseif (!empty($this->getData('x_MD5_Hash'))) { + } elseif (!empty($xMD5Hash)) { $hash = $this->generateHash($storedHash, $merchantApiLogin, $this->getXAmount(), $this->getXTransId()); return $hash == $this->getData('x_MD5_Hash'); } diff --git a/app/code/core/Mage/Catalog/Block/Product/Abstract.php b/app/code/core/Mage/Catalog/Block/Product/Abstract.php index 3cbb1e6977..7e11331065 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Abstract.php +++ b/app/code/core/Mage/Catalog/Block/Product/Abstract.php @@ -124,21 +124,7 @@ public function getProductHelper() */ public function getAddToCartUrl($product, $additional = array()) { - if (!$product->getTypeInstance(true)->hasRequiredOptions($product)) { - return $this->helper('checkout/cart')->getAddUrl($product, $additional); - } - $additional = array_merge( - $additional, - array(Mage_Core_Model_Url::FORM_KEY => $this->_getSingletonModel('core/session')->getFormKey()) - ); - if (!isset($additional['_escape'])) { - $additional['_escape'] = true; - } - if (!isset($additional['_query'])) { - $additional['_query'] = array(); - } - $additional['_query']['options'] = 'cart'; - return $this->getProductUrl($product, $additional); + return $this->getAddToCartUrlCustom($product, $additional); } /** @@ -164,15 +150,7 @@ protected function _getSingletonModel($className, $arguments = array()) */ public function getSubmitUrl($product, $additional = array()) { - $submitRouteData = $this->getData('submit_route_data'); - if ($submitRouteData) { - $route = $submitRouteData['route']; - $params = isset($submitRouteData['params']) ? $submitRouteData['params'] : array(); - $submitUrl = $this->getUrl($route, array_merge($params, $additional)); - } else { - $submitUrl = $this->getAddToCartUrl($product, $additional); - } - return $submitUrl; + return $this->getSubmitUrlCustom($product, $additional); } /** @@ -183,7 +161,7 @@ public function getSubmitUrl($product, $additional = array()) */ public function getAddToWishlistUrl($product) { - return $this->helper('wishlist')->getAddUrl($product); + return $this->getAddToWishlistUrlCustom($product); } /** @@ -194,7 +172,7 @@ public function getAddToWishlistUrl($product) */ public function getAddToCompareUrl($product) { - return $this->helper('catalog/product_compare')->getAddUrl($product); + return $this->getAddToCompareUrlCustom($product); } /** @@ -650,6 +628,36 @@ public function displayProductStockStatus() return (boolean)$statusInfo->getDisplayStatus(); } + /** + * Return link to Add to Wishlist with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param bool $addFormKey + * @return string + */ + public function getAddToWishlistUrlCustom($product, $addFormKey = true) + { + if (!$addFormKey) { + return $this->helper('wishlist')->getAddUrlWithCustomParams($product, array(), false); + } + return $this->helper('wishlist')->getAddUrl($product); + } + + /** + * Retrieve Add Product to Compare Products List URL with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param bool $addFormKey + * @return string + */ + public function getAddToCompareUrlCustom($product, $addFormKey = true) + { + if (!$addFormKey) { + return $this->helper('catalog/product_compare')->getAddUrlCustom($product, false); + } + return $this->helper('catalog/product_compare')->getAddUrl($product); + } + /** * If exists price template block, retrieve price blocks from it * @@ -669,4 +677,64 @@ protected function _prepareLayout() return $this; } + + /** + * Retrieve url for add product to cart with or without Form Key + * Will return product view page URL if product has required options + * + * @param Mage_Catalog_Model_Product $product + * @param array $additional + * @param bool $addFormKey + * @return string + */ + public function getAddToCartUrlCustom($product, $additional = array(), $addFormKey = true) + { + if (!$product->getTypeInstance(true)->hasRequiredOptions($product)) { + if (!$addFormKey) { + return $this->helper('checkout/cart')->getAddUrlCustom($product, $additional, false); + } + return $this->helper('checkout/cart')->getAddUrl($product, $additional); + } + if ($addFormKey) { + $additional = array_merge( + $additional, + array(Mage_Core_Model_Url::FORM_KEY => $this->_getSingletonModel('core/session')->getFormKey()) + ); + } + if (!isset($additional['_escape'])) { + $additional['_escape'] = true; + } + if (!isset($additional['_query'])) { + $additional['_query'] = array(); + } + $additional['_query']['options'] = 'cart'; + return $this->getProductUrl($product, $additional); + } + + /** + * Retrieves url for form submitting: + * some objects can use setSubmitRouteData() to set route and params for form submitting, + * otherwise default url will be used with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param array $additional + * @param bool $addFormKey + * @return string + */ + public function getSubmitUrlCustom($product, $additional = array(), $addFormKey = true) + { + $submitRouteData = $this->getData('submit_route_data'); + if ($submitRouteData) { + $route = $submitRouteData['route']; + $params = isset($submitRouteData['params']) ? $submitRouteData['params'] : array(); + $submitUrl = $this->getUrl($route, array_merge($params, $additional)); + } else { + if ($addFormKey) { + $submitUrl = $this->getAddToCartUrl($product, $additional); + } else { + $submitUrl = $this->getAddToCartUrlCustom($product, $additional, false); + } + } + return $submitUrl; + } } diff --git a/app/code/core/Mage/Catalog/Block/Product/Compare/List.php b/app/code/core/Mage/Catalog/Block/Product/Compare/List.php index e347dd52c8..4d7358acba 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Compare/List.php +++ b/app/code/core/Mage/Catalog/Block/Product/Compare/List.php @@ -77,14 +77,7 @@ class Mage_Catalog_Block_Product_Compare_List extends Mage_Catalog_Block_Product */ public function getAddToWishlistUrl($product) { - $continueUrl = Mage::helper('core')->urlEncode($this->getUrl('customer/account')); - $urlParamName = Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED; - - $params = array( - $urlParamName => $continueUrl - ); - - return $this->helper('wishlist')->getAddUrlWithParams($product, $params); + return $this->getAddToWishlistUrlCustom($product); } /** @@ -195,4 +188,26 @@ public function setCustomerId($id) $this->_customerId = $id; return $this; } + + /** + * Retrieve url for adding product to wishlist with params with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param bool $addFormKey + * @return string + */ + public function getAddToWishlistUrlCustom($product, $addFormKey = true) + { + $continueUrl = Mage::helper('core')->urlEncode($this->getUrl('customer/account')); + $params = array( + Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $continueUrl + ); + + if (!$addFormKey) { + return $this->helper('wishlist')->getAddUrlWithCustomParams($product, $params, false); + } + + return $this->helper('wishlist')->getAddUrlWithParams($product, $params); + } + } diff --git a/app/code/core/Mage/Catalog/Block/Product/Price.php b/app/code/core/Mage/Catalog/Block/Product/Price.php index fe31dcd528..653a5ad010 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Price.php +++ b/app/code/core/Mage/Catalog/Block/Product/Price.php @@ -179,7 +179,7 @@ public function getTierPrices($product = null, $parent = null) */ public function getAddToCartUrl($product, $additional = array()) { - return $this->helper('checkout/cart')->getAddUrl($product, $additional); + return $this->getAddToCartUrlCustom($product, $additional); } /** @@ -229,4 +229,20 @@ public function getProductAttribute($attribute) { return $this->getProduct()->getResource()->getAttribute($attribute); } + + /** + * Retrieve url for direct adding product to cart with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param array $additional + * @param bool $addFormKey + * @return string + */ + public function getAddToCartUrlCustom($product, $additional = array(), $addFormKey = true) + { + if (!$addFormKey) { + return $this->helper('checkout/cart')->getAddUrlCustom($product, $additional, false); + } + return $this->helper('checkout/cart')->getAddUrl($product, $additional); + } } diff --git a/app/code/core/Mage/Catalog/Block/Product/View.php b/app/code/core/Mage/Catalog/Block/Product/View.php index 14b44e6635..20ded710ca 100644 --- a/app/code/core/Mage/Catalog/Block/Product/View.php +++ b/app/code/core/Mage/Catalog/Block/Product/View.php @@ -113,19 +113,7 @@ public function canEmailToFriend() */ public function getAddToCartUrl($product, $additional = array()) { - if ($this->hasCustomAddToCartUrl()) { - return $this->getCustomAddToCartUrl(); - } - - if ($this->getRequest()->getParam('wishlist_next')) { - $additional['wishlist_next'] = 1; - } - - $addUrlKey = Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED; - $addUrlValue = Mage::getUrl('*/*/*', array('_use_rewrite' => true, '_current' => true)); - $additional[$addUrlKey] = Mage::helper('core')->urlEncode($addUrlValue); - - return $this->helper('checkout/cart')->getAddUrl($product, $additional); + return $this->getAddToCartUrlCustom($product, $additional); } /** @@ -223,4 +211,34 @@ public function getCacheTags() { return array_merge(parent::getCacheTags(), $this->getProduct()->getCacheIdTags()); } + + /** + * Retrieve url for direct adding product to cart with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param array $additional + * @param bool $addFormKey + * @return string + */ + public function getAddToCartUrlCustom($product, $additional = array(), $addFormKey = true) + { + if (!$addFormKey && $this->hasCustomAddToCartPostUrl()) { + return $this->getCustomAddToCartPostUrl(); + } elseif ($this->hasCustomAddToCartUrl()) { + return $this->getCustomAddToCartUrl(); + } + + if ($this->getRequest()->getParam('wishlist_next')) { + $additional['wishlist_next'] = 1; + } + + $addUrlValue = Mage::getUrl('*/*/*', array('_use_rewrite' => true, '_current' => true)); + $additional[Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED] = + Mage::helper('core')->urlEncode($addUrlValue); + + if (!$addFormKey) { + return $this->helper('checkout/cart')->getAddUrlCustom($product, $additional, false); + } + return $this->helper('checkout/cart')->getAddUrl($product, $additional); + } } diff --git a/app/code/core/Mage/Catalog/Helper/Product/Compare.php b/app/code/core/Mage/Catalog/Helper/Product/Compare.php index 83477740b5..f3324fd265 100644 --- a/app/code/core/Mage/Catalog/Helper/Product/Compare.php +++ b/app/code/core/Mage/Catalog/Helper/Product/Compare.php @@ -146,11 +146,7 @@ public function getListUrl() */ protected function _getUrlParams($product) { - return array( - 'product' => $product->getId(), - Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->getEncodedUrl(), - Mage_Core_Model_Url::FORM_KEY => $this->_coreSession->getFormKey() - ); + return $this->_getUrlCustomParams($product); } /** @@ -161,10 +157,7 @@ protected function _getUrlParams($product) */ public function getAddUrl($product) { - if ($this->_logCondition->isVisitorLogEnabled() || $this->_customerSession->isLoggedIn()) { - return $this->_getUrl('catalog/product_compare/add', $this->_getUrlParams($product)); - } - return ''; + return $this->getAddUrlCustom($product); } /** @@ -175,15 +168,7 @@ public function getAddUrl($product) */ public function getAddToWishlistUrl($product) { - $beforeCompareUrl = $this->_catalogSession->getBeforeCompareUrl(); - - $params = array( - 'product' => $product->getId(), - Mage_Core_Model_Url::FORM_KEY => $this->_coreSession->getFormKey(), - Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->getEncodedUrl($beforeCompareUrl) - ); - - return $this->_getUrl('wishlist/index/add', $params); + return $this->getAddToWishlistUrlCustom($product); } /** @@ -194,14 +179,7 @@ public function getAddToWishlistUrl($product) */ public function getAddToCartUrl($product) { - $beforeCompareUrl = $this->_catalogSession->getBeforeCompareUrl(); - $params = array( - 'product' => $product->getId(), - Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->getEncodedUrl($beforeCompareUrl), - Mage_Core_Model_Url::FORM_KEY => $this->_coreSession->getFormKey() - ); - - return $this->_getUrl('checkout/cart/add', $params); + return $this->getAddToCartUrlCustom($product); } /** @@ -362,4 +340,74 @@ public function setCustomerId($id) $this->_customerId = $id; return $this; } + + /** + * Retrieve url for adding product to conpare list with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param bool $addFormKey + * @return string + */ + public function getAddUrlCustom($product, $addFormKey = true) + { + if ($this->_logCondition->isVisitorLogEnabled() || $this->_customerSession->isLoggedIn()) { + return $this->_getUrl('catalog/product_compare/add', $this->_getUrlCustomParams($product, $addFormKey)); + } + return ''; + } + + /** + * Retrive add to wishlist url with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param bool $addFormKey + * @return string + */ + public function getAddToWishlistUrlCustom($product, $addFormKey = true) + { + $beforeCompareUrl = $this->_catalogSession->getBeforeCompareUrl(); + $params = $this->_getUrlCustomParams($product, $addFormKey, $beforeCompareUrl); + + return $this->_getUrl('wishlist/index/add', $params); + } + + /** + * Retrive add to cart url with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param bool $addFormKey + * @return string + */ + public function getAddToCartUrlCustom($product, $addFormKey = true) + { + $beforeCompareUrl = $this->_catalogSession->getBeforeCompareUrl(); + $params = array( + 'product' => $product->getId(), + Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->getEncodedUrl($beforeCompareUrl), + ); + if ($addFormKey) { + $params[Mage_Core_Model_Url::FORM_KEY] = $this->_coreSession->getFormKey(); + } + + return $this->_getUrl('checkout/cart/add', $params); + } + + /** + * Get parameters used for build add product to compare list urls with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param bool $addFormKey + * @return array + */ + protected function _getUrlCustomParams($product, $addFormKey = true, $url = null) + { + $params = array( + 'product' => $product->getId(), + Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->getEncodedUrl($url), + ); + if ($addFormKey) { + $params[Mage_Core_Model_Url::FORM_KEY] = $this->_coreSession->getFormKey(); + } + return $params; + } } diff --git a/app/code/core/Mage/Catalog/Model/Design.php b/app/code/core/Mage/Catalog/Model/Design.php index 8a6bdc840e..5261143c6e 100644 --- a/app/code/core/Mage/Catalog/Model/Design.php +++ b/app/code/core/Mage/Catalog/Model/Design.php @@ -375,9 +375,19 @@ protected function _extractSettings($object) $date = $object->getCustomDesignDate(); if (array_key_exists('from', $date) && array_key_exists('to', $date) && Mage::app()->getLocale()->isStoreDateInInterval(null, $date['from'], $date['to'])) { - $settings->setCustomDesign($object->getCustomDesign()) - ->setPageLayout($object->getPageLayout()) - ->setLayoutUpdates((array)$object->getCustomLayoutUpdate()); + $customLayout = $object->getCustomLayoutUpdate(); + if ($customLayout) { + try { + if (!Mage::getModel('core/layout_validator')->isValid($customLayout)) { + $customLayout = ''; + } + } catch (Exception $e) { + $customLayout = ''; + } + } + $settings->setCustomDesign($object->getCustomDesign()) + ->setPageLayout($object->getPageLayout()) + ->setLayoutUpdates((array)$customLayout); } return $settings; } diff --git a/app/code/core/Mage/Catalog/etc/config.xml b/app/code/core/Mage/Catalog/etc/config.xml index f038fc0263..24bb640d5b 100644 --- a/app/code/core/Mage/Catalog/etc/config.xml +++ b/app/code/core/Mage/Catalog/etc/config.xml @@ -28,7 +28,7 @@ - 1.6.0.0.19.1.5 + 1.6.0.0.19.1.6 diff --git a/app/code/core/Mage/Catalog/sql/catalog_setup/upgrade-1.6.0.0.19.1.5-1.6.0.0.19.1.6.php b/app/code/core/Mage/Catalog/sql/catalog_setup/upgrade-1.6.0.0.19.1.5-1.6.0.0.19.1.6.php new file mode 100644 index 0000000000..d2863c47aa --- /dev/null +++ b/app/code/core/Mage/Catalog/sql/catalog_setup/upgrade-1.6.0.0.19.1.5-1.6.0.0.19.1.6.php @@ -0,0 +1,44 @@ +getEntityTypeId('catalog_product'), + $installer->getEntityTypeId('catalog_category'), +]; +foreach ($entitiesToUpgrade as $entityTypeId) { + if ($this->getAttributeId($entityTypeId, $attributeId)) { + $installer->updateAttribute( + $entityTypeId, + $attributeId, + 'backend_model', + 'catalog/attribute_backend_customlayoutupdate' + ); + } +} diff --git a/app/code/core/Mage/Checkout/Block/Cart/Item/Renderer.php b/app/code/core/Mage/Checkout/Block/Cart/Item/Renderer.php index 3478b4efa8..d3f9bbc84e 100644 --- a/app/code/core/Mage/Checkout/Block/Cart/Item/Renderer.php +++ b/app/code/core/Mage/Checkout/Block/Cart/Item/Renderer.php @@ -215,19 +215,31 @@ public function getConfigureUrl() * @return string */ public function getDeleteUrl() + { + return $this->getDeleteUrlCustom(); + } + + /** + * Get item delete url with or without Form Key + * + * @param bool $addFormKey + * @return string + */ + public function getDeleteUrlCustom($addFormKey = true) { if ($this->hasDeleteUrl()) { return $this->getData('delete_url'); } - return $this->getUrl( - 'checkout/cart/delete', - array( - 'id'=>$this->getItem()->getId(), - 'form_key' => Mage::getSingleton('core/session')->getFormKey(), - Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->helper('core/url')->getEncodedUrl() - ) + $params = array( + 'id' => $this->getItem()->getId(), + Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->helper('core/url')->getEncodedUrl(), ); + if ($addFormKey) { + $params[Mage_Core_Model_Url::FORM_KEY] = Mage::getSingleton('core/session')->getFormKey(); + } + + return $this->getUrl('checkout/cart/delete', $params); } /** diff --git a/app/code/core/Mage/Checkout/Helper/Cart.php b/app/code/core/Mage/Checkout/Helper/Cart.php index 0a1e68c985..d864ea671f 100644 --- a/app/code/core/Mage/Checkout/Helper/Cart.php +++ b/app/code/core/Mage/Checkout/Helper/Cart.php @@ -60,28 +60,7 @@ public function getCart() */ public function getAddUrl($product, $additional = array()) { - $routeParams = array( - Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->_getHelperInstance('core') - ->urlEncode($this->getCurrentUrl()), - 'product' => $product->getEntityId(), - Mage_Core_Model_Url::FORM_KEY => $this->_getSingletonModel('core/session')->getFormKey() - ); - - if (!empty($additional)) { - $routeParams = array_merge($routeParams, $additional); - } - - if ($product->hasUrlDataObject()) { - $routeParams['_store'] = $product->getUrlDataObject()->getStoreId(); - $routeParams['_store_to_url'] = true; - } - - if ($this->_getRequest()->getRouteName() == 'checkout' - && $this->_getRequest()->getControllerName() == 'cart') { - $routeParams['in_cart'] = 1; - } - - return $this->_getUrl('checkout/cart/add', $routeParams); + return $this->getAddUrlCustom($product, $additional); } /** @@ -180,4 +159,39 @@ public function getShouldRedirectToCart($store = null) { return Mage::getStoreConfigFlag(self::XML_PATH_REDIRECT_TO_CART, $store); } + + /** + * Retrieve url for add product to cart with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param array $additional + * @param bool $addFormKey + * @return string + */ + public function getAddUrlCustom($product, $additional = array(), $addFormKey = true) + { + $routeParams = array( + Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $this->_getHelperInstance('core') + ->urlEncode($this->getCurrentUrl()), + 'product' => $product->getEntityId(), + ); + if ($addFormKey) { + $routeParams[Mage_Core_Model_Url::FORM_KEY] = $this->_getSingletonModel('core/session')->getFormKey(); + } + if (!empty($additional)) { + $routeParams = array_merge($routeParams, $additional); + } + if ($product->hasUrlDataObject()) { + $routeParams['_store'] = $product->getUrlDataObject()->getStoreId(); + $routeParams['_store_to_url'] = true; + } + if ( + $this->_getRequest()->getRouteName() == 'checkout' + && $this->_getRequest()->getControllerName() == 'cart' + ) { + $routeParams['in_cart'] = 1; + } + + return $this->_getUrl('checkout/cart/add', $routeParams); + } } diff --git a/app/code/core/Mage/Checkout/Model/Session.php b/app/code/core/Mage/Checkout/Model/Session.php index dded46610c..fc99aa61bd 100644 --- a/app/code/core/Mage/Checkout/Model/Session.php +++ b/app/code/core/Mage/Checkout/Model/Session.php @@ -120,21 +120,13 @@ public function getQuote() if ($this->_quote === null) { /** @var $quote Mage_Sales_Model_Quote */ $quote = Mage::getModel('sales/quote')->setStoreId(Mage::app()->getStore()->getId()); - $customerSession = Mage::getSingleton('customer/session'); - if ($this->getQuoteId()) { if ($this->_loadInactive) { $quote->load($this->getQuoteId()); } else { $quote->loadActive($this->getQuoteId()); } - if ( - $quote->getId() - && ( - ($customerSession->isLoggedIn() && $customerSession->getId() == $quote->getCustomerId()) - || (!$customerSession->isLoggedIn() && !$quote->getCustomerId()) - ) - ) { + if ($quote->getId()) { /** * If current currency code of quote is not equal current currency code of store, * need recalculate totals of quote. It is possible if customer use currency switcher or @@ -151,16 +143,16 @@ public function getQuote() $quote->load($this->getQuoteId()); } } else { - $quote->unsetData(); $this->setQuoteId(null); } } + $customerSession = Mage::getSingleton('customer/session'); + if (!$this->getQuoteId()) { if ($customerSession->isLoggedIn() || $this->_customer) { $customer = ($this->_customer) ? $this->_customer : $customerSession->getCustomer(); $quote->loadByCustomer($customer); - $quote->setCustomer($customer); $this->setQuoteId($quote->getId()); } else { $quote->setIsCheckoutCart(true); diff --git a/app/code/core/Mage/Cms/Block/Widget/Block.php b/app/code/core/Mage/Cms/Block/Widget/Block.php index 4ebfffa81f..99d13da263 100644 --- a/app/code/core/Mage/Cms/Block/Widget/Block.php +++ b/app/code/core/Mage/Cms/Block/Widget/Block.php @@ -81,7 +81,13 @@ protected function _beforeToHtml() /* @var $helper Mage_Cms_Helper_Data */ $helper = Mage::helper('cms'); $processor = $helper->getBlockTemplateProcessor(); - $this->setText($processor->filter($block->getContent())); + if ($this->isRequestFromAdminArea()) { + $this->setText($processor->filter( + Mage::getSingleton('core/input_filter_maliciousCode')->filter($block->getContent()) + )); + } else { + $this->setText($processor->filter($block->getContent())); + } $this->addModelTags($block); } } @@ -104,4 +110,14 @@ public function getCacheKeyInfo() } return $result; } + + /** + * Check is request goes from admin area + * + * @return bool + */ + public function isRequestFromAdminArea() + { + return $this->getRequest()->getRouteName() === Mage_Core_Model_App_Area::AREA_ADMINHTML; + } } diff --git a/app/code/core/Mage/Compiler/controllers/Adminhtml/Compiler/ProcessController.php b/app/code/core/Mage/Compiler/controllers/Adminhtml/Compiler/ProcessController.php index a8d51be15d..352f73c74b 100644 --- a/app/code/core/Mage/Compiler/controllers/Adminhtml/Compiler/ProcessController.php +++ b/app/code/core/Mage/Compiler/controllers/Adminhtml/Compiler/ProcessController.php @@ -83,10 +83,17 @@ public function recompileAction() /** * Add redirect heades before clear compiled sources */ - $this->_redirect('*/*/run'); - $this->_getCompiler()->clear(); - $this->getResponse()->sendHeaders(); - exit; + if (defined('COMPILER_INCLUDE_PATH')) { + Mage::getSingleton('adminhtml/session')->addError( + Mage::helper('compiler')->__('Please, press disable button before run compilation process') + ); + $this->_redirect('*/*/'); + } else { + $this->_redirect('*/*/run'); + $this->_getCompiler()->clear(); + $this->getResponse()->sendHeaders(); + exit; + } } public function disableAction() diff --git a/app/code/core/Mage/Core/Block/Abstract.php b/app/code/core/Mage/Core/Block/Abstract.php index 6f14908d1c..dbcba901a6 100644 --- a/app/code/core/Mage/Core/Block/Abstract.php +++ b/app/code/core/Mage/Core/Block/Abstract.php @@ -1393,6 +1393,16 @@ public function getCacheLifetime() return $this->getData('cache_lifetime'); } + /** + * Retrieve Session Form Key + * + * @return string + */ + public function getFormKey() + { + return Mage::getSingleton('core/session')->getFormKey(); + } + /** * Load block html from cache storage * diff --git a/app/code/core/Mage/Core/Helper/Data.php b/app/code/core/Mage/Core/Helper/Data.php index f4deb30f61..ec7006fa4c 100644 --- a/app/code/core/Mage/Core/Helper/Data.php +++ b/app/code/core/Mage/Core/Helper/Data.php @@ -270,11 +270,41 @@ public function getHash($password, $salt = false) return $this->getEncryptor()->getHash($password, $salt); } + /** + * Generate password hash for user + * + * @param string $password + * @param mixed $salt + * @return string + */ + public function getHashPassword($password, $salt = false) + { + $encryptionModel = $this->getEncryptor(); + $latestVersionHash = $this->getVersionHash($encryptionModel); + if ($latestVersionHash == $encryptionModel::HASH_VERSION_SHA512) { + return $this->getEncryptor()->getHashPassword($password, $salt); + } + return $this->getEncryptor()->getHashPassword($password, Mage_Admin_Model_User::HASH_SALT_EMPTY); + } + public function validateHash($password, $hash) { return $this->getEncryptor()->validateHash($password, $hash); } + /** + * Get encryption method depending on the presence of the function - password_hash. + * + * @param Mage_Core_Model_Encryption $encryptionModel + * @return int + */ + public function getVersionHash(Mage_Core_Model_Encryption $encryptionModel) + { + return function_exists('password_hash') + ? $encryptionModel::HASH_VERSION_LATEST + : $encryptionModel::HASH_VERSION_SHA512; + } + /** * Retrieve store identifier * diff --git a/app/code/core/Mage/Core/Helper/String.php b/app/code/core/Mage/Core/Helper/String.php index 94ccc225d9..2e3766da57 100644 --- a/app/code/core/Mage/Core/Helper/String.php +++ b/app/code/core/Mage/Core/Helper/String.php @@ -536,4 +536,36 @@ public function unserialize($str) $prevChar = $char; } } + + /** + * Detect serialization of data Array or Object + * + * @param mixed $data + * @return bool + */ + public function isSerializedArrayOrObject($data) + { + $pattern = + '/^a:\d+:\{(i:\d+;|s:\d+:\".+\";|N;|O:\d+:\"\w+\":\d+:\{\w:\d+:)+|^O:\d+:\"\w+\":\d+:\{(s:\d+:\"|i:\d+;)/'; + return is_string($data) && preg_match($pattern, $data); + } + + /** + * Validate is Serialized Data Object in string + * + * @param string $str + * @return bool + */ + public function validateSerializedObject($str) + { + if ($this->isSerializedArrayOrObject($str)) { + try { + $this->unserialize($str); + } catch (Exception $e) { + return false; + } + } + + return true; + } } diff --git a/app/code/core/Mage/Core/Model/App.php b/app/code/core/Mage/Core/Model/App.php index 1e5e6d68fd..75feadad59 100644 --- a/app/code/core/Mage/Core/Model/App.php +++ b/app/code/core/Mage/Core/Model/App.php @@ -72,6 +72,22 @@ class Mage_Core_Model_App */ const ADMIN_STORE_ID = 0; + /** + * The absolute minimum of password length for all types of passwords + * + * With changing this value also need to change: + * 1. in `js/prototype/validation.js` declarations `var minLength = 7;` in two places; + * 2. in `app/code/core/Mage/Customer/etc/system.xml` + * comments for fields `min_password_length` and `min_admin_password_length` + * `Please enter a number 7 or greater in this field.`; + * 3. in `app/code/core/Mage/Customer/etc/config.xml` value `7` + * and, maybe, value `14` + * (if the absolute minimum of password length is higher then this value); + * 4. maybe, the value of deprecated `const MIN_PASSWORD_LENGTH` in `app/code/core/Mage/Admin/Model/User.php`, + * (if the absolute minimum of password length is higher then this value). + */ + const ABSOLUTE_MIN_PASSWORD_LENGTH = 7; + /** * Application loaded areas array * diff --git a/app/code/core/Mage/Core/Model/Encryption.php b/app/code/core/Mage/Core/Model/Encryption.php index 7bf43e7f36..0a92150036 100644 --- a/app/code/core/Mage/Core/Model/Encryption.php +++ b/app/code/core/Mage/Core/Model/Encryption.php @@ -33,6 +33,14 @@ */ class Mage_Core_Model_Encryption { + const HASH_VERSION_MD5 = 0; + const HASH_VERSION_SHA512 = 2; + + /** + * Encryption method bcrypt + */ + const HASH_VERSION_LATEST = 3; + /** * @var Varien_Crypt_Mcrypt */ @@ -74,14 +82,37 @@ public function getHash($password, $salt = false) return $salt === false ? $this->hash($password) : $this->hash($salt . $password) . ':' . $salt; } + /** + * Generate hash for customer password + * + * @param string $password + * @param mixed $salt + * @return string + */ + public function getHashPassword($password, $salt = null) + { + if (is_integer($salt)) { + $salt = $this->_helper->getRandomString($salt); + } + return (bool) $salt + ? $this->hash($salt . $password, $this->_helper->getVersionHash($this)) . ':' . $salt + : $this->hash($password, $this->_helper->getVersionHash($this)); + } + /** * Hash a string * * @param string $data - * @return string + * @param int $version + * @return bool|string */ - public function hash($data) + public function hash($data, $version = self::HASH_VERSION_MD5) { + if (self::HASH_VERSION_LATEST === $version && $version === $this->_helper->getVersionHash($this)) { + return password_hash($data, PASSWORD_DEFAULT); + } elseif (self::HASH_VERSION_SHA512 == $version) { + return hash('sha512', $data); + } return md5($data); } @@ -95,14 +126,31 @@ public function hash($data) */ public function validateHash($password, $hash) { - $hashArr = explode(':', $hash); - switch (count($hashArr)) { - case 1: - return hash_equals($this->hash($password), $hash); - case 2: - return hash_equals($this->hash($hashArr[1] . $password), $hashArr[0]); + return $this->validateHashByVersion($password, $hash, self::HASH_VERSION_LATEST) + || $this->validateHashByVersion($password, $hash, self::HASH_VERSION_SHA512) + || $this->validateHashByVersion($password, $hash, self::HASH_VERSION_MD5); + } + + /** + * Validate hash by specified version + * + * @param string $password + * @param string $hash + * @param int $version + * @return bool + */ + public function validateHashByVersion($password, $hash, $version = self::HASH_VERSION_MD5) + { + if ($version == self::HASH_VERSION_LATEST && $version == $this->_helper->getVersionHash($this)) { + return password_verify($password, $hash); + } + // look for salt + $hashArr = explode(':', $hash, 2); + if (1 === count($hashArr)) { + return hash_equals($this->hash($password, $version), $hash); } - Mage::throwException('Invalid hash.'); + list($hash, $salt) = $hashArr; + return hash_equals($this->hash($salt . $password, $version), $hash); } /** diff --git a/app/code/core/Mage/Core/Model/File/Uploader.php b/app/code/core/Mage/Core/Model/File/Uploader.php index a35a4c05ce..d934eb8753 100644 --- a/app/code/core/Mage/Core/Model/File/Uploader.php +++ b/app/code/core/Mage/Core/Model/File/Uploader.php @@ -41,6 +41,13 @@ class Mage_Core_Model_File_Uploader extends Varien_File_Uploader */ protected $_skipDbProcessing = false; + /** + * Max file name length + * + * @var int + */ + protected $_fileNameMaxLength = 200; + /** * Save file to storage * @@ -99,4 +106,25 @@ public function checkAllowedExtension($extension) return parent::checkAllowedExtension($extension); } + + /** + * Used to save uploaded file into destination folder with + * original or new file name (if specified). + * Added file name length validation. + * + * @param string $destinationFolder + * @param string|null $newFileName + * @return bool|void + * @throws Exception + */ + public function save($destinationFolder, $newFileName = null) + { + $fileName = isset($newFileName) ? $newFileName : $this->_file['name']; + if (strlen($fileName) > $this->_fileNameMaxLength) { + throw new Exception( + Mage::helper('core')->__("File name is too long. Maximum length is %s.", $this->_fileNameMaxLength) + ); + } + return parent::save($destinationFolder, $newFileName); + } } diff --git a/app/code/core/Mage/Core/Model/Input/Filter/MaliciousCode.php b/app/code/core/Mage/Core/Model/Input/Filter/MaliciousCode.php index 7bc7c959e5..b3cadd0136 100644 --- a/app/code/core/Mage/Core/Model/Input/Filter/MaliciousCode.php +++ b/app/code/core/Mage/Core/Model/Input/Filter/MaliciousCode.php @@ -50,11 +50,13 @@ class Mage_Core_Model_Input_Filter_MaliciousCode implements Zend_Filter_Interfac //js in the style attribute '/style=[^<]*((expression\s*?\([^<]*?\))|(behavior\s*:))[^<]*(?=\>)/Uis', //js attributes - '/(ondblclick|onclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onload|onunload|onerror)\s*=[^>]*(?=\>)/Uis', + '/(ondblclick|onclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onload|onunload|onerror|onanimationstart)\s*=[^>]*(?=\>)/Uis', //tags '/<\/?(script|meta|link|frame|iframe).*>/Uis', //base64 usage '/src\s*=[^<]*base64[^<]*(?=\>)/Uis', + //data attribute + '/(data(\\\\x3a|:|%3A)(.+?(?=")|.+?(?=\')))/is', ); /** @@ -99,4 +101,64 @@ public function setExpressions(array $expressions) $this->_expressions = $expressions; return $this; } + + /** + * The filter adds safe attributes to the link + * + * @param string $html + * @param bool $removeWrapper flag for remove wrapper tags: Doctype, html, body + * @return string + * @throws Mage_Core_Exception + */ + public function linkFilter($html, $removeWrapper = true) + { + if (stristr($html, '_initDOMDocument(); + if (!$dom->loadHTML($html)) { + Mage::throwException(Mage::helper('core')->__('HTML filtration has failed.')); + } + + $relAttributeDefaultItems = array('noopener', 'noreferrer'); + /** @var DOMElement $linkItem */ + foreach ($dom->getElementsByTagName('a') as $linkItem) { + $relAttributeItems = array(); + $relAttributeCurrentValue = $linkItem->getAttribute('rel'); + if (!empty($relAttributeCurrentValue)) { + $relAttributeItems = explode(' ', $relAttributeCurrentValue); + } + $relAttributeItems = array_unique(array_merge($relAttributeItems, $relAttributeDefaultItems)); + $linkItem->setAttribute('rel', implode(' ', $relAttributeItems)); + $linkItem->setAttribute('target', '_blank'); + } + + if (!$html = $dom->saveHTML()) { + Mage::throwException(Mage::helper('core')->__('HTML filtration has failed.')); + } + + if ($removeWrapper) { + $html = preg_replace('/<(?:!DOCTYPE|\/?(?:html|body))[^>]*>\s*/i', '', $html); + } + + libxml_use_internal_errors($libXmlErrorsState); + + return $html; + } + + /** + * Initialize built-in DOM parser instance + * + * @return DOMDocument + */ + protected function _initDOMDocument() + { + $dom = new DOMDocument(); + $dom->strictErrorChecking = false; + $dom->recover = false; + + return $dom; + } } diff --git a/app/code/core/Mage/Core/Model/Layout/Validator.php b/app/code/core/Mage/Core/Model/Layout/Validator.php new file mode 100644 index 0000000000..94497b9f24 --- /dev/null +++ b/app/code/core/Mage/Core/Model/Layout/Validator.php @@ -0,0 +1,258 @@ + + */ +class Mage_Core_Model_Layout_Validator extends Zend_Validate_Abstract +{ + const XML_PATH_LAYOUT_DISALLOWED_BLOCKS = 'validators/custom_layout/disallowed_block'; + const XML_INVALID = 'invalidXml'; + const INVALID_TEMPLATE_PATH = 'invalidTemplatePath'; + const INVALID_BLOCK_NAME = 'invalidBlockName'; + const PROTECTED_ATTR_HELPER_IN_TAG_ACTION_VAR = 'protectedAttrHelperInActionVar'; + const INVALID_XML_OBJECT_EXCEPTION = 'invalidXmlObject'; + + /** + * The Varien SimpleXml object + * + * @var Varien_Simplexml_Element + */ + protected $_value; + + /** + * XPath expression for checking layout update + * + * @var array + */ + protected $_disallowedXPathExpressions = array( + '*//template', + '*//@template', + '//*[@method=\'setTemplate\']', + '//*[@method=\'setDataUsingMethod\']//*[contains(translate(text(), + \'ABCDEFGHIJKLMNOPQRSTUVWXYZ\', \'abcdefghijklmnopqrstuvwxyz\'), \'template\')]/../*', + ); + + /** + * @var string + */ + protected $_xpathBlockValidationExpression = ''; + + /** + * Disallowed template name + * + * @var array + */ + protected $_disallowedBlock = array(); + + /** + * Protected expressions + * + * @var array + */ + protected $_protectedExpressions = array( + self::PROTECTED_ATTR_HELPER_IN_TAG_ACTION_VAR => '//action/*[@helper]', + ); + + /** + * Construct + */ + public function __construct() + { + $this->_initMessageTemplates(); + $this->getDisallowedBlocks(); + } + + /** + * Initialize messages templates with translating + * + * @return Mage_Core_Model_Layout_Validator + */ + protected function _initMessageTemplates() + { + if (!$this->_messageTemplates) { + $this->_messageTemplates = array( + self::PROTECTED_ATTR_HELPER_IN_TAG_ACTION_VAR => + Mage::helper('core')->__('Helper attributes should not be used in custom layout updates.'), + self::XML_INVALID => Mage::helper('core')->__('XML data is invalid.'), + self::INVALID_TEMPLATE_PATH => Mage::helper('core')->__( + 'Invalid template path used in layout update.' + ), + self::INVALID_BLOCK_NAME => Mage::helper('core')->__('Disallowed block name for frontend.'), + self::INVALID_XML_OBJECT_EXCEPTION => + Mage::helper('core')->__('XML object is not instance of "Varien_Simplexml_Element".'), + ); + } + return $this; + } + + /** + * @return array + */ + public function getDisallowedBlocks() + { + if (!count($this->_disallowedBlock)) { + $disallowedBlockConfig = $this->_getDisallowedBlockConfigValue(); + if (is_array($disallowedBlockConfig)) { + foreach ($disallowedBlockConfig as $blockName => $value) { + $this->_disallowedBlock[] = $blockName; + } + } + } + return $this->_disallowedBlock; + } + + /** + * @return mixed + */ + protected function _getDisallowedBlockConfigValue() + { + return Mage::getStoreConfig(self::XML_PATH_LAYOUT_DISALLOWED_BLOCKS); + } + + /** + * Returns true if and only if $value meets the validation requirements + * + * If $value fails validation, then this method returns false, and + * getMessages() will return an array of messages that explain why the + * validation failed. + * + * @throws Exception Throw exception when xml object is not + * instance of Varien_Simplexml_Element + * @param Varien_Simplexml_Element|string $value + * @return bool + */ + public function isValid($value) + { + if (is_string($value)) { + $value = trim($value); + try { + $value = new Varien_Simplexml_Element('' . $value . ''); + } catch (Exception $e) { + $this->_error(self::XML_INVALID); + return false; + } + } elseif (!($value instanceof Varien_Simplexml_Element)) { + throw new Exception($this->_messageTemplates[self::INVALID_XML_OBJECT_EXCEPTION]); + } + if ($value->xpath($this->getXpathBlockValidationExpression())) { + $this->_error(self::INVALID_BLOCK_NAME); + return false; + } + // if layout update declare custom templates then validate their paths + if ($templatePaths = $value->xpath($this->getXpathValidationExpression())) { + try { + $this->validateTemplatePath($templatePaths); + } catch (Exception $e) { + $this->_error(self::INVALID_TEMPLATE_PATH); + return false; + } + } + $this->_setValue($value); + + foreach ($this->_protectedExpressions as $key => $xpr) { + if ($this->_value->xpath($xpr)) { + $this->_error($key); + return false; + } + } + return true; + } + + /** + * @return array + */ + public function getProtectedExpressions() + { + return $this->_protectedExpressions; + } + + /** + * Returns xPath for validate incorrect path to template + * + * @return string xPath for validate incorrect path to template + */ + public function getXpathValidationExpression() + { + return implode(" | ", $this->_disallowedXPathExpressions); + } + + /** + * @return array + */ + public function getDisallowedXpathValidationExpression() + { + return $this->_disallowedXPathExpressions; + } + + /** + * Returns xPath for validate incorrect block name + * + * @return string xPath for validate incorrect block name + */ + public function getXpathBlockValidationExpression() + { + if (!$this->_xpathBlockValidationExpression) { + if (count($this->_disallowedBlock)) { + foreach ($this->_disallowedBlock as $key => $value) { + $this->_xpathBlockValidationExpression .= $key > 0 ? " | " : ''; + $this->_xpathBlockValidationExpression .= + "//block[translate(@type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = "; + $this->_xpathBlockValidationExpression .= + "translate('$value', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')]"; + } + } + } + return $this->_xpathBlockValidationExpression; + } + + /** + * Validate template path for preventing access to the directory above + * If template path value has "../" + * + * @throws Exception + * + * @param $templatePaths | array + */ + public function validateTemplatePath(array $templatePaths) + { + /** @var $path Varien_Simplexml_Element */ + foreach ($templatePaths as $path) { + if ($path->hasChildren()) { + $path = stripcslashes(trim((string) $path->children(), '"')); + } + if (strpos($path, '..' . DS) !== false) { + throw new Exception(); + } + } + } +} diff --git a/app/code/core/Mage/Core/Model/Resource/File/Storage/Database.php b/app/code/core/Mage/Core/Model/Resource/File/Storage/Database.php index a52585c033..c6b32a5017 100644 --- a/app/code/core/Mage/Core/Model/Resource/File/Storage/Database.php +++ b/app/code/core/Mage/Core/Model/Resource/File/Storage/Database.php @@ -71,7 +71,7 @@ public function createDatabaseScheme() 'nullable' => false, 'default' => Varien_Db_Ddl_Table::TIMESTAMP_INIT ), 'Upload Timestamp') - ->addColumn('filename', Varien_Db_Ddl_Table::TYPE_TEXT, 100, array( + ->addColumn('filename', Varien_Db_Ddl_Table::TYPE_TEXT, 255, array( 'nullable' => false ), 'Filename') ->addColumn('directory_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( diff --git a/app/code/core/Mage/Core/etc/config.xml b/app/code/core/Mage/Core/etc/config.xml index 7abca9384a..e0966c26df 100644 --- a/app/code/core/Mage/Core/etc/config.xml +++ b/app/code/core/Mage/Core/etc/config.xml @@ -28,7 +28,7 @@ - 1.6.0.8 + 1.6.0.10 @@ -432,6 +432,7 @@ 2 2 1 + 0 @@ -499,6 +500,13 @@ + + + + + + + diff --git a/app/code/core/Mage/Core/etc/jstranslator.xml b/app/code/core/Mage/Core/etc/jstranslator.xml index 97ee655de8..7403685c62 100644 --- a/app/code/core/Mage/Core/etc/jstranslator.xml +++ b/app/code/core/Mage/Core/etc/jstranslator.xml @@ -85,10 +85,10 @@ Please use only visible characters and spaces. - Please enter 6 or more characters without leading or trailing spaces. + Please enter more characters or clean leading or trailing spaces. - Please enter 7 or more characters. Password should contain both numeric and alphabetic characters. + Please enter more characters. Password should contain both numeric and alphabetic characters. Please make sure your passwords match. @@ -133,7 +133,7 @@ Please select State/Province. - Please enter 6 or more characters without leading or trailing spaces. + Please enter more characters or clean leading or trailing spaces. Please enter a number greater than 0 in this field. diff --git a/app/code/core/Mage/Core/etc/system.xml b/app/code/core/Mage/Core/etc/system.xml index 13d799efa2..4391b63847 100644 --- a/app/code/core/Mage/Core/etc/system.xml +++ b/app/code/core/Mage/Core/etc/system.xml @@ -119,6 +119,7 @@ 1 1 1 + 1 diff --git a/app/code/core/Mage/Core/sql/core_setup/upgrade-1.6.0.8-1.6.0.9.php b/app/code/core/Mage/Core/sql/core_setup/upgrade-1.6.0.8-1.6.0.9.php new file mode 100644 index 0000000000..d43552d82d --- /dev/null +++ b/app/code/core/Mage/Core/sql/core_setup/upgrade-1.6.0.8-1.6.0.9.php @@ -0,0 +1,35 @@ +startSetup(); +$connection = $installer->getConnection(); + +$connection->addColumn($installer->getTable('core_config_data'), 'updated_at', Varien_Db_Ddl_Table::TYPE_TIMESTAMP); + +$installer->endSetup(); diff --git a/app/code/core/Mage/Core/sql/core_setup/upgrade-1.6.0.9-1.6.0.10.php b/app/code/core/Mage/Core/sql/core_setup/upgrade-1.6.0.9-1.6.0.10.php new file mode 100644 index 0000000000..b56a7dda9a --- /dev/null +++ b/app/code/core/Mage/Core/sql/core_setup/upgrade-1.6.0.9-1.6.0.10.php @@ -0,0 +1,48 @@ +startSetup(); +$table = $installer->getTable('core/file_storage'); + +/** + * Change column + */ +if ($installer->getConnection()->isTableExists($table)) { + $installer->getConnection()->modifyColumn( + $table, + 'filename', + array( + 'type' => Varien_Db_Ddl_Table::TYPE_TEXT, + 'length' => 255, + 'nullable' => false, + 'comment' => 'Filename', + ) + ); +} + +$installer->endSetup(); diff --git a/app/code/core/Mage/Customer/Block/Account/Changeforgotten.php b/app/code/core/Mage/Customer/Block/Account/Changeforgotten.php index efbb24e3ef..179e53613e 100644 --- a/app/code/core/Mage/Customer/Block/Account/Changeforgotten.php +++ b/app/code/core/Mage/Customer/Block/Account/Changeforgotten.php @@ -33,5 +33,13 @@ */ class Mage_Customer_Block_Account_Changeforgotten extends Mage_Core_Block_Template { - + /** + * Retrieve minimum length of customer password + * + * @return int + */ + public function getMinPasswordLength() + { + return Mage::getModel('customer/customer')->getMinPasswordLength(); + } } diff --git a/app/code/core/Mage/Customer/Block/Address/Renderer/Default.php b/app/code/core/Mage/Customer/Block/Address/Renderer/Default.php index fd7f731d5d..63cb5f6a30 100644 --- a/app/code/core/Mage/Customer/Block/Address/Renderer/Default.php +++ b/app/code/core/Mage/Customer/Block/Address/Renderer/Default.php @@ -70,7 +70,13 @@ public function getFormat(Mage_Customer_Model_Address_Abstract $address=null) $countryFormat = is_null($address) ? false : $address->getCountryModel()->getFormat($this->getType()->getCode()); - $format = $countryFormat ? $countryFormat->getFormat() : $this->getType()->getDefaultFormat(); + if ($countryFormat) { + $format = $countryFormat->getFormat(); + } else { + $regExp = "/^[^()\n]*+(\((?>[^()\n]|(?1))*+\)[^()\n]*+)++$|^[^()]+?$/m"; + preg_match_all($regExp, $this->getType()->getDefaultFormat(), $matches, PREG_SET_ORDER); + $format = count($matches) ? $this->_prepareAddressTemplateData($this->getType()->getDefaultFormat()) : null; + } return $format; } @@ -132,9 +138,25 @@ public function render(Mage_Customer_Model_Address_Abstract $address, $format=nu } $formater->setVariables($data); - - $format = !is_null($format) ? $format : $this->getFormat($address); + $format = !is_null($format) ? $format : $this->_prepareAddressTemplateData($this->getFormat($address)); return $formater->filter($format); } + + /** + * Get address template data without url and js code + * @param $data + * @return string + */ + protected function _prepareAddressTemplateData($data) + { + $result = ''; + if (is_string($data)) { + $urlRegExp = "@(https?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@"; + /** @var $maliciousCodeFilter Mage_Core_Model_Input_Filter_MaliciousCode */ + $maliciousCodeFilter = Mage::getSingleton('core/input_filter_maliciousCode'); + $result = preg_replace($urlRegExp, ' ', $maliciousCodeFilter->filter($data)); + } + return $result; + } } diff --git a/app/code/core/Mage/Customer/Block/Form/Register.php b/app/code/core/Mage/Customer/Block/Form/Register.php index c1b53d729a..cc149c0b00 100644 --- a/app/code/core/Mage/Customer/Block/Form/Register.php +++ b/app/code/core/Mage/Customer/Block/Form/Register.php @@ -161,4 +161,14 @@ public function restoreSessionData(Mage_Customer_Model_Form $form, $scope = null return $this; } + + /** + * Retrieve minimum length of customer password + * + * @return int + */ + public function getMinPasswordLength() + { + return Mage::getModel('customer/customer')->getMinPasswordLength(); + } } diff --git a/app/code/core/Mage/Customer/Model/Customer.php b/app/code/core/Mage/Customer/Model/Customer.php index b9da9d04bc..c5c757d879 100644 --- a/app/code/core/Mage/Customer/Model/Customer.php +++ b/app/code/core/Mage/Customer/Model/Customer.php @@ -71,8 +71,14 @@ class Mage_Customer_Model_Customer extends Mage_Core_Model_Abstract /** * Minimum Password Length + * @deprecated Use getMinPasswordLength() method instead */ - const MINIMUM_PASSWORD_LENGTH = 6; + const MINIMUM_PASSWORD_LENGTH = Mage_Core_Model_App::ABSOLUTE_MIN_PASSWORD_LENGTH; + + /** + * Configuration path for minimum length of password + */ + const XML_PATH_MIN_PASSWORD_LENGTH = 'customer/password/min_password_length'; /** * Maximum Password Length @@ -398,7 +404,7 @@ public function setPassword($password) public function hashPassword($password, $salt = null) { return $this->_getHelper('core') - ->getHash(trim($password), !is_null($salt) ? $salt : Mage_Admin_Model_User::HASH_SALT_LENGTH); + ->getHashPassword(trim($password), (bool) $salt ? $salt : Mage_Admin_Model_User::HASH_SALT_LENGTH); } /** @@ -420,6 +426,10 @@ protected function _getHelper($helperName) */ public function generatePassword($length = 8) { + $minPasswordLength = $this->getMinPasswordLength(); + if ($minPasswordLength > $length) { + $length = $minPasswordLength; + } $chars = Mage_Core_Helper_Data::CHARS_PASSWORD_LOWERS . Mage_Core_Helper_Data::CHARS_PASSWORD_UPPERS . Mage_Core_Helper_Data::CHARS_PASSWORD_DIGITS @@ -878,9 +888,10 @@ public function validate() if (!$this->getId() && !Zend_Validate::is($password , 'NotEmpty')) { $errors[] = Mage::helper('customer')->__('The password cannot be empty.'); } - if (strlen($password) && !Zend_Validate::is($password, 'StringLength', array(self::MINIMUM_PASSWORD_LENGTH))) { + $minPasswordLength = $this->getMinPasswordLength(); + if (strlen($password) && !Zend_Validate::is($password, 'StringLength', array($minPasswordLength))) { $errors[] = Mage::helper('customer') - ->__('The minimum password length is %s', self::MINIMUM_PASSWORD_LENGTH); + ->__('The minimum password length is %s', $minPasswordLength); } if (strlen($password) && !Zend_Validate::is($password, 'StringLength', array('max' => self::MAXIMUM_PASSWORD_LENGTH))) { $errors[] = Mage::helper('customer') @@ -922,9 +933,10 @@ public function validateResetPassword() if (!Zend_Validate::is($password, 'NotEmpty')) { $errors[] = Mage::helper('customer')->__('The password cannot be empty.'); } - if (!Zend_Validate::is($password, 'StringLength', array(self::MINIMUM_PASSWORD_LENGTH))) { + $minPasswordLength = $this->getMinPasswordLength(); + if (!Zend_Validate::is($password, 'StringLength', array($minPasswordLength))) { $errors[] = Mage::helper('customer') - ->__('The minimum password length is %s', self::MINIMUM_PASSWORD_LENGTH); + ->__('The minimum password length is %s', $minPasswordLength); } if (!Zend_Validate::is($password, 'StringLength', array('max' => self::MAXIMUM_PASSWORD_LENGTH))) { $errors[] = Mage::helper('customer') @@ -1455,4 +1467,16 @@ public function cleanPasswordsValidationData() $this->setData('password_confirmation', null); return $this; } + + /** + * Retrieve minimum length of password + * + * @return int + */ + public function getMinPasswordLength() + { + $minLength = (int)Mage::getStoreConfig(self::XML_PATH_MIN_PASSWORD_LENGTH); + $absoluteMinLength = Mage_Core_Model_App::ABSOLUTE_MIN_PASSWORD_LENGTH; + return ($minLength < $absoluteMinLength) ? $absoluteMinLength : $minLength; + } } diff --git a/app/code/core/Mage/Customer/Model/Customer/Attribute/Backend/Password.php b/app/code/core/Mage/Customer/Model/Customer/Attribute/Backend/Password.php index 3b0d961ec0..42c6255e1c 100644 --- a/app/code/core/Mage/Customer/Model/Customer/Attribute/Backend/Password.php +++ b/app/code/core/Mage/Customer/Model/Customer/Attribute/Backend/Password.php @@ -43,8 +43,12 @@ public function beforeSave($object) $password = trim($object->getPassword()); $len = Mage::helper('core/string')->strlen($password); if ($len) { - if ($len < 6) { - Mage::throwException(Mage::helper('customer')->__('The password must have at least 6 characters. Leading or trailing spaces will be ignored.')); + $minPasswordLength = Mage::getModel('customer/customer')->getMinPasswordLength(); + if ($len < $minPasswordLength) { + Mage::throwException(Mage::helper('customer')->__( + 'The password must have at least %d characters. Leading or trailing spaces will be ignored.', + $minPasswordLength + )); } $object->setPasswordHash($object->hashPassword($password)); } diff --git a/app/code/core/Mage/Customer/etc/config.xml b/app/code/core/Mage/Customer/etc/config.xml index 7583623c4b..20177055ed 100644 --- a/app/code/core/Mage/Customer/etc/config.xml +++ b/app/code/core/Mage/Customer/etc/config.xml @@ -533,6 +533,7 @@ customer_password_remind_email_template 2 1 + 7
2 @@ -593,6 +594,7 @@ T: {{var telephone}} 1 5 5 + 14 diff --git a/app/code/core/Mage/Customer/etc/system.xml b/app/code/core/Mage/Customer/etc/system.xml index 0d0dcaf136..729770d32a 100644 --- a/app/code/core/Mage/Customer/etc/system.xml +++ b/app/code/core/Mage/Customer/etc/system.xml @@ -333,6 +333,17 @@ 0 0 + + + Please enter a number 7 or greater in this field. + text + required-entry validate-digits validate-digits-range digits-range-7- + adminhtml/system_config_backend_passwordlength + 60 + 1 + 0 + 0 +
@@ -551,6 +562,17 @@ 1 1,3 + + + Please enter a number 7 or greater in this field. + text + required-entry validate-digits validate-digits-range digits-range-7- + adminhtml/system_config_backend_passwordlength + 170 + 1 + 0 + 0 + diff --git a/app/code/core/Mage/Dataflow/Model/Convert/Container/Abstract.php b/app/code/core/Mage/Dataflow/Model/Convert/Container/Abstract.php index 888e68ba9f..8e59b6a838 100644 --- a/app/code/core/Mage/Dataflow/Model/Convert/Container/Abstract.php +++ b/app/code/core/Mage/Dataflow/Model/Convert/Container/Abstract.php @@ -55,9 +55,7 @@ abstract class Mage_Dataflow_Model_Convert_Container_Abstract */ protected function isSerialized($data) { - $pattern = - '/^a:\d+:\{(i:\d+;|s:\d+:\".+\";|N;|O:\d+:\"\w+\":\d+:\{\w:\d+:)+|^O:\d+:\"\w+\":\d+:\{(s:\d+:\"|i:\d+;)/'; - return (is_string($data) && preg_match($pattern, $data)); + return Mage::helper('core/string')->isSerializedArrayOrObject($data); } public function getVar($key, $default=null) diff --git a/app/code/core/Mage/Dataflow/Model/Convert/Parser/Csv.php b/app/code/core/Mage/Dataflow/Model/Convert/Parser/Csv.php index 01b80fa781..234cba3a2e 100644 --- a/app/code/core/Mage/Dataflow/Model/Convert/Parser/Csv.php +++ b/app/code/core/Mage/Dataflow/Model/Convert/Parser/Csv.php @@ -71,6 +71,7 @@ public function parse() if (!method_exists($adapter, $adapterMethod)) { $message = Mage::helper('dataflow') ->__('Method "%s" not defined in adapter %s.', $adapterMethod, $adapterName); + $message = Mage::helper('dataflow')->escapeHtml($message); $this->addException($message, Mage_Dataflow_Model_Convert_Exception::FATAL); return $this; } diff --git a/app/code/core/Mage/Dataflow/Model/Convert/Parser/Xml/Excel.php b/app/code/core/Mage/Dataflow/Model/Convert/Parser/Xml/Excel.php index 18de8bc897..5025dbadb5 100644 --- a/app/code/core/Mage/Dataflow/Model/Convert/Parser/Xml/Excel.php +++ b/app/code/core/Mage/Dataflow/Model/Convert/Parser/Xml/Excel.php @@ -71,6 +71,7 @@ public function parse() if (!method_exists($adapter, $adapterMethod)) { $message = Mage::helper('dataflow') ->__('Method "%s" was not defined in adapter %s.', $adapterMethod, $adapterName); + $message = Mage::helper('dataflow')->escapeHtml($message); $this->addException($message, Mage_Dataflow_Model_Convert_Exception::FATAL); return $this; } diff --git a/app/code/core/Mage/Dataflow/Model/Profile.php b/app/code/core/Mage/Dataflow/Model/Profile.php index ce4c7f51aa..b61f8cc03d 100644 --- a/app/code/core/Mage/Dataflow/Model/Profile.php +++ b/app/code/core/Mage/Dataflow/Model/Profile.php @@ -57,6 +57,20 @@ class Mage_Dataflow_Model_Profile extends Mage_Core_Model_Abstract const DEFAULT_EXPORT_PATH = 'var/export'; const DEFAULT_EXPORT_FILENAME = 'export_'; + /** + * Product table permanent attributes + * + * @var array + */ + protected $_productTablePermanentAttributes = array('sku'); + + /** + * Customer table permanent attributes + * + * @var array + */ + protected $_customerTablePermanentAttributes = array('email', 'website'); + protected function _construct() { $this->_init('dataflow/profile'); @@ -151,6 +165,9 @@ protected function _afterSave() ->setProfileId($this->getId()) ->setActionCode($this->getOrigData('profile_id') ? 'update' : 'create') ->save(); + $csvParser = new Varien_File_Csv(); + $xmlParser = new DOMDocument(); + $newUploadedFilenames = array(); if (isset($_FILES['file_1']['tmp_name']) || isset($_FILES['file_2']['tmp_name']) || isset($_FILES['file_3']['tmp_name'])) { @@ -160,9 +177,58 @@ protected function _afterSave() $uploader->setAllowedExtensions(array('csv','xml')); $path = Mage::app()->getConfig()->getTempVarDir() . '/import/'; $uploader->save($path); - if ($uploadFile = $uploader->getUploadedFileName()) { + $uploadFile = $uploader->getUploadedFileName(); + + if ($_FILES['file_' . ($index + 1)]['type'] == "text/csv") { + $fileData = $csvParser->getData($path . $uploadFile); + $fileData = array_shift($fileData); + } else { + try { + $xmlParser->loadXML(file_get_contents($path . $uploadFile)); + $cells = $this->getNode($xmlParser, 'Worksheet')->item(0); + $cells = $this->getNode($cells, 'Row')->item(0); + $cells = $this->getNode($cells, 'Cell'); + $fileData = array(); + foreach ($cells as $cell) { + $fileData[] = $this->getNode($cell, 'Data')->item(0)->nodeValue; + } + } catch (Exception $e) { + foreach ($newUploadedFilenames as $k => $v) { + unlink($path . $v); + } + unlink($path . $uploadFile); + Mage::throwException( + Mage::helper('Dataflow')->__( + 'Upload failed. Wrong data format in file: %s.', + $uploadFile + ) + ); + } + } + + if ($this->_data['entity_type'] == 'customer') { + $attributes = $this->_customerTablePermanentAttributes; + } else { + $attributes = $this->_productTablePermanentAttributes; + } + $colsAbsent = array_diff($attributes, $fileData); + if ($colsAbsent) { + foreach ($newUploadedFilenames as $k => $v) { + unlink($path . $v); + } + unlink($path . $uploadFile); + Mage::throwException( + Mage::helper('Dataflow')->__( + 'Upload failed. Can not find required columns: %s in file %s.', + implode(', ', $colsAbsent), + $uploadFile + ) + ); + } + if ($uploadFile) { $newFilename = 'import-' . date('YmdHis') . '-' . ($index+1) . '_' . $uploadFile; rename($path . $uploadFile, $path . $newFilename); + $newUploadedFilenames[] = $newFilename; } } //BOM deleting for UTF files @@ -431,4 +497,20 @@ public function _parseGuiData() die;*/ return $this; } + + /** + * Get node from xml object + * + * @param object $xmlObject + * @param string $nodeName + * @return object + * @throws Exception + */ + protected function getNode($xmlObject, $nodeName) + { + if ($xmlObject != null) { + return $xmlObject->getElementsByTagName($nodeName); + } + Mage::throwException(Mage::helper('Dataflow')->__('Invalid node.')); + } } diff --git a/app/code/core/Mage/Directory/Model/Currency/Import/Currencyconverterapi.php b/app/code/core/Mage/Directory/Model/Currency/Import/Currencyconverterapi.php new file mode 100644 index 0000000000..55519aa906 --- /dev/null +++ b/app/code/core/Mage/Directory/Model/Currency/Import/Currencyconverterapi.php @@ -0,0 +1,199 @@ + + */ +class Mage_Directory_Model_Currency_Import_Currencyconverterapi extends Mage_Directory_Model_Currency_Import_Abstract +{ + /** + * XML path to Currency Converter timeout setting + */ + const XML_PATH_CURRENCY_CONVERTER_TIMEOUT = 'currency/currencyconverterapi/timeout'; + + /** + * XML path to Currency Converter API key setting + */ + const XML_PATH_CURRENCY_CONVERTER_API_KEY = 'currency/currencyconverterapi/api_key'; + + /** + * URL template for currency rates import + * + * @var string + */ + protected $_url = ''; + + /** + * Information messages stack + * + * @var array + */ + protected $_messages = array(); + + /** + * HTTP client + * + * @var Varien_Http_Client + */ + protected $_httpClient; + + /** + * Create and set HTTP Client + */ + public function __construct() + { + $this->_httpClient = new Varien_Http_Client(); + if (empty($this->_url)) { + $this->_url = 'https://free.currconv.com/api/v7/convert' + . '?apiKey={{API_KEY}}&q={{CURRENCY_FROM}}_{{CURRENCY_TO}}&compact=ultra'; + } + } + + /** + * @inheritdoc + */ + protected function _convert($currencyFrom, $currencyTo) + { + return 1; + } + + /** + * Fetching of the currency rates data + * + * @return array + */ + public function fetchRates() + { + $data = array(); + $currencies = $this->_getCurrencyCodes(); + $defaultCurrencies = $this->_getDefaultCurrencyCodes(); + + foreach ($defaultCurrencies as $currencyFrom) { + if (!isset($data[$currencyFrom])) { + $data[$currencyFrom] = array(); + } + + $data = $this->_convertBatch($data, $currencyFrom, $currencies); + ksort($data[$currencyFrom]); + } + + return $data; + } + + /** + * Batch import of currency rates + * + * @param array $data + * @param string $currencyFrom + * @param array $currenciesTo + * @return array + */ + protected function _convertBatch(array $data, $currencyFrom, array $currenciesTo) + { + $apiKey = Mage::getStoreConfig(self::XML_PATH_CURRENCY_CONVERTER_API_KEY); + if (empty($apiKey)) { + $this->_messages[] = Mage::helper('directory') + ->__('No API Key was specified or an invalid API Key was specified.'); + $data[$currencyFrom] = $this->_makeEmptyResponse($currenciesTo); + return $data; + } + + foreach ($currenciesTo as $currencyTo) { + $currenciesCombined = $currencyFrom . '_' . $currencyTo; + $url = str_replace( + array('{{API_KEY}}', '{{CURRENCY_FROM}}_{{CURRENCY_TO}}'), + array($apiKey, $currenciesCombined), + $this->_url + ); + + $timeLimitCalculated = 2 * (int) Mage::getStoreConfig(self::XML_PATH_CURRENCY_CONVERTER_TIMEOUT) + + (int) ini_get('max_execution_time'); + + @set_time_limit($timeLimitCalculated); + try { + $response = $this->_getServiceResponse($url); + } catch (Exception $e) { + ini_restore('max_execution_time'); + } + + if ($currencyFrom == $currencyTo) { + $data[$currencyFrom][$currencyTo] = $this->_numberFormat(1); + } else { + if (empty($response)) { + $this->_messages[] = Mage::helper('directory') + ->__('We can\'t retrieve a rate from %s for %s.', $url, $currencyTo); + $data[$currencyFrom][$currencyTo] = null; + } else { + $data[$currencyFrom][$currencyTo] = $this->_numberFormat((float) $response[$currenciesCombined]); + } + } + } + + return $data; + } + + /** + * Get response from external service + * + * @param string $url + * @param int $retry + * @return array + */ + protected function _getServiceResponse($url, $retry = 0) + { + $response = array(); + try { + $jsonResponse = $this->_httpClient + ->setUri($url) + ->setConfig(array('timeout' => Mage::getStoreConfig(self::XML_PATH_CURRENCY_CONVERTER_TIMEOUT))) + ->request('GET') + ->getBody(); + + $response = json_decode($jsonResponse, true); + } catch (Exception $e) { + if ($retry === 0) { + $response = $this->_getServiceResponse($url, 1); + } + } + + return $response; + } + + /** + * Fill simulated response with empty data + * + * @param array $currenciesTo + * @return array + */ + protected function _makeEmptyResponse(array $currenciesTo) + { + return array_fill_keys($currenciesTo, null); + } +} diff --git a/app/code/core/Mage/Directory/Model/Currency/Import/Fixerio.php b/app/code/core/Mage/Directory/Model/Currency/Import/Fixerio.php new file mode 100644 index 0000000000..24bd7433b3 --- /dev/null +++ b/app/code/core/Mage/Directory/Model/Currency/Import/Fixerio.php @@ -0,0 +1,241 @@ + + */ +class Mage_Directory_Model_Currency_Import_Fixerio extends Mage_Directory_Model_Currency_Import_Abstract +{ + /** + * XML path to Fixer.IO timeout setting + */ + const XML_PATH_FIXERIO_TIMEOUT = 'currency/fixerio/timeout'; + + /** + * XML path to Fixer.IO API key setting + */ + const XML_PATH_FIXERIO_API_KEY = 'currency/fixerio/api_key'; + + /** + * URL template for currency rates import + * + * @var string + */ + protected $_url = ''; + + /** + * Information messages stack + * + * @var array + */ + protected $_messages = array(); + + /** + * HTTP client + * + * @var Varien_Http_Client + */ + protected $_httpClient; + + /** + * Create and set HTTP Client + */ + public function __construct() + { + $this->_httpClient = new Varien_Http_Client(); + if (empty($this->_url)) { + $this->_url = 'http://data.fixer.io/api/latest' + . '?access_key={{ACCESS_KEY}}&base={{CURRENCY_FROM}}&symbols={{CURRENCY_TO}}'; + } + } + + /** + * @inheritdoc + */ + protected function _convert($currencyFrom, $currencyTo) + { + return 1; + } + + /** + * Fetching of the currency rates data + * + * @return array + */ + public function fetchRates() + { + $data = array(); + $currencies = $this->_getCurrencyCodes(); + $defaultCurrencies = $this->_getDefaultCurrencyCodes(); + + foreach ($defaultCurrencies as $currencyFrom) { + if (!isset($data[$currencyFrom])) { + $data[$currencyFrom] = array(); + } + + $data = $this->_convertBatch($data, $currencyFrom, $currencies); + ksort($data[$currencyFrom]); + } + + return $data; + } + + /** + * Batch import of currency rates + * + * @param array $data + * @param string $currencyFrom + * @param array $currenciesTo + * @return array + */ + protected function _convertBatch(array $data, $currencyFrom, array $currenciesTo) + { + $accessKey = Mage::getStoreConfig(self::XML_PATH_FIXERIO_API_KEY); + if (empty($accessKey)) { + $this->_messages[] = Mage::helper('directory') + ->__('No API Key was specified or an invalid API Key was specified.'); + $data[$currencyFrom] = $this->_makeEmptyResponse($currenciesTo); + return $data; + } + + $currenciesImploded = implode(',', $currenciesTo); + $url = str_replace( + array('{{ACCESS_KEY}}', '{{CURRENCY_FROM}}', '{{CURRENCY_TO}}'), + array($accessKey, $currencyFrom, $currenciesImploded), + $this->_url + ); + + $timeLimitCalculated = 2 * (int) Mage::getStoreConfig(self::XML_PATH_FIXERIO_TIMEOUT) + + (int) ini_get('max_execution_time'); + + @set_time_limit($timeLimitCalculated); + try { + $response = $this->_getServiceResponse($url); + } catch (Exception $e) { + ini_restore('max_execution_time'); + } + + if (!$this->_validateResponse($response, $currencyFrom)) { + $data[$currencyFrom] = $this->_makeEmptyResponse($currenciesTo); + return $data; + } + + foreach ($currenciesTo as $currencyTo) { + if ($currencyFrom == $currencyTo) { + $data[$currencyFrom][$currencyTo] = $this->_numberFormat(1); + } else { + if (empty($response['rates'][$currencyTo])) { + $this->_messages[] = Mage::helper('directory') + ->__('We can\'t retrieve a rate from %s for %s.', $url, $currencyTo); + $data[$currencyFrom][$currencyTo] = null; + } else { + $data[$currencyFrom][$currencyTo] = $this->_numberFormat((float) $response['rates'][$currencyTo]); + } + } + } + + return $data; + } + + /** + * Get response from external service + * + * @param string $url + * @param int $retry + * @return array + */ + protected function _getServiceResponse($url, $retry = 0) + { + $response = array(); + try { + $jsonResponse = $this->_httpClient + ->setUri($url) + ->setConfig(array('timeout' => Mage::getStoreConfig(self::XML_PATH_FIXERIO_TIMEOUT))) + ->request('GET') + ->getBody(); + + $response = json_decode($jsonResponse, true); + } catch (Exception $e) { + if ($retry === 0) { + $response = $this->_getServiceResponse($url, 1); + } + } + + return $response; + } + + /** + * Validate response from external service + * + * @param array $response + * @param string $baseCurrency + * @return bool + */ + protected function _validateResponse(array $response, $baseCurrency) + { + if (!$response['success']) { + $errorCodes = array( + 101 => Mage::helper('directory') + ->__('No API Key was specified or an invalid API Key was specified.'), + 102 => Mage::helper('directory') + ->__('The account this API request is coming from is inactive.'), + 104 => Mage::helper('directory') + ->__('The maximum allowed API amount of monthly API requests has been reached.'), + 105 => Mage::helper('directory') + ->__('The "%s" is not allowed as base currency for your subscription plan.', $baseCurrency), + 106 => Mage::helper('directory') + ->__('The current request did not return any results.'), + 201 => Mage::helper('directory') + ->__('An invalid base currency has been entered.'), + 202 => Mage::helper('directory') + ->__('One or more invalid symbols have been specified.'), + ); + + $this->_messages[] = isset($errorCodes[$response['error']['code']]) + ? $errorCodes[$response['error']['code']] + : Mage::helper('directory')->__('Currency rates can\'t be retrieved.'); + + return false; + } + + return true; + } + + /** + * Fill simulated response with empty data + * + * @param array $currenciesTo + * @return array + */ + protected function _makeEmptyResponse(array $currenciesTo) + { + return array_fill_keys($currenciesTo, null); + } +} diff --git a/app/code/core/Mage/Directory/Model/Currency/Import/Webservicex.php b/app/code/core/Mage/Directory/Model/Currency/Import/Webservicex.php index a220c5e822..a9306f44ac 100644 --- a/app/code/core/Mage/Directory/Model/Currency/Import/Webservicex.php +++ b/app/code/core/Mage/Directory/Model/Currency/Import/Webservicex.php @@ -30,6 +30,8 @@ * @category Mage * @package Mage_Directory * @author Magento Core Team + * + * @deprecated after 1.9.4.3 */ class Mage_Directory_Model_Currency_Import_Webservicex extends Mage_Directory_Model_Currency_Import_Abstract { diff --git a/app/code/core/Mage/Directory/etc/config.xml b/app/code/core/Mage/Directory/etc/config.xml index 4cfe78468f..991f6856dd 100644 --- a/app/code/core/Mage/Directory/etc/config.xml +++ b/app/code/core/Mage/Directory/etc/config.xml @@ -35,6 +35,14 @@ + + CurrencyConverterAPI + directory/currency_import_currencyconverterapi + + + Fixer.IO + directory/currency_import_fixerio + Webservicex directory/currency_import_webservicex @@ -141,8 +149,19 @@ USD USD + + 100 + + 1 + + + 100 + + 1 + 100 + 0 0 diff --git a/app/code/core/Mage/Directory/etc/system.xml b/app/code/core/Mage/Directory/etc/system.xml index e4f5efaffb..0e617bf403 100644 --- a/app/code/core/Mage/Directory/etc/system.xml +++ b/app/code/core/Mage/Directory/etc/system.xml @@ -77,23 +77,76 @@ - - + + 40 1 0 0 + + + select + adminhtml/system_config_source_yesno + 0 + 1 + 0 + 0 + text + 10 + 1 + 0 + 0 + + + + obscure + adminhtml/system_config_backend_encrypted + 20 + 1 + 0 + 0 + + + + + + 45 + 1 + 0 + 0 + + + + select + adminhtml/system_config_source_yesno 0 1 0 0 + + + + text + 10 + 1 + 0 + 0 + + + obscure + adminhtml/system_config_backend_encrypted + 20 + 1 + 0 + 0 + - + text diff --git a/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Abstract.php b/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Abstract.php index 9f163dae73..4d9f8c0cb4 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Abstract.php +++ b/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Abstract.php @@ -246,6 +246,15 @@ public function validate($object) return false; } + //Validate serialized data + if (!Mage::helper('core/string')->validateSerializedObject($value)) { + $label = $this->getAttribute()->getFrontend()->getLabel(); + throw Mage::exception( + 'Mage_Eav', + Mage::helper('eav')->__('The value of attribute "%s" contains invalid data.', $label) + ); + } + if ($this->getAttribute()->getIsUnique() && !$this->getAttribute()->getIsRequired() && ($value == '' || $this->getAttribute()->isValueEmpty($value))) diff --git a/app/code/core/Mage/ImportExport/Model/Import/Adapter/Abstract.php b/app/code/core/Mage/ImportExport/Model/Import/Adapter/Abstract.php index 38c969f91d..4c31f5f71b 100644 --- a/app/code/core/Mage/ImportExport/Model/Import/Adapter/Abstract.php +++ b/app/code/core/Mage/ImportExport/Model/Import/Adapter/Abstract.php @@ -183,4 +183,14 @@ public function validateSource() { return $this; } + + /** + * Get the source path + * + * @return string + */ + public function getSource() + { + return $this->_source; + } } diff --git a/app/code/core/Mage/ImportExport/Model/Import/Entity/Abstract.php b/app/code/core/Mage/ImportExport/Model/Import/Entity/Abstract.php index 7d4eaad7ce..bcb4782ef5 100644 --- a/app/code/core/Mage/ImportExport/Model/Import/Entity/Abstract.php +++ b/app/code/core/Mage/ImportExport/Model/Import/Entity/Abstract.php @@ -669,6 +669,7 @@ public function validateData() if (!$this->_dataValidated) { // does all permanent columns exists? if (($colsAbsent = array_diff($this->_permanentAttributes, $this->_getSource()->getColNames()))) { + file_put_contents($this->_getSource()->getSource(), ""); Mage::throwException( Mage::helper('importexport')->__('Can not find required columns: %s', implode(', ', $colsAbsent)) ); diff --git a/app/code/core/Mage/Install/Block/Admin.php b/app/code/core/Mage/Install/Block/Admin.php index b03ccd60e5..687d62781f 100644 --- a/app/code/core/Mage/Install/Block/Admin.php +++ b/app/code/core/Mage/Install/Block/Admin.php @@ -51,4 +51,14 @@ public function getFormData() } return $data; } + + /** + * Retrieve minimum length of admin password + * + * @return int + */ + public function getMinAdminPasswordLength() + { + return Mage::getModel('admin/user')->getMinAdminPasswordLength(); + } } diff --git a/app/code/core/Mage/Install/etc/config.xml b/app/code/core/Mage/Install/etc/config.xml index 4eb20652f3..f1b04dc0cc 100644 --- a/app/code/core/Mage/Install/etc/config.xml +++ b/app/code/core/Mage/Install/etc/config.xml @@ -57,6 +57,13 @@ + + + + + + + diff --git a/app/code/core/Mage/Review/controllers/ProductController.php b/app/code/core/Mage/Review/controllers/ProductController.php index d14be3ee8d..671b09bf35 100644 --- a/app/code/core/Mage/Review/controllers/ProductController.php +++ b/app/code/core/Mage/Review/controllers/ProductController.php @@ -304,7 +304,17 @@ protected function _initProductLayout($product) $this->getLayout()->helper('page/layout') ->applyTemplate($product->getPageLayout()); } - $update->addUpdate($product->getCustomLayoutUpdate()); + $customLayout = $product->getCustomLayoutUpdate(); + if ($customLayout) { + try { + if (!Mage::getModel('core/layout_validator')->isValid($customLayout)) { + $customLayout = ''; + } + } catch (Exception $e) { + $customLayout = ''; + } + } + $update->addUpdate($customLayout); $this->generateLayoutXml()->generateLayoutBlocks(); } diff --git a/app/code/core/Mage/Rss/etc/config.xml b/app/code/core/Mage/Rss/etc/config.xml index 29cec917a4..f574bad4cf 100644 --- a/app/code/core/Mage/Rss/etc/config.xml +++ b/app/code/core/Mage/Rss/etc/config.xml @@ -123,4 +123,13 @@ + + + + + + + + + diff --git a/app/code/core/Mage/Widget/controllers/Adminhtml/Widget/InstanceController.php b/app/code/core/Mage/Widget/controllers/Adminhtml/Widget/InstanceController.php index 6f1d498f8c..6b5fd88f25 100644 --- a/app/code/core/Mage/Widget/controllers/Adminhtml/Widget/InstanceController.php +++ b/app/code/core/Mage/Widget/controllers/Adminhtml/Widget/InstanceController.php @@ -295,6 +295,17 @@ public function templateAction() $this->setBody($templateChooser->toHtml()); } + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions('delete'); + return parent::preDispatch(); + } + /** * Check is allowed access to action * diff --git a/app/code/core/Mage/Wishlist/Block/Abstract.php b/app/code/core/Mage/Wishlist/Block/Abstract.php index 994ba19348..ca08986906 100644 --- a/app/code/core/Mage/Wishlist/Block/Abstract.php +++ b/app/code/core/Mage/Wishlist/Block/Abstract.php @@ -168,7 +168,7 @@ public function getWishlist() */ public function getItemRemoveUrl($item) { - return $this->_getHelper()->getRemoveUrl($item); + return $this->getItemRemoveUrlCustom($item); } /** @@ -179,7 +179,7 @@ public function getItemRemoveUrl($item) */ public function getItemAddToCartUrl($item) { - return $this->_getHelper()->getAddToCartUrl($item); + return $this->getItemAddToCartUrlCustom($item); } /** @@ -201,7 +201,7 @@ public function getSharedItemAddToCartUrl($item) */ public function getAddToWishlistUrl($product) { - return $this->_getHelper()->getAddUrl($product); + return $this->getAddToWishlistUrlCustom($product); } /** @@ -408,4 +408,49 @@ public function getProductUrl($item, $additional = array()) } return parent::getProductUrl($product, $additional); } + + /** + * Retrieve URL for adding Product to wishlist with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param bool $addFormKey + * @return string + */ + public function getAddToWishlistUrlCustom($product, $addFormKey = true) + { + if (!$addFormKey) { + return $this->_getHelper()->getAddUrlWithCustomParams($product, array(), false); + } + return $this->_getHelper()->getAddUrl($product); + } + + /** + * Retrieve URL for Removing item from wishlist with or without Form Key + * + * @param Mage_Catalog_Model_Product|Mage_Wishlist_Model_Item $item + * @param bool $addFormKey + * @return string + */ + public function getItemRemoveUrlCustom($item, $addFormKey = true) + { + if (!$addFormKey) { + return $this->_getHelper()->getRemoveUrlCustom($item, false); + } + return $this->_getHelper()->getRemoveUrl($item); + } + + /** + * Retrieve Add Item to shopping cart URL with or without Form Key + * + * @param string|Mage_Catalog_Model_Product|Mage_Wishlist_Model_Item $item + * @param bool $addFormKey + * @return string + */ + public function getItemAddToCartUrlCustom($item, $addFormKey = true) + { + if (!$addFormKey) { + return $this->_getHelper()->getAddToCartUrlCustom($item, false); + } + return $this->_getHelper()->getAddToCartUrl($item); + } } diff --git a/app/code/core/Mage/Wishlist/Block/Customer/Wishlist/Item/Column/Cart.php b/app/code/core/Mage/Wishlist/Block/Customer/Wishlist/Item/Column/Cart.php index 8e1dccba1a..da835ea36e 100644 --- a/app/code/core/Mage/Wishlist/Block/Customer/Wishlist/Item/Column/Cart.php +++ b/app/code/core/Mage/Wishlist/Block/Customer/Wishlist/Item/Column/Cart.php @@ -54,7 +54,16 @@ public function getJs() { $js = " function addWItemToCart(itemId) { - var url = '" . $this->getItemAddToCartUrl('%item%') . "'; + addWItemToCartCustom(itemId, true) + } + + function addWItemToCartCustom(itemId, sendGet) { + var url = ''; + if (sendGet) { + url = '" . $this->getItemAddToCartUrl('%item%') . "'; + } else { + url = '" . $this->getItemAddToCartUrlCustom('%item%', false) . "'; + } url = url.gsub('%item%', itemId); var form = $('wishlist-view-form'); if (form) { @@ -64,7 +73,11 @@ function addWItemToCart(itemId) { url += separator + input.name + '=' + encodeURIComponent(input.value); } } - setLocation(url); + if (sendGet) { + setLocation(url); + } else { + customFormSubmit(url, '" . json_encode(array('form_key' => $this->getFormKey())) . "', 'post'); + } } "; diff --git a/app/code/core/Mage/Wishlist/Block/Item/Configure.php b/app/code/core/Mage/Wishlist/Block/Item/Configure.php index e07ac9ac4e..92a775064b 100644 --- a/app/code/core/Mage/Wishlist/Block/Item/Configure.php +++ b/app/code/core/Mage/Wishlist/Block/Item/Configure.php @@ -65,7 +65,9 @@ protected function _prepareLayout() $block = $this->getLayout()->getBlock('product.info'); if ($block) { $url = Mage::helper('wishlist')->getAddToCartUrl($this->getWishlistItem()); + $postUrl = Mage::helper('wishlist')->getAddToCartUrlCustom($this->getWishlistItem(), false); $block->setCustomAddToCartUrl($url); + $block->setCustomAddToCartPostUrl($postUrl); } return parent::_prepareLayout(); diff --git a/app/code/core/Mage/Wishlist/Block/Share/Email/Items.php b/app/code/core/Mage/Wishlist/Block/Share/Email/Items.php index cde78268db..8cf718b7c2 100644 --- a/app/code/core/Mage/Wishlist/Block/Share/Email/Items.php +++ b/app/code/core/Mage/Wishlist/Block/Share/Email/Items.php @@ -66,9 +66,7 @@ public function getProductUrl($product, $additional = array()) */ public function getAddToCartUrl($product, $additional = array()) { - $additional['nocookie'] = 1; - $additional['_store_to_url'] = true; - return parent::getAddToCartUrl($product, $additional); + return $this->getAddToCartUrlCustom($product, $additional); } /** @@ -85,4 +83,19 @@ public function hasDescription($item) } return $hasDescription; } + + /** + * Retrieve URL for add product to shopping cart with or without Form Key + * + * @param Mage_Catalog_Model_Product $product + * @param array $additional + * @param bool $addFormKey + * @return string + */ + public function getAddToCartUrlCustom($product, $additional = array(), $addFormKey = true) + { + $additional['nocookie'] = 1; + $additional['_store_to_url'] = true; + return parent::getAddToCartUrlCustom($product, $additional, $addFormKey); + } } diff --git a/app/code/core/Mage/Wishlist/Helper/Data.php b/app/code/core/Mage/Wishlist/Helper/Data.php index 734e59e2c4..2f1137a2df 100644 --- a/app/code/core/Mage/Wishlist/Helper/Data.php +++ b/app/code/core/Mage/Wishlist/Helper/Data.php @@ -273,12 +273,7 @@ protected function _getUrlStore($item) */ public function getRemoveUrl($item) { - return $this->_getUrl('wishlist/index/remove', - array( - 'item' => $item->getWishlistItemId(), - Mage_Core_Model_Url::FORM_KEY => $this->_getSingletonModel('core/session')->getFormKey() - ) - ); + return $this->getRemoveUrlCustom($item); } /** @@ -352,21 +347,7 @@ public function getUpdateUrl($item) */ public function getAddUrlWithParams($item, array $params = array()) { - $productId = null; - if ($item instanceof Mage_Catalog_Model_Product) { - $productId = $item->getEntityId(); - } - if ($item instanceof Mage_Wishlist_Model_Item) { - $productId = $item->getProductId(); - } - - if ($productId) { - $params['product'] = $productId; - $params[Mage_Core_Model_Url::FORM_KEY] = $this->_getSingletonModel('core/session')->getFormKey(); - return $this->_getUrlStore($item)->getUrl('wishlist/index/add', $params); - } - - return false; + return $this->getAddUrlWithCustomParams($item, $params); } /** @@ -377,19 +358,7 @@ public function getAddUrlWithParams($item, array $params = array()) */ public function getAddToCartUrl($item) { - $continueUrl = $this->_getHelperInstance('core')->urlEncode( - $this->_getUrl('*/*/*', array( - '_current' => true, - '_use_rewrite' => true, - '_store_to_url' => true, - )) - ); - $params = array( - 'item' => is_string($item) ? $item : $item->getWishlistItemId(), - Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $continueUrl, - Mage_Core_Model_Url::FORM_KEY => $this->_getSingletonModel('core/session')->getFormKey() - ); - return $this->_getUrlStore($item)->getUrl('wishlist/index/cart', $params); + return $this->getAddToCartUrlCustom($item); } /** @@ -592,4 +561,78 @@ public function isDisplayQty() { return Mage::getStoreConfig(self::XML_PATH_WISHLIST_LINK_USE_QTY); } + + /** + * Retrieve url for adding product to wishlist with params with or without Form Key + * + * @param Mage_Catalog_Model_Product|Mage_Wishlist_Model_Item $item + * @param array $params + * @param bool $addFormKey + * @return string|bool + */ + public function getAddUrlWithCustomParams($item, array $params = array(), $addFormKey = true) + { + $productId = null; + if ($item instanceof Mage_Catalog_Model_Product) { + $productId = $item->getEntityId(); + } + if ($item instanceof Mage_Wishlist_Model_Item) { + $productId = $item->getProductId(); + } + + if ($productId) { + $params['product'] = $productId; + if ($addFormKey) { + $params[Mage_Core_Model_Url::FORM_KEY] = $this->_getSingletonModel('core/session')->getFormKey(); + } + return $this->_getUrlStore($item)->getUrl('wishlist/index/add', $params); + } + + return false; + } + + /** + * Retrieve URL for removing item from wishlist with params with or without Form Key + * + * @param Mage_Catalog_Model_Product|Mage_Wishlist_Model_Item $item + * @param bool $addFormKey + * @return string + */ + public function getRemoveUrlCustom($item, $addFormKey = true) + { + $params = array( + 'item' => $item->getWishlistItemId() + ); + if ($addFormKey) { + $params[Mage_Core_Model_Url::FORM_KEY] = $this->_getSingletonModel('core/session')->getFormKey(); + } + + return $this->_getUrl('wishlist/index/remove', $params); + } + + /** + * Retrieve URL for adding item to shopping cart with or without Form Key + * + * @param string|Mage_Catalog_Model_Product|Mage_Wishlist_Model_Item $item + * @param bool $addFormKey + * @return string + */ + public function getAddToCartUrlCustom($item, $addFormKey = true) + { + $continueUrl = $this->_getHelperInstance('core')->urlEncode( + $this->_getUrl('*/*/*', array( + '_current' => true, + '_use_rewrite' => true, + '_store_to_url' => true, + )) + ); + $params = array( + 'item' => is_string($item) ? $item : $item->getWishlistItemId(), + Mage_Core_Controller_Front_Action::PARAM_NAME_URL_ENCODED => $continueUrl, + ); + if ($addFormKey) { + $params[Mage_Core_Model_Url::FORM_KEY] = $this->_getSingletonModel('core/session')->getFormKey(); + } + return $this->_getUrlStore($item)->getUrl('wishlist/index/cart', $params); + } } diff --git a/app/code/core/Mage/Wishlist/controllers/IndexController.php b/app/code/core/Mage/Wishlist/controllers/IndexController.php index 88d77e5107..f322f2ed9d 100644 --- a/app/code/core/Mage/Wishlist/controllers/IndexController.php +++ b/app/code/core/Mage/Wishlist/controllers/IndexController.php @@ -137,6 +137,13 @@ public function indexAction() } $this->loadLayout(); + if ($this->_isFormKeyEnabled() && strpos($this->_getRefererUrl(), 'login')) { + Mage::getSingleton('core/session')->addError(Mage::helper('wishlist')->__( + 'Please add product to wishlist again.' + )); + return $this->_redirectUrl(Mage::getSingleton('customer/session')->getBeforeWishlistUrl()); + } + $session = Mage::getSingleton('customer/session'); $block = $this->getLayout()->getBlock('customer.wishlist'); $referer = $session->getAddActionReferer(true); diff --git a/app/code/core/Mage/XmlConnect/Helper/Translate.php b/app/code/core/Mage/XmlConnect/Helper/Translate.php index 69be2e0fab..2e4d04e5b5 100644 --- a/app/code/core/Mage/XmlConnect/Helper/Translate.php +++ b/app/code/core/Mage/XmlConnect/Helper/Translate.php @@ -328,7 +328,8 @@ public function getLocalizationArray() 'OtherAmount' => $this->__('Other amount'), 'OutOfStock' => $this->__('Out of Stock'), 'ParsingError' => $this->__('Error while reading remote data'), - 'PasswordLength' => $this->__('The minimum password length is 6'), + 'PasswordLength' => $this->__('The minimum password length is ') + . Mage::getModel('customer/customer')->getMinPasswordLength(), 'PayPalCheckout' => $this->__('PayPal Checkout'), 'PayPalText' => $this->__('PayPal'), 'PaymentBridgeServiceErrorMessage' => $this->__('Unknown Payment Bridge Error'), diff --git a/app/design/adminhtml/default/default/template/resetforgottenpassword.phtml b/app/design/adminhtml/default/default/template/resetforgottenpassword.phtml index 8f0bbb490a..508ae90a82 100644 --- a/app/design/adminhtml/default/default/template/resetforgottenpassword.phtml +++ b/app/design/adminhtml/default/default/template/resetforgottenpassword.phtml @@ -50,12 +50,21 @@
getMessagesBlock()->toHtml(); ?>
-
+

- + +

+ + __('Password must be at least of %d characters.', $minAdminPasswordLength); ?> + +

diff --git a/app/design/frontend/base/default/template/bundle/catalog/product/view/option_tierprices.phtml b/app/design/frontend/base/default/template/bundle/catalog/product/view/option_tierprices.phtml index 61b1a04b5d..257e048a8a 100644 --- a/app/design/frontend/base/default/template/bundle/catalog/product/view/option_tierprices.phtml +++ b/app/design/frontend/base/default/template/bundle/catalog/product/view/option_tierprices.phtml @@ -197,9 +197,9 @@ if (Mage::helper('weee')->typeOfDisplay($_product, array(1,2,4))) { __('Click for price'); ?> diff --git a/app/design/frontend/base/default/template/catalog/product/price_msrp_noform.phtml b/app/design/frontend/base/default/template/catalog/product/price_msrp_noform.phtml index f56f929bc7..0be6495ae9 100644 --- a/app/design/frontend/base/default/template/catalog/product/price_msrp_noform.phtml +++ b/app/design/frontend/base/default/template/catalog/product/price_msrp_noform.phtml @@ -48,7 +48,7 @@ diff --git a/app/design/frontend/rwd/default/template/catalog/product/compare/list.phtml b/app/design/frontend/rwd/default/template/catalog/product/compare/list.phtml index e2bdf12462..3850b423fd 100644 --- a/app/design/frontend/rwd/default/template/catalog/product/compare/list.phtml +++ b/app/design/frontend/rwd/default/template/catalog/product/compare/list.phtml @@ -30,6 +30,7 @@ __('Print This Page') ?>
getItems()->count() ?> +escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); ?> @@ -75,13 +76,30 @@ @@ -128,13 +146,32 @@ diff --git a/app/design/frontend/rwd/default/template/catalog/product/list.phtml b/app/design/frontend/rwd/default/template/catalog/product/list.phtml index dd66f5dc4b..13849deb15 100644 --- a/app/design/frontend/rwd/default/template/catalog/product/list.phtml +++ b/app/design/frontend/rwd/default/template/catalog/product/list.phtml @@ -35,6 +35,7 @@ getLoadedProductCollection(); $_helper = $this->helper('catalog/output'); + $_params = $this->escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); ?> count()): ?>

__('There are no products matching the selection.') ?>

@@ -87,7 +88,17 @@
canConfigure() && $_product->isSaleable()): ?> -

+

+ +

getStockItem() && $_product->getStockItem()->getIsInStock()): ?>

__('View Details') ?>

@@ -95,10 +106,26 @@
@@ -150,7 +177,15 @@
canConfigure() && $_product->isSaleable()): ?> - + getStockItem() && $_product->getStockItem()->getIsInStock()): ?> __('View Details') ?> @@ -158,10 +193,26 @@
diff --git a/app/design/frontend/rwd/default/template/catalog/product/list/related.phtml b/app/design/frontend/rwd/default/template/catalog/product/list/related.phtml index 1de1078e2f..4c98bab8e9 100644 --- a/app/design/frontend/rwd/default/template/catalog/product/list/related.phtml +++ b/app/design/frontend/rwd/default/template/catalog/product/list/related.phtml @@ -45,7 +45,14 @@

escapeHtml($_item->getName()) ?>

getPriceHtml($_item, true, '-related') ?> helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?> + + __('Add to Wishlist') ?> + diff --git a/app/design/frontend/rwd/default/template/catalog/product/view.phtml b/app/design/frontend/rwd/default/template/catalog/product/view.phtml index 8c22d55a6a..212c91c359 100644 --- a/app/design/frontend/rwd/default/template/catalog/product/view.phtml +++ b/app/design/frontend/rwd/default/template/catalog/product/view.phtml @@ -39,7 +39,10 @@
getMessagesBlock()->toHtml() ?>
-
getOptions()): ?> enctype="multipart/form-data"> + getOptions()): ?> enctype="multipart/form-data" > getBlockHtml('formkey') ?>
diff --git a/app/design/frontend/rwd/default/template/catalog/product/view/addto.phtml b/app/design/frontend/rwd/default/template/catalog/product/view/addto.phtml index 0cc3ff1d6a..2e582127f3 100644 --- a/app/design/frontend/rwd/default/template/catalog/product/view/addto.phtml +++ b/app/design/frontend/rwd/default/template/catalog/product/view/addto.phtml @@ -26,17 +26,31 @@ ?> getProduct(); ?> -helper('wishlist')->getAddUrl($_product); ?> +helper('wishlist')->getAddUrlWithCustomParams($_product, array(), false); ?> +escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); ?> diff --git a/app/design/frontend/rwd/default/template/catalog/product/view/sharing.phtml b/app/design/frontend/rwd/default/template/catalog/product/view/sharing.phtml index b3d2389813..8fb84a4e86 100644 --- a/app/design/frontend/rwd/default/template/catalog/product/view/sharing.phtml +++ b/app/design/frontend/rwd/default/template/catalog/product/view/sharing.phtml @@ -26,7 +26,7 @@ ?> getProduct(); ?> -helper('wishlist')->getAddUrl($_product); ?> +helper('wishlist')->getAddUrlWithCustomParams($_product, array(), false); ?>
diff --git a/app/design/frontend/rwd/default/template/checkout/cart/shipping.phtml b/app/design/frontend/rwd/default/template/checkout/cart/shipping.phtml index 39004bea3c..542a663069 100644 --- a/app/design/frontend/rwd/default/template/checkout/cart/shipping.phtml +++ b/app/design/frontend/rwd/default/template/checkout/cart/shipping.phtml @@ -87,7 +87,7 @@ getEstimateRates())): ?> - +
$_rates): ?>
escapeHtml($this->getCarrierName($code)) ?>
diff --git a/app/design/frontend/rwd/default/template/checkout/cart/sidebar/default.phtml b/app/design/frontend/rwd/default/template/checkout/cart/sidebar/default.phtml index 341c953fc0..f337ba49ac 100644 --- a/app/design/frontend/rwd/default/template/checkout/cart/sidebar/default.phtml +++ b/app/design/frontend/rwd/default/template/checkout/cart/sidebar/default.phtml @@ -36,7 +36,14 @@ <?php echo $this->escapeHtml($this->getProductName()) ?>
- __('Remove This Item') ?> + + __('Remove This Item') ?> +

hasProductUrl()): ?>escapeHtml($this->getProductName()) ?>hasProductUrl()): ?>

__('Edit item')?> diff --git a/app/design/frontend/rwd/default/template/checkout/onepage/review/info.phtml b/app/design/frontend/rwd/default/template/checkout/onepage/review/info.phtml index 29426a5df6..db8ac95d8a 100644 --- a/app/design/frontend/rwd/default/template/checkout/onepage/review/info.phtml +++ b/app/design/frontend/rwd/default/template/checkout/onepage/review/info.phtml @@ -79,7 +79,7 @@
diff --git a/app/design/frontend/rwd/default/template/customer/form/changepassword.phtml b/app/design/frontend/rwd/default/template/customer/form/changepassword.phtml index 37a3d192e4..b6a32afcba 100644 --- a/app/design/frontend/rwd/default/template/customer/form/changepassword.phtml +++ b/app/design/frontend/rwd/default/template/customer/form/changepassword.phtml @@ -43,7 +43,15 @@
- + getCustomer()->getMinPasswordLength(), Mage_Core_Model_App::ABSOLUTE_MIN_PASSWORD_LENGTH); ?> + +

+ __('The minimum password length is %s', $minPasswordLength) ?> +

diff --git a/app/design/frontend/rwd/default/template/customer/form/edit.phtml b/app/design/frontend/rwd/default/template/customer/form/edit.phtml index 789a8b965f..21465588cf 100644 --- a/app/design/frontend/rwd/default/template/customer/form/edit.phtml +++ b/app/design/frontend/rwd/default/template/customer/form/edit.phtml @@ -75,7 +75,15 @@
- + getCustomer()->getMinPasswordLength(); ?> + +

+ __('The minimum password length is %s', $minPasswordLength) ?> +

diff --git a/app/design/frontend/rwd/default/template/customer/form/resetforgottenpassword.phtml b/app/design/frontend/rwd/default/template/customer/form/resetforgottenpassword.phtml index 1810ac709a..ef953a7a6f 100644 --- a/app/design/frontend/rwd/default/template/customer/form/resetforgottenpassword.phtml +++ b/app/design/frontend/rwd/default/template/customer/form/resetforgottenpassword.phtml @@ -36,7 +36,14 @@
- + getMinPasswordLength(); ?> + +

+ __('The minimum password length is %s', $minPasswordLength); ?> +

diff --git a/app/design/frontend/rwd/default/template/downloadable/checkout/cart/item/default.phtml b/app/design/frontend/rwd/default/template/downloadable/checkout/cart/item/default.phtml index ba713947af..e29e68c4f2 100644 --- a/app/design/frontend/rwd/default/template/downloadable/checkout/cart/item/default.phtml +++ b/app/design/frontend/rwd/default/template/downloadable/checkout/cart/item/default.phtml @@ -28,6 +28,8 @@ $_item = $this->getItem(); $isVisibleProduct = $_item->getProduct()->isVisibleInSiteVisibility(); $canApplyMsrp = Mage::helper('catalog')->canApplyMsrp($_item->getProduct(), Mage_Catalog_Model_Product_Attribute_Source_Msrp_Type::TYPE_BEFORE_ORDER_CONFIRM); +$_params = $this->escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); +$_deleteUrl = $this->getDeleteUrlCustom(false); ?>
- + diff --git a/app/design/frontend/rwd/default/template/email/catalog/product/list.phtml b/app/design/frontend/rwd/default/template/email/catalog/product/list.phtml index 33c916928d..9aeddec9b0 100644 --- a/app/design/frontend/rwd/default/template/email/catalog/product/list.phtml +++ b/app/design/frontend/rwd/default/template/email/catalog/product/list.phtml @@ -35,6 +35,7 @@ getLoadedProductCollection(); $_helper = $this->helper('catalog/output'); +$_params = $this->escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); ?> count()): ?>

__('There are no products matching the selection.') ?>

@@ -87,7 +88,17 @@ $_helper = $this->helper('catalog/output');
canConfigure() && $_product->isSaleable()): ?> -

+

+ +

getStockItem() && $_product->getStockItem()->getIsInStock()): ?>

__('View Details') ?>

@@ -95,10 +106,24 @@ $_helper = $this->helper('catalog/output');
@@ -150,7 +175,15 @@ $_helper = $this->helper('catalog/output');
canConfigure() && $_product->isSaleable()): ?> - + getStockItem() && $_product->getStockItem()->getIsInStock()): ?> __('View Details') ?> @@ -158,10 +191,26 @@ $_helper = $this->helper('catalog/output');
diff --git a/app/design/frontend/rwd/default/template/persistent/checkout/onepage/billing.phtml b/app/design/frontend/rwd/default/template/persistent/checkout/onepage/billing.phtml index d92b96af6b..21321e2d91 100644 --- a/app/design/frontend/rwd/default/template/persistent/checkout/onepage/billing.phtml +++ b/app/design/frontend/rwd/default/template/persistent/checkout/onepage/billing.phtml @@ -160,7 +160,15 @@
- + getQuote()->getCustomer()->getMinPasswordLength(); ?> + +

+ __('The minimum password length is %s', $minPasswordLength) ?> +

diff --git a/app/design/frontend/rwd/default/template/persistent/checkout/onepage/login.phtml b/app/design/frontend/rwd/default/template/persistent/checkout/onepage/login.phtml index ff0494d497..b24645a46b 100644 --- a/app/design/frontend/rwd/default/template/persistent/checkout/onepage/login.phtml +++ b/app/design/frontend/rwd/default/template/persistent/checkout/onepage/login.phtml @@ -102,7 +102,7 @@
  • - +
  • diff --git a/app/design/frontend/rwd/default/template/persistent/customer/form/login.phtml b/app/design/frontend/rwd/default/template/persistent/customer/form/login.phtml index 4bf18be77f..9d7e4193d8 100644 --- a/app/design/frontend/rwd/default/template/persistent/customer/form/login.phtml +++ b/app/design/frontend/rwd/default/template/persistent/customer/form/login.phtml @@ -76,7 +76,7 @@
  • - +
  • getChildHtml('form.additional.info'); ?> diff --git a/app/design/frontend/rwd/default/template/persistent/customer/form/register.phtml b/app/design/frontend/rwd/default/template/persistent/customer/form/register.phtml index eb9edf7c66..5104c34201 100644 --- a/app/design/frontend/rwd/default/template/persistent/customer/form/register.phtml +++ b/app/design/frontend/rwd/default/template/persistent/customer/form/register.phtml @@ -147,7 +147,15 @@
    - + getMinPasswordLength(); ?> + +

    + __('The minimum password length is %s', $minPasswordLength) ?> +

    diff --git a/app/design/frontend/rwd/default/template/reports/widget/compared/content/compared_grid.phtml b/app/design/frontend/rwd/default/template/reports/widget/compared/content/compared_grid.phtml index 86c15d5fd4..e4503d3818 100644 --- a/app/design/frontend/rwd/default/template/reports/widget/compared/content/compared_grid.phtml +++ b/app/design/frontend/rwd/default/template/reports/widget/compared/content/compared_grid.phtml @@ -31,6 +31,7 @@
    getColumnCount(); ?> + escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); ?>
      @@ -45,16 +46,39 @@ getReviewsSummaryHtml($_product, 'short') ?>
      isSaleable()): ?> - +

      __('Out of stock') ?>

      diff --git a/app/design/frontend/rwd/default/template/reports/widget/viewed/content/viewed_grid.phtml b/app/design/frontend/rwd/default/template/reports/widget/viewed/content/viewed_grid.phtml index 94a1ec74a4..246f2de1c8 100644 --- a/app/design/frontend/rwd/default/template/reports/widget/viewed/content/viewed_grid.phtml +++ b/app/design/frontend/rwd/default/template/reports/widget/viewed/content/viewed_grid.phtml @@ -36,6 +36,7 @@
    getColumnCount(); ?> + escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); ?>
    • @@ -49,16 +50,40 @@ getReviewsSummaryHtml($_product, 'short') ?>
      isSaleable()): ?> - +

      __('Out of stock') ?>

      diff --git a/app/design/frontend/rwd/default/template/wishlist/item/column/cart.phtml b/app/design/frontend/rwd/default/template/wishlist/item/column/cart.phtml index 6549c2a37d..d9602bd351 100644 --- a/app/design/frontend/rwd/default/template/wishlist/item/column/cart.phtml +++ b/app/design/frontend/rwd/default/template/wishlist/item/column/cart.phtml @@ -34,7 +34,12 @@ $options = $this->getChild('customer.wishlist.item.options') ?>
      isSaleable()): ?> - + getIsSalable()): ?>

      diff --git a/app/design/frontend/rwd/default/template/wishlist/shared.phtml b/app/design/frontend/rwd/default/template/wishlist/shared.phtml index 1bd87dd710..6d95bd31dd 100644 --- a/app/design/frontend/rwd/default/template/wishlist/shared.phtml +++ b/app/design/frontend/rwd/default/template/wishlist/shared.phtml @@ -45,6 +45,7 @@

    + escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); ?> getWishlistItems() as $item): ?> getProduct(); @@ -64,7 +65,16 @@ -

    __('Add to Wishlist') ?>

    +

    + getAddToWishlistUrlCustom($item, false); ?> + + __('Add to Wishlist') ?> + +

    diff --git a/app/design/frontend/rwd/default/template/wishlist/sidebar.phtml b/app/design/frontend/rwd/default/template/wishlist/sidebar.phtml index f48eb4012e..e066bb5095 100644 --- a/app/design/frontend/rwd/default/template/wishlist/sidebar.phtml +++ b/app/design/frontend/rwd/default/template/wishlist/sidebar.phtml @@ -34,15 +34,27 @@

    __('Last Added Items') ?>

    hasWishlistItems()): ?>
      - getWishlistItems() as $_item): ?> + getWishlistItems() as $_item): ?> getProduct(); ?> + escapeHtml(json_encode(array('form_key' => $this->getFormKey()))); ?>
    1. <?php echo $this->escapeHtml($product->getName()) ?>
      - __('Remove This Item') ?> + + __('Remove This Item') ?> +

      escapeHtml($product->getName()) ?>

      isSaleable() && $product->isVisibleInSiteVisibility()): ?> - __('Add to Cart') ?> + + __('Add to Cart') ?> + getPriceHtml($product, false, '-wishlist') ?>
      diff --git a/app/design/install/default/default/template/install/create_admin.phtml b/app/design/install/default/default/template/install/create_admin.phtml index 54d12d3c2a..03ec63ccc0 100644 --- a/app/design/install/default/default/template/install/create_admin.phtml +++ b/app/design/install/default/default/template/install/create_admin.phtml @@ -68,7 +68,18 @@
      - + getMinAdminPasswordLength(); ?> + +

      + + __('Password must be at least of %d characters.', $minAdminPasswordLength) ?> + +

    isSaleable()): ?> -

    +

    __('Out of stock') ?>

    helper('wishlist')->isAllow()) : ?> + getAddToWishlistUrlCustom($_item, false); ?>
    getPriceHtml($_item, true, '-compare-list-bottom') ?> isSaleable()): ?> -

    +

    + +

    __('Out of stock') ?>

    helper('wishlist')->isAllow()) : ?> + getAddToWishlistUrlCustom($_item, false); ?>
    @@ -56,7 +58,12 @@ $canApplyMsrp = Mage::helper('catalog')->canApplyMsrp($_item->getProduct(), Mage - __('Remove Item') ?> + + __('Remove Item') ?> +

    hasProductUrl()):?> @@ -325,7 +332,12 @@ $canApplyMsrp = Mage::helper('catalog')->canApplyMsrp($_item->getProduct(), Mage

    - __('Remove Item') ?> + + __('Remove Item') ?> +
    canApplyMsrp($_item->getProduct(), Mage - __('Remove Item') ?> + + __('Remove Item') ?> +

    escapeHtml($this->getProductName()) ?>

    @@ -341,6 +348,12 @@ $canApplyMsrp = Mage::helper('catalog')->canApplyMsrp($_item->getProduct(), Mage
    __('Remove Item') ?> + + __('Remove Item') ?> + +