From 04970bf892ff3265f84caea7dc6f1caf9656ab31 Mon Sep 17 00:00:00 2001 From: Andreas Mautz Date: Fri, 29 Jun 2018 12:21:40 +0200 Subject: [PATCH] Magento Community 1.9.3.9 --- README.md | 20 + RELEASE_NOTES.txt | 16 +- app/Mage.php | 2 +- app/code/core/Mage/Admin/Model/User.php | 19 + .../Product/Composite/Fieldset/Options.php | 3 + .../Product/Edit/Tab/Options/Option.php | 2 +- .../Widget/Grid/Column/Filter/Datetime.php | 5 +- .../Model/LayoutUpdate/Validator.php | 23 +- .../Catalog/CategoryController.php | 3 + .../controllers/Catalog/ProductController.php | 1 + .../Cms/Wysiwyg/ImagesController.php | 1 + .../controllers/Cms/WysiwygController.php | 1 + .../controllers/CustomerController.php | 1 + .../controllers/System/StoreController.php | 10 + app/code/core/Mage/Catalog/Model/Product.php | 8 + .../Catalog/Model/Resource/Category/Tree.php | 3 + app/code/core/Mage/Catalog/Model/Url.php | 72 ++- .../Checkout/Model/Api/Resource/Customer.php | 1 + .../core/Mage/Checkout/Model/Type/Onepage.php | 3 + .../Checkout/controllers/CartController.php | 5 + app/code/core/Mage/Core/Helper/Http.php | 7 +- .../Core/Model/Session/Abstract/Varien.php | 24 + app/code/core/Mage/Customer/Helper/Data.php | 17 + .../Mage/Customer/Model/Resource/Customer.php | 3 +- .../controllers/AccountController.php | 3 + app/code/core/Mage/Log/Model/Visitor.php | 2 +- app/code/core/Mage/Usa/Helper/Data.php | 19 + .../Carrier/Abstract/Backend/Abstract.php | 100 +++ .../Carrier/Ups/Backend/Freemethod.php | 57 ++ .../Carrier/Ups/Backend/OriginShipment.php | 57 ++ .../Shipping/Carrier/Ups/Backend/Type.php | 56 ++ app/code/core/Mage/Usa/etc/system.xml | 3 + app/code/core/Zend/Filter/PregReplace.php | 183 ++++++ app/code/core/Zend/Validate/EmailAddress.php | 579 ++++++++++++++++++ .../bundle/product/edit/bundle/option.phtml | 1 + .../template/system/shipping/ups.phtml | 9 + .../downloadable/catalog/product/links.phtml | 2 +- .../checkout/cart/item/default.phtml | 2 +- .../checkout/onepage/review/item.phtml | 2 +- .../order/items/renderer/downloadable.phtml | 2 +- .../checkout/cart/item/default.phtml | 2 +- .../checkout/onepage/review/item.phtml | 2 +- .../checkout/cart/item/default.phtml | 2 +- .../checkout/onepage/review/item.phtml | 2 +- .../order/items/renderer/downloadable.phtml | 2 +- app/etc/applied.patches.list | 8 - app/locale/en_US/Mage_Catalog.csv | 1 + app/locale/en_US/Mage_Usa.csv | 2 + cron.php | 11 +- downloader/Maged/Controller.php | 2 +- js/tiny_mce/plugins/media/.htaccess | 7 + lib/Varien/Image/Adapter/Gd2.php | 12 +- ....9.3.8.xml => Cm_RedisSession-1.9.3.9.xml} | 10 +- ...> Interface_Adminhtml_Default-1.9.3.9.xml} | 12 +- ...terface_Frontend_Base_Default-1.9.3.9.xml} | 12 +- ...=> Interface_Frontend_Default-1.9.3.9.xml} | 10 +- ...nterface_Frontend_Rwd_Default-1.9.3.9.xml} | 12 +- ... => Interface_Install_Default-1.9.3.9.xml} | 10 +- ...{Lib_Cm-1.9.3.8.xml => Lib_Cm-1.9.3.9.xml} | 10 +- ...dis-1.9.3.8.xml => Lib_Credis-1.9.3.9.xml} | 8 +- ....8.xml => Lib_Google_Checkout-1.9.3.9.xml} | 8 +- ...DNA2-1.9.3.8.xml => Lib_IDNA2-1.9.3.9.xml} | 8 +- ...1.14.xml => Lib_Js_Calendar-1.51.1.15.xml} | 8 +- ...Ext-1.9.3.8.xml => Lib_Js_Ext-1.9.3.9.xml} | 8 +- ...ge-1.9.3.8.xml => Lib_Js_Mage-1.9.3.9.xml} | 10 +- ...9.3.8.xml => Lib_Js_Prototype-1.9.3.9.xml} | 8 +- ...11.13.xml => Lib_Js_TinyMCE-3.5.11.14.xml} | 10 +- ...xml => Lib_LinLibertineFont-2.8.14.15.xml} | 8 +- ..._Mage-1.9.3.8.xml => Lib_Mage-1.9.3.9.xml} | 8 +- ...to-1.9.3.8.xml => Lib_Magento-1.9.3.9.xml} | 8 +- ...ago-1.9.3.8.xml => Lib_Pelago-1.9.3.9.xml} | 8 +- ...-1.9.3.8.xml => Lib_Phpseclib-1.9.3.9.xml} | 8 +- ....9.3.8.xml => Lib_Unserialize-1.9.3.9.xml} | 8 +- ...ien-1.9.3.8.xml => Lib_Varien-1.9.3.9.xml} | 12 +- ...F-1.12.10.13.xml => Lib_ZF-1.12.10.14.xml} | 10 +- ...10.13.xml => Lib_ZF_Locale-1.12.10.14.xml} | 8 +- var/package/Mage_All_Latest-1.9.3.8.xml | 18 - var/package/Mage_All_Latest-1.9.3.9.xml | 18 + ...-1.9.3.8.xml => Mage_Centinel-1.9.3.9.xml} | 10 +- ...-1.9.3.8.xml => Mage_Compiler-1.9.3.9.xml} | 10 +- ....8.xml => Mage_Core_Adminhtml-1.9.3.9.xml} | 12 +- ....3.8.xml => Mage_Core_Modules-1.9.3.9.xml} | 12 +- ....9.3.8.xml => Mage_Downloader-1.9.3.9.xml} | 10 +- ....3.8.xml => Mage_Locale_en_US-1.9.3.9.xml} | 10 +- ...1.9.3.8.xml => Magento_Mobile-1.9.3.9.xml} | 10 +- ...8.xml => Phoenix_Moneybookers-1.9.3.9.xml} | 10 +- 86 files changed, 1490 insertions(+), 232 deletions(-) create mode 100644 README.md create mode 100644 app/code/core/Mage/Usa/Model/Shipping/Carrier/Abstract/Backend/Abstract.php create mode 100644 app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/Freemethod.php create mode 100644 app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/OriginShipment.php create mode 100644 app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/Type.php create mode 100644 app/code/core/Zend/Filter/PregReplace.php create mode 100644 app/code/core/Zend/Validate/EmailAddress.php delete mode 100644 app/etc/applied.patches.list create mode 100644 js/tiny_mce/plugins/media/.htaccess rename var/package/{Cm_RedisSession-1.9.3.8.xml => Cm_RedisSession-1.9.3.9.xml} (85%) rename var/package/{Interface_Adminhtml_Default-1.9.3.8.xml => Interface_Adminhtml_Default-1.9.3.9.xml} (99%) rename var/package/{Interface_Frontend_Base_Default-1.9.3.8.xml => Interface_Frontend_Base_Default-1.9.3.9.xml} (98%) rename var/package/{Interface_Frontend_Default-1.9.3.8.xml => Interface_Frontend_Default-1.9.3.9.xml} (98%) rename var/package/{Interface_Frontend_Rwd_Default-1.9.3.8.xml => Interface_Frontend_Rwd_Default-1.9.3.9.xml} (98%) rename var/package/{Interface_Install_Default-1.9.3.8.xml => Interface_Install_Default-1.9.3.9.xml} (95%) rename var/package/{Lib_Cm-1.9.3.8.xml => Lib_Cm-1.9.3.9.xml} (82%) rename var/package/{Lib_Credis-1.9.3.8.xml => Lib_Credis-1.9.3.9.xml} (86%) rename var/package/{Lib_Google_Checkout-1.9.3.8.xml => Lib_Google_Checkout-1.9.3.9.xml} (83%) rename var/package/{Lib_IDNA2-1.9.3.8.xml => Lib_IDNA2-1.9.3.9.xml} (89%) rename var/package/{Lib_Js_Calendar-1.51.1.14.xml => Lib_Js_Calendar-1.51.1.15.xml} (95%) rename var/package/{Lib_Js_Ext-1.9.3.8.xml => Lib_Js_Ext-1.9.3.9.xml} (99%) rename var/package/{Lib_Js_Mage-1.9.3.8.xml => Lib_Js_Mage-1.9.3.9.xml} (97%) rename var/package/{Lib_Js_Prototype-1.9.3.8.xml => Lib_Js_Prototype-1.9.3.9.xml} (99%) rename var/package/{Lib_Js_TinyMCE-3.5.11.13.xml => Lib_Js_TinyMCE-3.5.11.14.xml} (99%) rename var/package/{Lib_LinLibertineFont-2.8.14.14.xml => Lib_LinLibertineFont-2.8.14.15.xml} (92%) rename var/package/{Lib_Mage-1.9.3.8.xml => Lib_Mage-1.9.3.9.xml} (98%) rename var/package/{Lib_Magento-1.9.3.8.xml => Lib_Magento-1.9.3.9.xml} (94%) rename var/package/{Lib_Pelago-1.9.3.8.xml => Lib_Pelago-1.9.3.9.xml} (86%) rename var/package/{Lib_Phpseclib-1.9.3.8.xml => Lib_Phpseclib-1.9.3.9.xml} (94%) rename var/package/{Lib_Unserialize-1.9.3.8.xml => Lib_Unserialize-1.9.3.9.xml} (91%) rename var/package/{Lib_Varien-1.9.3.8.xml => Lib_Varien-1.9.3.9.xml} (98%) rename var/package/{Lib_ZF-1.12.10.13.xml => Lib_ZF-1.12.10.14.xml} (99%) rename var/package/{Lib_ZF_Locale-1.12.10.13.xml => Lib_ZF_Locale-1.12.10.14.xml} (99%) delete mode 100644 var/package/Mage_All_Latest-1.9.3.8.xml create mode 100644 var/package/Mage_All_Latest-1.9.3.9.xml rename var/package/{Mage_Centinel-1.9.3.8.xml => Mage_Centinel-1.9.3.9.xml} (96%) rename var/package/{Mage_Compiler-1.9.3.8.xml => Mage_Compiler-1.9.3.9.xml} (91%) rename var/package/{Mage_Core_Adminhtml-1.9.3.8.xml => Mage_Core_Adminhtml-1.9.3.9.xml} (98%) rename var/package/{Mage_Core_Modules-1.9.3.8.xml => Mage_Core_Modules-1.9.3.9.xml} (93%) rename var/package/{Mage_Downloader-1.9.3.8.xml => Mage_Downloader-1.9.3.9.xml} (98%) rename var/package/{Mage_Locale_en_US-1.9.3.8.xml => Mage_Locale_en_US-1.9.3.9.xml} (95%) rename var/package/{Magento_Mobile-1.9.3.8.xml => Magento_Mobile-1.9.3.9.xml} (99%) rename var/package/{Phoenix_Moneybookers-1.9.3.8.xml => Phoenix_Moneybookers-1.9.3.9.xml} (97%) diff --git a/README.md b/README.md new file mode 100644 index 00000000000..ba3d28bef67 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# Magento Community Edition + +Firegento Magento Community Magento-1.x Mirror Github Repository with Patches. + +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/firegento/magento?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +- [available magento versions](https://github.com/firegento/magento/releases) +- [an overview of all patches](https://github.com/brentwpeterson/magento-patches) + +## Installation via Composer + +If you do not know what Composer is, please first read [this](https://getcomposer.org/doc/00-intro.md). + +To generate `composer.json` and install magento for the first time run: + +``` +composer require magento-hackathon/magento-composer-installer ~3.0 +composer require aydin-hassan/magento-core-composer-installer ~1.2 +composer require firegento/magento ~1.9.3.9 +``` \ No newline at end of file diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index fa99672bf25..84feb627784 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,3 +1,13 @@ +==== 1.9.3.9 ==== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +] NOTE: Current Release Notes are maintained at: [ +] [ +] http://devdocs.magento.com/guides/m1x/ce19-ee114/ce1.9_release-notes.html [ +] [ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ==== 1.9.3.8 ==== ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -13,7 +23,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ] NOTE: Current Release Notes are maintained at: [ ] [ -] http://devdocs.magento.com/guides/m1x/ce19-ee114/ce1.9_release-notes.html [ +] http://devdocs.magento.com/guides/m1x/ce19-ee114/ce1.9_release-notes.html [ ] [ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -23,7 +33,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ] NOTE: Current Release Notes are maintained at: [ ] [ -] http://devdocs.magento.com/guides/m1x/ce19-ee114/ce1.9_release-notes.html [ +] http://devdocs.magento.com/guides/m1x/ce19-ee114/ce1.9_release-notes.html [ ] [ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -33,7 +43,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ] NOTE: Current Release Notes are maintained at: [ ] [ -] http://devdocs.magento.com/guides/m1x/ce19-ee114/ce1.9_release-notes.html [ +] http://devdocs.magento.com/guides/m1x/ce19-ee114/ce1.9_release-notes.html [ ] [ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/app/Mage.php b/app/Mage.php index 11e5e02ce7e..b6d379e20f2 100644 --- a/app/Mage.php +++ b/app/Mage.php @@ -171,7 +171,7 @@ public static function getVersionInfo() 'major' => '1', 'minor' => '9', 'revision' => '3', - 'patch' => '8', + 'patch' => '9', 'stability' => '', 'number' => '', ); diff --git a/app/code/core/Mage/Admin/Model/User.php b/app/code/core/Mage/Admin/Model/User.php index 310d8229d10..94059a981f8 100644 --- a/app/code/core/Mage/Admin/Model/User.php +++ b/app/code/core/Mage/Admin/Model/User.php @@ -134,6 +134,10 @@ protected function _beforeSave() // Change user password $data['password'] = $this->_getEncodedPassword($this->getNewPassword()); $data['new_password'] = $data['password']; + $sessionUser = $this->getSession()->getUser(); + if ($sessionUser && $sessionUser->getId() == $this->getId()) { + $this->getSession()->setUserPasswordChanged(true); + } } elseif ($this->getPassword() && $this->getPassword() != $this->getOrigData('password')) { // New user password $data['password'] = $this->_getEncodedPassword($this->getPassword()); @@ -154,6 +158,14 @@ protected function _beforeSave() return parent::_beforeSave(); } + /** + * @return Mage_Admin_Model_Session + */ + protected function getSession() + { + return Mage::getSingleton('admin/session'); + } + /** * Save admin user extra data (like configuration sections state) * @@ -400,8 +412,15 @@ public function login($username, $password) public function reload() { $id = $this->getId(); + $oldPassword = $this->getPassword(); $this->setId(null); $this->load($id); + $isUserPasswordChanged = $this->getSession()->getUserPasswordChanged(); + if ($this->getPassword() !== $oldPassword && !$isUserPasswordChanged) { + $this->setId(null); + } elseif ($isUserPasswordChanged) { + $this->getSession()->setUserPasswordChanged(false); + } return $this; } diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Composite/Fieldset/Options.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Composite/Fieldset/Options.php index 45df50bd1e9..451a61b9c0b 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Composite/Fieldset/Options.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Composite/Fieldset/Options.php @@ -57,6 +57,9 @@ public function __construct() */ public function getOptionHtml(Mage_Catalog_Model_Product_Option $option) { + if (!empty($option['file_extension'])) { + $option['file_extension'] = $this->escapeHtml($option['file_extension']); + } $renderer = $this->getOptionRender( $this->getGroupOfOption($option->getType()) ); diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Option.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Option.php index 6239efba17f..8426475bee5 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Option.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Option.php @@ -286,7 +286,7 @@ public function getOptionValues() $value['price_type'] = $option->getPriceType(); $value['sku'] = $this->escapeHtml($option->getSku()); $value['max_characters'] = $option->getMaxCharacters(); - $value['file_extension'] = $option->getFileExtension(); + $value['file_extension'] = $this->escapeHtml($option->getFileExtension()); $value['image_size_x'] = $option->getImageSizeX(); $value['image_size_y'] = $option->getImageSizeY(); if ($this->getProduct()->getStoreId() != '0' && diff --git a/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Filter/Datetime.php b/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Filter/Datetime.php index c76b24b4739..339c4807a0f 100644 --- a/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Filter/Datetime.php +++ b/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Filter/Datetime.php @@ -169,10 +169,9 @@ public function getEscapedValue($index=null) $this->getLocale()->getDateTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT) ); } - return $value; + return $this->escapeHtml($value); } - return parent::getEscapedValue($index); + return $this->escapeHtml(parent::getEscapedValue($index)); } - } diff --git a/app/code/core/Mage/Adminhtml/Model/LayoutUpdate/Validator.php b/app/code/core/Mage/Adminhtml/Model/LayoutUpdate/Validator.php index 6e690790f33..3b7319fe5fb 100644 --- a/app/code/core/Mage/Adminhtml/Model/LayoutUpdate/Validator.php +++ b/app/code/core/Mage/Adminhtml/Model/LayoutUpdate/Validator.php @@ -47,6 +47,18 @@ class Mage_Adminhtml_Model_LayoutUpdate_Validator extends Zend_Validate_Abstract */ protected $_value; + /** + * XPath expression for checking layout update + * + * @var array + */ + protected $_disallowedXPathExpressions = array( + '*//template', + '*//@template', + '//*[@method=\'setTemplate\']', + '//*[@method=\'setDataUsingMethod\']//*[text() = \'template\']/../*' + ); + /** * Protected expressions * @@ -114,7 +126,7 @@ public function isValid($value) } // if layout update declare custom templates then validate their paths - if ($templatePaths = $value->xpath('*//template | *//@template | //*[@method=\'setTemplate\']/*')) { + if ($templatePaths = $value->xpath($this->_getXpathValidationExpression())) { try { $this->_validateTemplatePath($templatePaths); } catch (Exception $e) { @@ -133,6 +145,15 @@ public function isValid($value) return true; } + /** + * Returns xPath for validate incorrect path to template + * + * @return string xPath for validate incorrect path to template + */ + protected function _getXpathValidationExpression() { + return implode(" | ", $this->_disallowedXPathExpressions); + } + /** * Validate template path for preventing access to the directory above * If template path value has "../" @throws Exception diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php index 78958c1e4be..c27c2fc52bd 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php @@ -269,6 +269,9 @@ public function saveAction() $storeId = $this->getRequest()->getParam('store'); $refreshTree = 'false'; if ($data = $this->getRequest()->getPost()) { + if (isset($data['general']['path'])) { + unset($data['general']['path']); + } $category->addData($data['general']); if (!$category->getId()) { $parentId = $this->getRequest()->getParam('parent'); diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php index 569d1786cc5..4c5d8e0bd56 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php @@ -735,6 +735,7 @@ public function saveAction() } try { + $product->validate(); $product->save(); $productId = $product->getId(); diff --git a/app/code/core/Mage/Adminhtml/controllers/Cms/Wysiwyg/ImagesController.php b/app/code/core/Mage/Adminhtml/controllers/Cms/Wysiwyg/ImagesController.php index 0a6752623ef..8d27fad8399 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Cms/Wysiwyg/ImagesController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Cms/Wysiwyg/ImagesController.php @@ -188,6 +188,7 @@ public function thumbnailAction() if ($thumb !== false) { $image = Varien_Image_Adapter::factory('GD2'); $image->open($thumb); + $this->getResponse()->setHeader('Content-type', $image->getMimeTypeWithOutFileType()); ob_start(); $image->display(); $this->getResponse()->setBody(ob_get_contents()); diff --git a/app/code/core/Mage/Adminhtml/controllers/Cms/WysiwygController.php b/app/code/core/Mage/Adminhtml/controllers/Cms/WysiwygController.php index c7de5421143..fe44dc8793d 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Cms/WysiwygController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Cms/WysiwygController.php @@ -50,6 +50,7 @@ public function directiveAction() $image = Varien_Image_Adapter::factory('GD2'); $image->open(Mage::getSingleton('cms/wysiwyg_config')->getSkinImagePlaceholderPath()); } + $this->getResponse()->setHeader('Content-type', $image->getMimeTypeWithOutFileType()); ob_start(); $image->display(); $this->getResponse()->setBody(ob_get_contents()); diff --git a/app/code/core/Mage/Adminhtml/controllers/CustomerController.php b/app/code/core/Mage/Adminhtml/controllers/CustomerController.php index d490dd6edc3..c7ef678f48f 100644 --- a/app/code/core/Mage/Adminhtml/controllers/CustomerController.php +++ b/app/code/core/Mage/Adminhtml/controllers/CustomerController.php @@ -333,6 +333,7 @@ public function saveAction() // Force new customer confirmation if ($isNewCustomer) { $customer->setPassword($data['account']['password']); + $customer->setPasswordCreatedAt(time()); $customer->setForceConfirmed(true); if ($customer->getPassword() == 'auto') { $sendPassToEmail = true; diff --git a/app/code/core/Mage/Adminhtml/controllers/System/StoreController.php b/app/code/core/Mage/Adminhtml/controllers/System/StoreController.php index a9660909510..b628a971a95 100644 --- a/app/code/core/Mage/Adminhtml/controllers/System/StoreController.php +++ b/app/code/core/Mage/Adminhtml/controllers/System/StoreController.php @@ -33,6 +33,16 @@ */ class Mage_Adminhtml_System_StoreController extends Mage_Adminhtml_Controller_Action { + /** + * Controller predispatch method + * + * @return Mage_Adminhtml_Controller_Action + */ + public function preDispatch() + { + $this->_setForcedFormKeyActions(array('deleteWebsitePost', 'deleteGroupPost', 'deleteStorePost')); + return parent::preDispatch(); + } /** * Init actions diff --git a/app/code/core/Mage/Catalog/Model/Product.php b/app/code/core/Mage/Catalog/Model/Product.php index 5c0ebbdca27..f6fe5d55294 100644 --- a/app/code/core/Mage/Catalog/Model/Product.php +++ b/app/code/core/Mage/Catalog/Model/Product.php @@ -460,6 +460,8 @@ public function getAttributes($groupId = null, $skipSuper = false) /** * Check product options and type options and save them, too + * + * @throws Mage_Core_Exception */ protected function _beforeSave() { @@ -485,6 +487,12 @@ protected function _beforeSave() foreach ($this->getProductOptions() as $option) { $this->getOptionInstance()->addOption($option); if ((!isset($option['is_delete'])) || $option['is_delete'] != '1') { + if (!empty($option['file_extension'])) { + $fileExtension = $option['file_extension']; + if (0 !== strcmp($fileExtension, Mage::helper('core')->removeTags($fileExtension))) { + Mage::throwException(Mage::helper('catalog')->__('Invalid custom option(s).')); + } + } $hasOptions = true; } } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Category/Tree.php b/app/code/core/Mage/Catalog/Model/Resource/Category/Tree.php index c969e60ddd9..43c9e330690 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Category/Tree.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Category/Tree.php @@ -482,6 +482,9 @@ public function loadByIds($ids, $addCollectionData = true, $updateAnchorProductC $where = array($levelField . '=0' => true); foreach ($this->_conn->fetchAll($select) as $item) { + if (!preg_match("#^[0-9\/]+$#", $item['path'])) { + $item['path'] = ''; + } $pathIds = explode('/', $item['path']); $level = (int)$item['level']; while ($level > 0) { diff --git a/app/code/core/Mage/Catalog/Model/Url.php b/app/code/core/Mage/Catalog/Model/Url.php index 3c9ca2bcd21..98fef1a294f 100644 --- a/app/code/core/Mage/Catalog/Model/Url.php +++ b/app/code/core/Mage/Catalog/Model/Url.php @@ -602,12 +602,29 @@ public function clearStoreInvalidRewrites($storeId = null) * * Will try to get unique path by adding -1 -2 etc. between url_key and optional url_suffix * + * @deprecated use $this->getUnusedPathByUrlKey() instead * @param int $storeId * @param string $requestPath * @param string $idPath * @return string */ public function getUnusedPath($storeId, $requestPath, $idPath) + { + return $this->getUnusedPathByUrlKey($storeId, $requestPath, $idPath, ''); + } + + /** + * Get requestPath that was not used yet. + * + * Will try to get unique path by adding -1 -2 etc. between url_key and optional url_suffix + * + * @param int $storeId + * @param string $requestPath + * @param string $idPath + * @param string $urlKey + * @return string + */ + public function getUnusedPathByUrlKey($storeId, $requestPath, $idPath, $urlKey) { if (strpos($idPath, 'product') !== false) { $suffix = $this->getProductUrlSuffix($storeId); @@ -645,21 +662,22 @@ public function getUnusedPath($storeId, $requestPath, $idPath) } // match request_url abcdef1234(-12)(.html) pattern $match = array(); - $regularExpression = '#^([0-9a-z/-]+?)(-([0-9]+))?('.preg_quote($suffix).')?$#i'; + $regularExpression = '#(?P(.*/)?' . preg_quote($urlKey) . ')(-(?P[0-9]+))?(?P' + . preg_quote($suffix) . ')?$#i'; if (!preg_match($regularExpression, $requestPath, $match)) { - return $this->getUnusedPath($storeId, '-', $idPath); + return $this->getUnusedPathByUrlKey($storeId, '-', $idPath, $urlKey); } - $match[1] = $match[1] . '-'; - $match[4] = isset($match[4]) ? $match[4] : ''; + $match['prefix'] = $match['prefix'] . '-'; + $match['suffix'] = isset($match['suffix']) ? $match['suffix'] : ''; $lastRequestPath = $this->getResource() - ->getLastUsedRewriteRequestIncrement($match[1], $match[4], $storeId); + ->getLastUsedRewriteRequestIncrement($match['prefix'], $match['suffix'], $storeId); if ($lastRequestPath) { - $match[3] = $lastRequestPath; + $match['increment'] = $lastRequestPath; } - return $match[1] - . (isset($match[3]) ? ($match[3]+1) : '1') - . $match[4]; + return $match['prefix'] + . (isset($match['increment']) ? ($match['increment'] + 1) : '1') + . $match['suffix']; } else { return $requestPath; @@ -699,7 +717,6 @@ public function getCategoryRequestPath($category, $parentPath) { $storeId = $category->getStoreId(); $idPath = $this->generatePath('id', null, $category); - $suffix = $this->getCategoryUrlSuffix($storeId); if (isset($this->_rewrites[$idPath])) { $this->_rewrite = $this->_rewrites[$idPath]; @@ -713,28 +730,27 @@ public function getCategoryRequestPath($category, $parentPath) $urlKey = $this->getCategoryModel()->formatUrlKey($category->getUrlKey()); } - $categoryUrlSuffix = $this->getCategoryUrlSuffix($category->getStoreId()); + $categoryUrlSuffix = $this->getCategoryUrlSuffix($storeId); if (null === $parentPath) { $parentPath = $this->getResource()->getCategoryParentPath($category); } elseif ($parentPath == '/') { $parentPath = ''; } - $parentPath = Mage::helper('catalog/category')->getCategoryUrlPath($parentPath, - true, $category->getStoreId()); + $parentPath = Mage::helper('catalog/category')->getCategoryUrlPath($parentPath, true, $storeId); - $requestPath = $parentPath . $urlKey . $categoryUrlSuffix; - if (isset($existingRequestPath) && $existingRequestPath == $requestPath . $suffix) { + $requestPath = $parentPath . $urlKey; + $regexp = '/^' . preg_quote($requestPath, '/') . '(\-[0-9]+)?' . preg_quote($categoryUrlSuffix, '/') . '$/i'; + if (isset($existingRequestPath) && preg_match($regexp, $existingRequestPath)) { return $existingRequestPath; } - if ($this->_deleteOldTargetPath($requestPath, $idPath, $storeId)) { + $fullPath = $requestPath . $categoryUrlSuffix; + if ($this->_deleteOldTargetPath($fullPath, $idPath, $storeId)) { return $requestPath; } - return $this->getUnusedPath($category->getStoreId(), $requestPath, - $this->generatePath('id', null, $category) - ); + return $this->getUnusedPathByUrlKey($storeId, $fullPath, $this->generatePath('id', null, $category), $urlKey); } /** @@ -798,7 +814,8 @@ public function getProductRequestPath($product, $category) $this->_rewrite = $this->_rewrites[$idPath]; $existingRequestPath = $this->_rewrites[$idPath]->getRequestPath(); - if ($existingRequestPath == $requestPath . $suffix) { + $regexp = '/^' . preg_quote($requestPath, '/') . '(\-[0-9]+)?' . preg_quote($suffix, '/') . '$/i'; + if (preg_match($regexp, $existingRequestPath)) { return $existingRequestPath; } @@ -836,7 +853,7 @@ public function getProductRequestPath($product, $category) /** * Use unique path generator */ - return $this->getUnusedPath($storeId, $requestPath.$suffix, $idPath); + return $this->getUnusedPathByUrlKey($storeId, $requestPath . $suffix, $idPath, $urlKey); } /** @@ -891,8 +908,8 @@ public function generatePath($type = 'target', $product = null, $category = null $parentPath = Mage::helper('catalog/category')->getCategoryUrlPath($parentPath, true, $category->getStoreId()); - return $this->getUnusedPath($category->getStoreId(), $parentPath . $urlKey . $categoryUrlSuffix, - $this->generatePath('id', null, $category) + return $this->getUnusedPathByUrlKey($category->getStoreId(), $parentPath . $urlKey . $categoryUrlSuffix, + $this->generatePath('id', null, $category), $urlKey ); } @@ -913,14 +930,15 @@ public function generatePath($type = 'target', $product = null, $category = null $this->_addCategoryUrlPath($category); $categoryUrl = Mage::helper('catalog/category')->getCategoryUrlPath($category->getUrlPath(), false, $category->getStoreId()); - return $this->getUnusedPath($category->getStoreId(), $categoryUrl . '/' . $urlKey . $productUrlSuffix, - $this->generatePath('id', $product, $category) + return $this->getUnusedPathByUrlKey( + $category->getStoreId(), $categoryUrl . '/' . $urlKey . $productUrlSuffix, + $this->generatePath('id', $product, $category), $urlKey ); } // for product only - return $this->getUnusedPath($category->getStoreId(), $urlKey . $productUrlSuffix, - $this->generatePath('id', $product) + return $this->getUnusedPathByUrlKey( + $category->getStoreId(), $urlKey . $productUrlSuffix, $this->generatePath('id', $product), $urlKey ); } diff --git a/app/code/core/Mage/Checkout/Model/Api/Resource/Customer.php b/app/code/core/Mage/Checkout/Model/Api/Resource/Customer.php index 9a69674e3d1..7d6e00698bc 100644 --- a/app/code/core/Mage/Checkout/Model/Api/Resource/Customer.php +++ b/app/code/core/Mage/Checkout/Model/Api/Resource/Customer.php @@ -149,6 +149,7 @@ protected function _prepareNewCustomerQuote(Mage_Sales_Model_Quote $quote) Mage::helper('core')->copyFieldset('checkout_onepage_quote', 'to_customer', $quote, $customer); $customer->setPassword($customer->decryptPassword($quote->getPasswordHash())); + $customer->setPasswordCreatedAt(time()); $quote->setCustomer($customer) ->setCustomerId(true); diff --git a/app/code/core/Mage/Checkout/Model/Type/Onepage.php b/app/code/core/Mage/Checkout/Model/Type/Onepage.php index e29d5945a49..2e6cad7d25d 100644 --- a/app/code/core/Mage/Checkout/Model/Type/Onepage.php +++ b/app/code/core/Mage/Checkout/Model/Type/Onepage.php @@ -729,6 +729,9 @@ protected function _prepareNewCustomerQuote() Mage::helper('core')->copyFieldset('checkout_onepage_quote', 'to_customer', $quote, $customer); $customer->setPassword($customer->decryptPassword($quote->getPasswordHash())); + $passwordCreatedTime = $this->_checkoutSession->getData('_session_validator_data')['session_expire_timestamp'] + - Mage::getSingleton('core/cookie')->getLifetime(); + $customer->setPasswordCreatedAt($passwordCreatedTime); $quote->setCustomer($customer) ->setCustomerId(true); } diff --git a/app/code/core/Mage/Checkout/controllers/CartController.php b/app/code/core/Mage/Checkout/controllers/CartController.php index 248fc08feb2..1b52698b39b 100644 --- a/app/code/core/Mage/Checkout/controllers/CartController.php +++ b/app/code/core/Mage/Checkout/controllers/CartController.php @@ -357,6 +357,11 @@ public function configureAction() */ public function updateItemOptionsAction() { + if (!$this->_validateFormKey()) { + $this->_redirect('*/*/'); + return; + } + $cart = $this->_getCart(); $id = (int) $this->getRequest()->getParam('id'); $params = $this->getRequest()->getParams(); diff --git a/app/code/core/Mage/Core/Helper/Http.php b/app/code/core/Mage/Core/Helper/Http.php index 6c4e3069f65..748c63d9825 100644 --- a/app/code/core/Mage/Core/Helper/Http.php +++ b/app/code/core/Mage/Core/Helper/Http.php @@ -131,7 +131,7 @@ public function getRemoteAddr($ipToLong = false) if (is_null($this->_remoteAddr)) { $headers = $this->getRemoteAddrHeaders(); foreach ($headers as $var) { - if ($this->_getRequest()->getServer($var, false)) { + if ($var != 'REMOTE_ADDR' && $this->_getRequest()->getServer($var, false)) { $this->_remoteAddr = $_SERVER[$var]; break; } @@ -146,6 +146,11 @@ public function getRemoteAddr($ipToLong = false) return false; } + if (strpos($this->_remoteAddr, ',') !== false) { + $ipList = explode(',', $this->_remoteAddr); + $this->_remoteAddr = trim(reset($ipList)); + } + return $ipToLong ? inet_pton($this->_remoteAddr) : $this->_remoteAddr; } diff --git a/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php b/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php index b27205e0d64..490fcda0718 100644 --- a/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php +++ b/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php @@ -33,6 +33,7 @@ class Mage_Core_Model_Session_Abstract_Varien extends Varien_Object const VALIDATOR_HTTP_VIA_KEY = 'http_via'; const VALIDATOR_REMOTE_ADDR_KEY = 'remote_addr'; const VALIDATOR_SESSION_EXPIRE_TIMESTAMP = 'session_expire_timestamp'; + const VALIDATOR_PASSWORD_CREATE_TIMESTAMP = 'password_create_timestamp'; const SECURE_COOKIE_CHECK_KEY = '_secure_cookie_check'; /** @@ -393,6 +394,16 @@ public function useValidateSessionExpire() return $this->getCookie()->getLifetime() > 0; } + /** + * Use password creation timestamp in validator key + * + * @return bool + */ + public function useValidateSessionPasswordTimestamp() + { + return true; + } + /** * Retrieve skip User Agent validation strings (Flash etc) * @@ -470,6 +481,14 @@ protected function _validate() $this->_data[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] = $validatorData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP]; } + if ($this->useValidateSessionPasswordTimestamp() + && isset($validatorData[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP]) + && isset($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP]) + && $validatorData[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP] + > $sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] - $this->getCookie()->getLifetime() + ) { + return false; + } return true; } @@ -506,6 +525,11 @@ public function getValidatorData() $parts[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] = time() + $this->getCookie()->getLifetime(); + if (isset($this->_data['visitor_data']['customer_id'])) { + $parts[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP] = + Mage::helper('customer')->getPasswordTimestamp($this->_data['visitor_data']['customer_id']); + } + return $parts; } diff --git a/app/code/core/Mage/Customer/Helper/Data.php b/app/code/core/Mage/Customer/Helper/Data.php index 436107e632a..1016c6c04c4 100644 --- a/app/code/core/Mage/Customer/Helper/Data.php +++ b/app/code/core/Mage/Customer/Helper/Data.php @@ -722,6 +722,23 @@ public function getVatValidationUserMessage($customerAddress, $customerGroupAuto return $validationMessageEnvelope; } + /** + * Get customer password creation timestamp or customer account creation timestamp + * + * @param $customerId + * @return int + */ + public function getPasswordTimestamp($customerId) + { + /** @var $customer Mage_Customer_Model_Customer */ + $customer = Mage::getModel('customer/customer') + ->setWebsiteId(Mage::app()->getStore()->getWebsiteId()) + ->load((int)$customerId); + $passwordCreatedAt = $customer->getPasswordCreatedAt(); + + return is_null($passwordCreatedAt) ? $customer->getCreatedAtTimestamp() : $passwordCreatedAt; + } + /** * Create SOAP client based on VAT validation service WSDL * diff --git a/app/code/core/Mage/Customer/Model/Resource/Customer.php b/app/code/core/Mage/Customer/Model/Resource/Customer.php index bae08ac1aeb..e783dd85858 100644 --- a/app/code/core/Mage/Customer/Model/Resource/Customer.php +++ b/app/code/core/Mage/Customer/Model/Resource/Customer.php @@ -235,8 +235,9 @@ public function loadByEmail(Mage_Customer_Model_Customer $customer, $email, $tes */ public function changePassword(Mage_Customer_Model_Customer $customer, $newPassword) { - $customer->setPassword($newPassword); + $customer->setPassword($newPassword)->setPasswordCreatedAt(time()); $this->saveAttribute($customer, 'password_hash'); + $this->saveAttribute($customer, 'password_created_at'); return $this; } diff --git a/app/code/core/Mage/Customer/controllers/AccountController.php b/app/code/core/Mage/Customer/controllers/AccountController.php index 151d3d4fb64..f29b23a6d8d 100644 --- a/app/code/core/Mage/Customer/controllers/AccountController.php +++ b/app/code/core/Mage/Customer/controllers/AccountController.php @@ -298,6 +298,7 @@ public function createPostAction() if (empty($errors)) { $customer->cleanPasswordsValidationData(); + $customer->setPasswordCreatedAt(time()); $customer->save(); $this->_dispatchRegisterSuccess($customer); $this->_successProcessRegistration($customer); @@ -865,6 +866,7 @@ public function resetPasswordPostAction() $customer->setRpToken(null); $customer->setRpTokenCreatedAt(null); $customer->cleanPasswordsValidationData(); + $customer->setPasswordCreatedAt(time()); $customer->save(); $this->_getSession()->unsetData(self::TOKEN_SESSION_NAME); @@ -1009,6 +1011,7 @@ public function editPostAction() try { $customer->cleanPasswordsValidationData(); + $customer->setPasswordCreatedAt(time()); // Reset all password reset tokens if all data was sufficient and correct on email change if ($customer->getIsChangeEmail()) { diff --git a/app/code/core/Mage/Log/Model/Visitor.php b/app/code/core/Mage/Log/Model/Visitor.php index c735998578c..57a93d39761 100644 --- a/app/code/core/Mage/Log/Model/Visitor.php +++ b/app/code/core/Mage/Log/Model/Visitor.php @@ -252,7 +252,7 @@ public function saveByRequest($observer) */ public function bindCustomerLogin($observer) { - if (!$this->getCustomerId() && $customer = $observer->getEvent()->getCustomer()) { + if ($customer = $observer->getEvent()->getCustomer()) { $this->setDoCustomerLogin(true); $this->setCustomerId($customer->getId()); } diff --git a/app/code/core/Mage/Usa/Helper/Data.php b/app/code/core/Mage/Usa/Helper/Data.php index 152d0df6a57..6f28031a116 100644 --- a/app/code/core/Mage/Usa/Helper/Data.php +++ b/app/code/core/Mage/Usa/Helper/Data.php @@ -135,4 +135,23 @@ public function displayGirthValue($shippingMethod) return false; } } + + /** + * Validate ups type value + * + * @param $valueForCheck string ups type value for check + * + * @return bool + */ + public function validateUpsType($valueForCheck) { + $result = false; + $sourceModel = Mage::getSingleton('usa/shipping_carrier_ups_source_type'); + foreach ($sourceModel->toOptionArray() as $allowedValue) { + if (isset($allowedValue['value']) && $allowedValue['value'] == $valueForCheck) { + $result = true; + break; + } + } + return $result; + } } diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Abstract/Backend/Abstract.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Abstract/Backend/Abstract.php new file mode 100644 index 00000000000..665ac3be6e2 --- /dev/null +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Abstract/Backend/Abstract.php @@ -0,0 +1,100 @@ + + */ + +abstract class Mage_Usa_Model_Shipping_Carrier_Abstract_Backend_Abstract extends Mage_Core_Model_Config_Data +{ + /** + * Source model to get allowed values + * + * @var string + */ + protected $_sourceModel; + + /** + * Field name to display in error block + * + * @var string + */ + protected $_nameErrorField; + + /** + * Set source model to get allowed values + * + * @return void + */ + abstract protected function _setSourceModelData(); + + /** + * Set field name to display in error block + * + * @return void + */ + abstract protected function _setNameErrorField(); + + /** + * Mage_Usa_Model_Shipping_Carrier_Ups_Backend_Abstract constructor. + */ + public function __construct() + { + parent::__construct(); + $this->_setSourceModelData(); + $this->_setNameErrorField(); + } + + /** + * Check for presence in array with allow value. + * + * @throws Mage_Core_Exception + * @return Mage_Usa_Model_Shipping_Carrier_Ups_Backend_FreeShipment + */ + protected function _beforeSave() + { + $sourceModel = Mage::getSingleton($this->_sourceModel); + if (!method_exists($sourceModel, 'toOptionArray')) { + Mage::throwException(Mage::helper('usa')->__('Method toOptionArray not found in source model.')); + } + $hasCorrectValue = false; + $value = $this->getValue(); + foreach ($sourceModel->toOptionArray() as $allowedValue) { + if (isset($allowedValue['value']) && $allowedValue['value'] == $value) { + $hasCorrectValue = true; + break; + } + } + if(!$hasCorrectValue) { + Mage::throwException(Mage::helper('usa')->__('Field "%s" has wrong value.', $this->_nameErrorField)); + } + return $this; + } +} diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/Freemethod.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/Freemethod.php new file mode 100644 index 00000000000..d844e62713e --- /dev/null +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/Freemethod.php @@ -0,0 +1,57 @@ + + */ + +class Mage_Usa_Model_Shipping_Carrier_Ups_Backend_Freemethod + extends Mage_Usa_Model_Shipping_Carrier_Abstract_Backend_Abstract +{ + /** + * Set source model to get allowed values + * + * @return void + */ + protected function _setSourceModelData() + { + $this->_sourceModel = 'usa/shipping_carrier_ups_source_freemethod'; + } + + /** + * Set field name to display in error block + * + * @return void + */ + protected function _setNameErrorField() + { + $this->_nameErrorField = 'Ups Free Method'; + } +} diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/OriginShipment.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/OriginShipment.php new file mode 100644 index 00000000000..4d7e1c0506f --- /dev/null +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/OriginShipment.php @@ -0,0 +1,57 @@ + + */ + +class Mage_Usa_Model_Shipping_Carrier_Ups_Backend_OriginShipment + extends Mage_Usa_Model_Shipping_Carrier_Abstract_Backend_Abstract +{ + /** + * Set source model to get allowed values + * + * @return void + */ + protected function _setSourceModelData() + { + $this->_sourceModel = 'usa/shipping_carrier_ups_source_originShipment'; + } + + /** + * Set field name to display in error block + * + * @return void + */ + protected function _setNameErrorField() + { + $this->_nameErrorField = 'Ups origin of the Shipment'; + } +} diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/Type.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/Type.php new file mode 100644 index 00000000000..fe033622cf6 --- /dev/null +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups/Backend/Type.php @@ -0,0 +1,56 @@ + + */ + +class Mage_Usa_Model_Shipping_Carrier_Ups_Backend_Type extends Mage_Usa_Model_Shipping_Carrier_Abstract_Backend_Abstract +{ + /** + * Set source model to get allowed values + * + * @return void + */ + protected function _setSourceModelData() + { + $this->_sourceModel = 'usa/shipping_carrier_ups_source_type'; + } + + /** + * Set field name to display in error block + * + * @return void + */ + protected function _setNameErrorField() + { + $this->_nameErrorField = 'UPS Type'; + } +} diff --git a/app/code/core/Mage/Usa/etc/system.xml b/app/code/core/Mage/Usa/etc/system.xml index 15b23e921e3..7bc0af9fc15 100644 --- a/app/code/core/Mage/Usa/etc/system.xml +++ b/app/code/core/Mage/Usa/etc/system.xml @@ -740,6 +740,7 @@ select free-method usa/shipping_carrier_ups_source_freemethod + usa/shipping_carrier_ups_backend_freemethod 200 1 1 @@ -843,6 +844,7 @@ select usa/shipping_carrier_ups_source_originShipment + usa/shipping_carrier_ups_backend_originShipment 30 1 1 @@ -886,6 +888,7 @@ select usa/shipping_carrier_ups_source_type + usa/shipping_carrier_ups_backend_type 20 1 1 diff --git a/app/code/core/Zend/Filter/PregReplace.php b/app/code/core/Zend/Filter/PregReplace.php new file mode 100644 index 00000000000..586c0fe20a0 --- /dev/null +++ b/app/code/core/Zend/Filter/PregReplace.php @@ -0,0 +1,183 @@ + matching pattern + * 'replace' => replace with this + * + * @param string|array $options + * @return void + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['match'] = array_shift($options); + } + + if (!empty($options)) { + $temp['replace'] = array_shift($options); + } + + $options = $temp; + } + + if (array_key_exists('match', $options)) { + $this->setMatchPattern($options['match']); + } + + if (array_key_exists('replace', $options)) { + $this->setReplacement($options['replace']); + } + } + + /** + * Set the match pattern for the regex being called within filter() + * + * @param mixed $match - same as the first argument of preg_replace + * @return Zend_Filter_PregReplace + */ + public function setMatchPattern($match) + { + $this->_matchPattern = $match; + return $this; + } + + /** + * Get currently set match pattern + * + * @return string + */ + public function getMatchPattern() + { + return $this->_matchPattern; + } + + /** + * Set the Replacement pattern/string for the preg_replace called in filter + * + * @param mixed $replacement - same as the second argument of preg_replace + * @return Zend_Filter_PregReplace + */ + public function setReplacement($replacement) + { + $this->_replacement = $replacement; + return $this; + } + + /** + * Get currently set replacement value + * + * @return string + */ + public function getReplacement() + { + return $this->_replacement; + } + + /** + * Perform regexp replacement as filter + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_matchPattern == null) { + #require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.'); + } + $firstDilimeter = substr($this->_matchPattern, 0, 1); + $partsOfRegex = explode($firstDilimeter, $this->_matchPattern); + $modifiers = array_pop($partsOfRegex); + if ($modifiers != str_replace('e', '', $modifiers)) { + throw new Zend_Filter_Exception(get_class($this) . ' uses deprecated modifier "/e".'); + } + + return preg_replace($this->_matchPattern, $this->_replacement, $value); + } + +} diff --git a/app/code/core/Zend/Validate/EmailAddress.php b/app/code/core/Zend/Validate/EmailAddress.php new file mode 100644 index 00000000000..95e9bdff7cf --- /dev/null +++ b/app/code/core/Zend/Validate/EmailAddress.php @@ -0,0 +1,579 @@ + "Invalid type given. String expected", + self::INVALID_FORMAT => "'%value%' is not a valid email address in the basic format local-part@hostname", + self::INVALID_HOSTNAME => "'%hostname%' is not a valid hostname for email address '%value%'", + self::INVALID_MX_RECORD => "'%hostname%' does not appear to have a valid MX record for the email address '%value%'", + self::INVALID_SEGMENT => "'%hostname%' is not in a routable network segment. The email address '%value%' should not be resolved from public network", + self::DOT_ATOM => "'%localPart%' can not be matched against dot-atom format", + self::QUOTED_STRING => "'%localPart%' can not be matched against quoted-string format", + self::INVALID_LOCAL_PART => "'%localPart%' is not a valid local part for email address '%value%'", + self::LENGTH_EXCEEDED => "'%value%' exceeds the allowed length", + ); + + /** + * As of RFC5753 (JAN 2010), the following blocks are no longer reserved: + * - 128.0.0.0/16 + * - 191.255.0.0/16 + * - 223.255.255.0/24 + * @see http://tools.ietf.org/html/rfc5735#page-6 + * + * As of RFC6598 (APR 2012), the following blocks are now reserved: + * - 100.64.0.0/10 + * @see http://tools.ietf.org/html/rfc6598#section-7 + * + * @see http://en.wikipedia.org/wiki/IPv4 + * @var array + */ + protected $_invalidIp = array( + '0' => '0.0.0.0/8', + '10' => '10.0.0.0/8', + '100' => '100.64.0.0/10', + '127' => '127.0.0.0/8', + '169' => '169.254.0.0/16', + '172' => '172.16.0.0/12', + '192' => array( + '192.0.0.0/24', + '192.0.2.0/24', + '192.88.99.0/24', + '192.168.0.0/16' + ), + '198' => '198.18.0.0/15', + '224' => '224.0.0.0/4', + '240' => '240.0.0.0/4' + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'hostname' => '_hostname', + 'localPart' => '_localPart' + ); + + /** + * @var string + */ + protected $_hostname; + + /** + * @var string + */ + protected $_localPart; + + /** + * Internal options array + */ + protected $_options = array( + 'mx' => false, + 'deep' => false, + 'domain' => true, + 'allow' => Zend_Validate_Hostname::ALLOW_DNS, + 'hostname' => null + ); + + /** + * Instantiates hostname validator for local use + * + * The following option keys are supported: + * 'hostname' => A hostname validator, see Zend_Validate_Hostname + * 'allow' => Options for the hostname validator, see Zend_Validate_Hostname::ALLOW_* + * 'mx' => If MX check should be enabled, boolean + * 'deep' => If a deep MX check should be done, boolean + * + * @param array|string|Zend_Config $options OPTIONAL + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['allow'] = array_shift($options); + if (!empty($options)) { + $temp['mx'] = array_shift($options); + } + + if (!empty($options)) { + $temp['hostname'] = array_shift($options); + } + + $options = $temp; + } + + $options += $this->_options; + $this->setOptions($options); + } + + /** + * Returns all set Options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Set options for the email validator + * + * @param array $options + * @return Zend_Validate_EmailAddress Provides a fluent inteface + */ + public function setOptions(array $options = array()) + { + if (array_key_exists('messages', $options)) { + $this->setMessages($options['messages']); + } + + if (array_key_exists('hostname', $options)) { + if (array_key_exists('allow', $options)) { + $this->setHostnameValidator($options['hostname'], $options['allow']); + } else { + $this->setHostnameValidator($options['hostname']); + } + } elseif ($this->_options['hostname'] == null) { + $this->setHostnameValidator(); + } + + if (array_key_exists('mx', $options)) { + $this->setValidateMx($options['mx']); + } + + if (array_key_exists('deep', $options)) { + $this->setDeepMxCheck($options['deep']); + } + + if (array_key_exists('domain', $options)) { + $this->setDomainCheck($options['domain']); + } + + return $this; + } + + /** + * Sets the validation failure message template for a particular key + * Adds the ability to set messages to the attached hostname validator + * + * @param string $messageString + * @param string $messageKey OPTIONAL + * @return Zend_Validate_Abstract Provides a fluent interface + * @throws Zend_Validate_Exception + */ + public function setMessage($messageString, $messageKey = null) + { + if ($messageKey === null) { + $this->_options['hostname']->setMessage($messageString); + parent::setMessage($messageString); + return $this; + } + + if (!isset($this->_messageTemplates[$messageKey])) { + $this->_options['hostname']->setMessage($messageString, $messageKey); + } + + $this->_messageTemplates[$messageKey] = $messageString; + return $this; + } + + /** + * Returns the set hostname validator + * + * @return Zend_Validate_Hostname + */ + public function getHostnameValidator() + { + return $this->_options['hostname']; + } + + /** + * @param Zend_Validate_Hostname $hostnameValidator OPTIONAL + * @param int $allow OPTIONAL + * @return $this + */ + public function setHostnameValidator(Zend_Validate_Hostname $hostnameValidator = null, $allow = Zend_Validate_Hostname::ALLOW_DNS) + { + if (!$hostnameValidator) { + $hostnameValidator = new Zend_Validate_Hostname($allow); + } + + $this->_options['hostname'] = $hostnameValidator; + $this->_options['allow'] = $allow; + return $this; + } + + /** + * Whether MX checking via getmxrr is supported or not + * + * This currently only works on UNIX systems + * + * @return boolean + */ + public function validateMxSupported() + { + return function_exists('getmxrr'); + } + + /** + * Returns the set validateMx option + * + * @return boolean + */ + public function getValidateMx() + { + return $this->_options['mx']; + } + + /** + * Set whether we check for a valid MX record via DNS + * + * This only applies when DNS hostnames are validated + * + * @param boolean $mx Set allowed to true to validate for MX records, and false to not validate them + * @throws Zend_Validate_Exception + * @return Zend_Validate_EmailAddress Provides a fluent inteface + */ + public function setValidateMx($mx) + { + if ((bool) $mx && !$this->validateMxSupported()) { + #require_once 'Zend/Validate/Exception.php'; + throw new Zend_Validate_Exception('MX checking not available on this system'); + } + + $this->_options['mx'] = (bool) $mx; + return $this; + } + + /** + * Returns the set deepMxCheck option + * + * @return boolean + */ + public function getDeepMxCheck() + { + return $this->_options['deep']; + } + + /** + * Set whether we check MX record should be a deep validation + * + * @param boolean $deep Set deep to true to perform a deep validation process for MX records + * @return Zend_Validate_EmailAddress Provides a fluent inteface + */ + public function setDeepMxCheck($deep) + { + $this->_options['deep'] = (bool) $deep; + return $this; + } + + /** + * Returns the set domainCheck option + * + * @return unknown + */ + public function getDomainCheck() + { + return $this->_options['domain']; + } + + /** + * Sets if the domain should also be checked + * or only the local part of the email address + * + * @param boolean $domain + * @return Zend_Validate_EmailAddress Provides a fluent inteface + */ + public function setDomainCheck($domain = true) + { + $this->_options['domain'] = (boolean) $domain; + return $this; + } + + /** + * Returns if the given host is reserved + * + * @param string $host + * @return boolean + */ + private function _isReserved($host){ + if (!preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $host)) { + $host = gethostbyname($host); + } + + $octet = explode('.',$host); + if ((int)$octet[0] >= 224) { + return true; + } else if (array_key_exists($octet[0], $this->_invalidIp)) { + foreach ((array)$this->_invalidIp[$octet[0]] as $subnetData) { + // we skip the first loop as we already know that octet matches + for ($i = 1; $i < 4; $i++) { + if (strpos($subnetData, $octet[$i]) !== $i * 4) { + break; + } + } + + $host = explode("/", $subnetData); + $binaryHost = ""; + $tmp = explode(".", $host[0]); + for ($i = 0; $i < 4 ; $i++) { + $binaryHost .= str_pad(decbin($tmp[$i]), 8, "0", STR_PAD_LEFT); + } + + $segmentData = array( + 'network' => (int)$this->_toIp(str_pad(substr($binaryHost, 0, $host[1]), 32, 0)), + 'broadcast' => (int)$this->_toIp(str_pad(substr($binaryHost, 0, $host[1]), 32, 1)) + ); + + for ($j = $i; $j < 4; $j++) { + if ((int)$octet[$j] < $segmentData['network'][$j] || + (int)$octet[$j] > $segmentData['broadcast'][$j]) { + return false; + } + } + } + + return true; + } else { + return false; + } + } + + /** + * Converts a binary string to an IP address + * + * @param string $binary + * @return mixed + */ + private function _toIp($binary) + { + $ip = array(); + $tmp = explode(".", chunk_split($binary, 8, ".")); + for ($i = 0; $i < 4 ; $i++) { + $ip[$i] = bindec($tmp[$i]); + } + + return $ip; + } + + /** + * Internal method to validate the local part of the email address + * + * @return boolean + */ + private function _validateLocalPart() + { + // First try to match the local part on the common dot-atom format + $result = false; + + // Dot-atom characters are: 1*atext *("." 1*atext) + // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*", + // "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~" + $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d\x7e'; + if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->_localPart)) { + $result = true; + } else { + // Try quoted string format (RFC 5321 Chapter 4.1.2) + + // Quoted-string characters are: DQUOTE *(qtext/quoted-pair) DQUOTE + $qtext = '\x20-\x21\x23-\x5b\x5d-\x7e'; // %d32-33 / %d35-91 / %d93-126 + $quotedPair = '\x20-\x7e'; // %d92 %d32-126 + if ((0 === (strcmp($this->localPart, strip_tags($this->localPart)))) + && (0 === (strcmp($this->localPart, htmlspecialchars_decode($this->localPart)))) + && (preg_match('/^"(['. $qtext .']|\x5c[' . $quotedPair . '])*"$/', $this->localPart))) { + $result = true; + } else { + $this->_error(self::DOT_ATOM); + $this->_error(self::QUOTED_STRING); + $this->_error(self::INVALID_LOCAL_PART); + } + } + + return $result; + } + + /** + * Internal method to validate the servers MX records + * + * @return boolean + */ + private function _validateMXRecords() + { + $mxHosts = array(); + $hostname = $this->_hostname; + + //decode IDN domain name if possible + if (function_exists('idn_to_ascii')) { + $hostname = idn_to_ascii($this->_hostname); + } + + $result = getmxrr($hostname, $mxHosts); + if (!$result) { + $this->_error(self::INVALID_MX_RECORD); + } else if ($this->_options['deep'] && function_exists('checkdnsrr')) { + $validAddress = false; + $reserved = true; + foreach ($mxHosts as $hostname) { + $res = $this->_isReserved($hostname); + if (!$res) { + $reserved = false; + } + + if (!$res + && (checkdnsrr($hostname, "A") + || checkdnsrr($hostname, "AAAA") + || checkdnsrr($hostname, "A6"))) { + $validAddress = true; + break; + } + } + + if (!$validAddress) { + $result = false; + if ($reserved) { + $this->_error(self::INVALID_SEGMENT); + } else { + $this->_error(self::INVALID_MX_RECORD); + } + } + } + + return $result; + } + + /** + * Internal method to validate the hostname part of the email address + * + * @return boolean + */ + private function _validateHostnamePart() + { + $hostname = $this->_options['hostname']->setTranslator($this->getTranslator()) + ->isValid($this->_hostname); + if (!$hostname) { + $this->_error(self::INVALID_HOSTNAME); + + // Get messages and errors from hostnameValidator + foreach ($this->_options['hostname']->getMessages() as $code => $message) { + $this->_messages[$code] = $message; + } + + foreach ($this->_options['hostname']->getErrors() as $error) { + $this->_errors[] = $error; + } + } else if ($this->_options['mx']) { + // MX check on hostname + $hostname = $this->_validateMXRecords(); + } + + return $hostname; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is a valid email address + * according to RFC2822 + * + * @link http://www.ietf.org/rfc/rfc2822.txt RFC2822 + * @link http://www.columbia.edu/kermit/ascii.html US-ASCII characters + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $matches = array(); + $length = true; + $this->_setValue($value); + + // Split email address up and disallow '..' + if ((strpos($value, '..') !== false) or + (!preg_match('/^(.+)@([^@]+)$/', $value, $matches))) { + $this->_error(self::INVALID_FORMAT); + return false; + } + + $this->_localPart = $matches[1]; + $this->_hostname = $matches[2]; + + if ((strlen($this->_localPart) > 64) || (strlen($this->_hostname) > 255)) { + $length = false; + $this->_error(self::LENGTH_EXCEEDED); + } + + // Match hostname part + if ($this->_options['domain']) { + $hostname = $this->_validateHostnamePart(); + } + + $local = $this->_validateLocalPart(); + + // If both parts valid, return true + if ($local && $length) { + if (($this->_options['domain'] && $hostname) || !$this->_options['domain']) { + return true; + } + } + + return false; + } +} diff --git a/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option.phtml b/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option.phtml index 3660eb39245..a18fdfeb0d4 100644 --- a/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option.phtml +++ b/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option.phtml @@ -213,6 +213,7 @@ optionIndex = bOption.add(toJson() ?>); getSelections()):?> getSelections() as $_selection): ?> setName($this->escapeHtml($_selection->getName())); ?> + setSku($this->escapeHtml($_selection->getSku())); ?> bSelection.addRow(optionIndex, toJson() ?>); diff --git a/app/design/adminhtml/default/default/template/system/shipping/ups.phtml b/app/design/adminhtml/default/default/template/system/shipping/ups.phtml index a011d2e9d12..e9a6203ffa5 100644 --- a/app/design/adminhtml/default/default/template/system/shipping/ups.phtml +++ b/app/design/adminhtml/default/default/template/system/shipping/ups.phtml @@ -52,6 +52,15 @@ if (!$storeCode && $websiteCode) { $storedFreeShipment = Mage::getStoreConfig('carriers/ups/free_method'); $storedUpsType = Mage::getStoreConfig('carriers/ups/type'); } +if (!in_array($storedOriginShipment, array_keys($orShipArr))) { + $storedOriginShipment = ''; +} +if ($storedFreeShipment != '' && !in_array($storedFreeShipment, array_keys($defShipArr))) { + $storedFreeShipment = ''; +} +if (!Mage::helper('usa')->validateUpsType($storedUpsType)) { + $storedUpsType = ''; +} ?>