diff --git a/core/Translate/Validate/BaseTranslations.php b/core/Translate/Validate/BaseTranslations.php new file mode 100644 index 0000000000000000000000000000000000000000..ceae7e3811eb5d10e5953ab077b4c86b6a794591 --- /dev/null +++ b/core/Translate/Validate/BaseTranslations.php @@ -0,0 +1,88 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik\Translate\Validate; + +use Piwik\Translate\Validate\ValidateAbstract; +use Piwik\Common; + +/** + * @package Piwik + * @subpackage Piwik_Translate + */ +class BaseTranslations extends ValidateAbstract +{ + /** + * Error States + */ + const __ERRORSTATE_MINIMUMTRANSLATIONS__ = 'At least 250 translations required'; + const __ERRORSTATE_LOCALEREQUIRED__ = 'Locale required'; + const __ERRORSTATE_TRANSLATORINFOREQUIRED__ = 'Translator info required'; + const __ERRORSTATE_TRANSLATOREMAILREQUIRED__ = 'Translator email required'; + const __ERRORSTATE_LAYOUTDIRECTIONINVALID__ = 'Layout direction must be rtl or ltr'; + const __ERRORSTATE_LOCALEINVALID__ = 'Locale is invalid'; + const __ERRORSTATE_LOCALEINVALIDLANGUAGE__ = 'Locale is invalid - invalid language code'; + const __ERRORSTATE_LOCALEINVALIDCOUNTRY__ = 'Locale is invalid - invalid country code'; + + /** + * Validates the given translations + * + * @param array $translations + * + * @return boolean + * + */ + public function isValid($translations) + { + if (250 > count($translations, COUNT_RECURSIVE)) { + $this->_error = self::__ERRORSTATE_MINIMUMTRANSLATIONS__; + return false; + } + + if (empty($translations['General']['Locale'])) { + $this->_error = self::__ERRORSTATE_LOCALEREQUIRED__; + return false; + } + + if (empty($translations['General']['TranslatorName'])) { + $this->_error = self::__ERRORSTATE_TRANSLATORINFOREQUIRED__; + return false; + } + + if (empty($translations['General']['TranslatorEmail'])) { + $this->_error = self::__ERRORSTATE_TRANSLATOREMAILREQUIRED__; + return false; + } + + if (!empty($translations['General']['LayoutDirection']) && + !in_array($translations['General']['LayoutDirection'], array('ltr', 'rtl')) + ) { + $this->_error = self::__ERRORSTATE_LAYOUTDIRECTIONINVALID__; + return false; + } + + $allLanguages = Common::getLanguagesList(); + $allCountries = Common::getCountriesList(); + + if (!preg_match('/^([a-z]{2})_([A-Z]{2})\.UTF-8$/', $translations['General']['Locale'], $matches)) { + $this->_error = self::__ERRORSTATE_LOCALEINVALID__; + return false; + } else if (!array_key_exists($matches[1], $allLanguages)) { + $this->_error = self::__ERRORSTATE_LOCALEINVALIDLANGUAGE__; + return false; + } else if (!array_key_exists(strtolower($matches[2]), $allCountries)) { + $this->_error = self::__ERRORSTATE_LOCALEINVALIDCOUNTRY__; + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/core/Translate/Validate/NoScripts.php b/core/Translate/Validate/NoScripts.php new file mode 100644 index 0000000000000000000000000000000000000000..b3017b840cf18cec58e269a09e0ffcfd3aba3109 --- /dev/null +++ b/core/Translate/Validate/NoScripts.php @@ -0,0 +1,46 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik\Translate\Validate; + +use Piwik\Translate\Validate\ValidateAbstract; +use Piwik\Common; + +/** + * @package Piwik + * @subpackage Piwik_Translate + */ +class NoScripts extends ValidateAbstract +{ + /** + * Validates the given translations + * + * @param array $translations + * + * @return boolean + * + */ + public function isValid($translations) + { + $this->_error = null; + + // check if any translation contains restricted script tags + $serializedStrings = serialize($translations); + $invalids = array("<script", 'document.', 'javascript:', 'src=', 'background=', 'onload='); + foreach ($invalids as $invalid) { + if (stripos($serializedStrings, $invalid) !== false) { + $this->_error = 'script tags restricted for language files'; + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/core/Translate/Validate/ValidateAbstract.php b/core/Translate/Validate/ValidateAbstract.php new file mode 100644 index 0000000000000000000000000000000000000000..6fdee45ed24ea3b6eae3b2c4e5d5e9ac59db6b01 --- /dev/null +++ b/core/Translate/Validate/ValidateAbstract.php @@ -0,0 +1,52 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik\Translate\Validate; + +/** + * @package Piwik + * @subpackage Piwik_Db + */ +abstract class ValidateAbstract +{ + protected $_baseTranslations = array(); + + protected $_error = null; + + /** + * Sets base translations + * + * @param array $baseTranslations + */ + public function __construct($baseTranslations=array()) + { + $this->_baseTranslations = $baseTranslations; + } + + /** + * Returns if the given translations are valid + * + * @param array $translations + * + * @return boolean + * + */ + abstract public function isValid($translations); + + /** + * Returns the error occured while validating + * @return mixed + */ + public function getError() + { + return $this->_error; + } +} \ No newline at end of file diff --git a/tests/PHPUnit/Core/Translate/Validate/BaseTranslationsTest.php b/tests/PHPUnit/Core/Translate/Validate/BaseTranslationsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d8a89bd140a585ef913261c2a80fa813a6d91f90 --- /dev/null +++ b/tests/PHPUnit/Core/Translate/Validate/BaseTranslationsTest.php @@ -0,0 +1,138 @@ +<?php +use Piwik\Translate\Validate\BaseTranslations; + +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +class BaseTranslationsTest extends PHPUnit_Framework_TestCase +{ + public function getFilterTestDataValid() + { + return array( + array( + array( + 'General' => array_merge(array_fill(0, 251, 'test'), array( + 'Locale' => 'de_DE.UTF-8', + 'TranslatorName' => 'name', + 'TranslatorEmail' => 'email', + ) + ) + ), + ) + ); + } + + /** + * @dataProvider getFilterTestDataValid + * @group Core + * @group Translate + */ + public function testFilterValid($translations) + { + $filter = new BaseTranslations(); + $result = $filter->isValid($translations); + $this->assertTrue($result); + } + + public function getFilterTestDataInvalid() + { + return array( + array( + array( + 'General' => array( + 'bla' => 'test text' + ) + ), + BaseTranslations::__ERRORSTATE_MINIMUMTRANSLATIONS__ + ), + array( + array( + 'General' => array_merge(array_fill(0, 251, 'test'), array( + 'bla' => 'test text' + )) + ), + BaseTranslations::__ERRORSTATE_LOCALEREQUIRED__ + ), + array( + array( + 'General' => array_merge(array_fill(0, 251, 'test'), array( + 'Locale' => 'de_DE.UTF-8' + )) + ), + BaseTranslations::__ERRORSTATE_TRANSLATORINFOREQUIRED__ + ), + array( + array( + 'General' => array_merge(array_fill(0, 251, 'test'), array( + 'Locale' => 'de_DE.UTF-8', + 'TranslatorName' => 'name', + )) + ), + BaseTranslations::__ERRORSTATE_TRANSLATOREMAILREQUIRED__ + ), + array( + array( + 'General' => array_merge(array_fill(0, 251, 'test'), array( + 'Locale' => 'de_DE.UTF-8', + 'TranslatorName' => 'name', + 'TranslatorEmail' => 'emails', + 'LayoutDirection' => 'afd' + )) + ), + BaseTranslations::__ERRORSTATE_LAYOUTDIRECTIONINVALID__ + ), + array( + array( + 'General' => array_merge(array_fill(0, 251, 'test'), array( + 'Locale' => 'invalid', + 'TranslatorName' => 'name', + 'TranslatorEmail' => 'emails', + 'LayoutDirection' => 'ltr' + )) + ), + BaseTranslations::__ERRORSTATE_LOCALEINVALID__ + ), + array( + array( + 'General' => array_merge(array_fill(0, 251, 'test'), array( + 'Locale' => 'xx_DE.UTF-8', + 'TranslatorName' => 'name', + 'TranslatorEmail' => 'emails', + 'LayoutDirection' => 'ltr' + )) + ), + BaseTranslations::__ERRORSTATE_LOCALEINVALIDLANGUAGE__ + ), + array( + array( + 'General' => array_merge(array_fill(0, 251, 'test'), array( + 'Locale' => 'de_XX.UTF-8', + 'TranslatorName' => 'name', + 'TranslatorEmail' => 'emails', + 'LayoutDirection' => 'ltr' + )) + ), + BaseTranslations::__ERRORSTATE_LOCALEINVALIDCOUNTRY__ + ), + ); + } + + /** + * @dataProvider getFilterTestDataInvalid + * @group Core + * @group Translate + */ + public function testFilterInvalid($translations, $msg) + { + include PIWIK_INCLUDE_PATH . '/core/DataFiles/Languages.php'; + include PIWIK_INCLUDE_PATH . '/core/DataFiles/Countries.php'; + + $filter = new BaseTranslations(); + $result = $filter->isValid($translations); + $this->assertFalse($result); + $this->assertEquals($msg, $filter->getError()); + } +} diff --git a/tests/PHPUnit/Core/Translate/Validate/NoScriptsTest.php b/tests/PHPUnit/Core/Translate/Validate/NoScriptsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..75df78b1fefe69179d20af5b465222f264a2989e --- /dev/null +++ b/tests/PHPUnit/Core/Translate/Validate/NoScriptsTest.php @@ -0,0 +1,109 @@ +<?php +use Piwik\Translate\Validate\NoScripts; + +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +class NoScriptsTest extends PHPUnit_Framework_TestCase +{ + public function getFilterTestDataValid() + { + return array( + array( + array(), + ), + array( + array( + 'test' => array() + ), + ), + array( + array( + 'test' => array( + 'key' => 'val%sue', + 'test' => 'test' + ) + ), + ), + ); + } + + /** + * @dataProvider getFilterTestDataValid + * @group Core + * @group Translate + */ + public function testFilterValid($translations) + { + $filter = new NoScripts(); + $result = $filter->isValid($translations); + $this->assertTrue($result); + } + + public function getFilterTestDataInvalid() + { + return array( + array( + array( + 'test' => array( + 'test' => 'test text <script' + ) + ), + ), + array( + array( + 'empty' => array( + 'test' => 'tüsest' + ), + 'test' => array( + 'test' => 'bla <a href="javascript:alert();"> link </a>', + 'empty' => '˜', + ) + ), + ), + array( + array( + 'test' => array( + 'test' => 'bla <a onload="alert();">link</a>' + ) + ), + ), + array( + array( + 'test' => array( + 'test' => 'no <img src="test" />' + ) + ), + ), + array( + array( + 'test' => array( + 'test' => 'that will fail on document. or not?' + ) + ), + ), + array( + array( + 'test' => array( + 'test' => 'bla <a background="yellow">link</a>' + ) + ), + ), + ); + } + + /** + * @dataProvider getFilterTestDataInvalid + * @group Core + * @group Translate + */ + public function testFilterInvalid($translations) + { + $filter = new NoScripts(); + $result = $filter->isValid($translations); + $this->assertFalse($result); + } +}