From aac5e96befbdcb823d09b447bc2252db2b2b2c2d Mon Sep 17 00:00:00 2001 From: Denis Ryabov Date: Tue, 5 Sep 2023 12:11:38 +0400 Subject: [PATCH] fix and improve processing of deprecated framework api --- .../language/en-GB/en-GB.com_jedchecker.ini | 1 + .../libraries/rules/framework.ini | 4 +- .../libraries/rules/framework.php | 92 ++++++++++++++----- 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/administrator/components/com_jedchecker/language/en-GB/en-GB.com_jedchecker.ini b/administrator/components/com_jedchecker/language/en-GB/en-GB.com_jedchecker.ini index a228002..9492195 100644 --- a/administrator/components/com_jedchecker/language/en-GB/en-GB.com_jedchecker.ini +++ b/administrator/components/com_jedchecker/language/en-GB/en-GB.com_jedchecker.ini @@ -85,6 +85,7 @@ COM_JEDCHECKER_ERROR_FRAMEWORK_LEFTOVER_FOLDER="Leftover folder detected" COM_JEDCHECKER_ERROR_FRAMEWORK_LEFTOVER_FILE="Leftover file detected" COM_JEDCHECKER_ERROR_FRAMEWORK_STRICT="PHP Strict Standards: Only variables should be assigned by reference" COM_JEDCHECKER_ERROR_FRAMEWORK_LEADING_SPACES="Spaces at the beginning of PHP file detected (it might result in the 'Cannot modify header information - headers already sent' warning message)" +COM_JEDCHECKER_ERROR_FRAMEWORK_INSTEAD_USE="Instead use" COM_JEDCHECKER_RULE_JAMSS="JAMSS - Joomla! Anti-Malware Scan Script" COM_JEDCHECKER_RULE_JAMSS_DESC="JAMSS will raise many flags for use of potentially dangerous methods, additionally checking for some known attack signatures. Find out more on the Project's homepage
JAMSS output is very verbose and very useful, hover over any lines to see the details." COM_JEDCHECKER_ERROR_JAMSS_SUSPICIOUS_FILENAME="Suspicious filename found :" diff --git a/administrator/components/com_jedchecker/libraries/rules/framework.ini b/administrator/components/com_jedchecker/libraries/rules/framework.ini index fc3db99..ec1c54d 100644 --- a/administrator/components/com_jedchecker/libraries/rules/framework.ini +++ b/administrator/components/com_jedchecker/libraries/rules/framework.ini @@ -34,9 +34,9 @@ todo="@TODO" compatibility_groups="notinj3,notinj4,deprecated,deprecatedinj4,jerr,DS,strict" notinj3="JUtility::isWinOS,JFTP,JLDAP,JWebClient,JloadResultArray,nameQuote,JRequest::checkToken,JParameter,JElement,JFormFieldEditors,JHtmlImage,JRules,JSimpleXML,JPane,$db->getEscaped,JDate::toMysql,JUtility::sendMail,JUtility::sendAdminMail,JUtility::getToken,JFactory::getXMLParser,JDate::toMysql" -notinj4="JInstallerComponent,JInstallerFile,JInstallerLanguage,JInstallerLibrary,JInstallerModule,JInstallerPackage,JInstallerPlugin,JInstallerTemplate,JSubMenuHelper,pagination_item_active,pagination_item_inactive,JVersion::RELEASE,JVersion::DEV_LEVEL,JVersion::BUILD,JHtmlBootstrap::modal,JHtml::_('bootstrap.modal',JHtmlBatch,JHtml::_('batch.,JAccess::$assetPermissionsById,JAccess::$assetPermissionsByName,JAccess::preloadPermissionsParentIdMapping,JAccess::getActions,JApplicationWebRouter,JApplicationWebRouterBase,JApplicationWebRouterRest,$app->getPageParameters,JApplicationHelper::parseXMLLangMetaFile,JCrypt::hasStrongPasswordSupport,JCacheStorage::test,JFactory::getXml,Factory::getXml,JFactory::getEditor,Factory::getEditor,JFilterInput::_,JNode,JTree,JGrid,JArrayHelper,$_PROFILER" +notinj4="JInstallerComponent=>JInstallerAdapterComponent,JInstallerFile=>JInstallerAdapterFile,JInstallerLanguage=>JInstallerAdapterLanguage,JInstallerLibrary=>JInstallerAdapterLibrary,JInstallerModule=>JInstallerAdapterModule,JInstallerPackage=>JInstallerAdapterPackage,JInstallerPlugin=>JInstallerAdapterPlugin,JInstallerTemplate=>JInstallerAdapterTemplate,JSubMenuHelper=>JHtmlSidebar,pagination_item_active=>JLayout joomla.pagination.link,pagination_item_inactive=>JLayout joomla.pagination.link,JVersion::RELEASE,JVersion::DEV_LEVEL,JVersion::BUILD,JHtmlBootstrap::modal=>JHtmlBootstrap::renderModal,JHtml::_('bootstrap.modal'=>JHtml::_('bootstrap.renderModal',JHtmlBatch=>JLayouts,JHtml::_('batch.,JAccess::$assetPermissionsById,JAccess::$assetPermissionsByName,JAccess::preloadPermissionsParentIdMapping,JAccess::getActions=>JAccess::getActionsFromFile/JAccess::getActionsFromData,JApplicationWebRouter=>joomla/router package,JApplicationWebRouterBase=>joomla/router package,JApplicationWebRouterRest=>joomla/router package,->isSite()=>isClient,->isAdmin()=>isClient,$app->getPageParameters=>getParams,JApplicationHelper::parseXMLLangMetaFile,JCrypt::hasStrongPasswordSupport,JCryptCipher3Des=>JCryptCipherCryptoбJCryptCipherBlowfish=>JCryptCipherCrypto,JCryptCipherMcrypt=>JCryptCipherCrypto,JCryptCipherRijndael256=>JCryptCipherCrypto,JCryptCipherSimpleJCacheStorage::test,JFactory::getXml=>SimpleXMLElement,Factory::getXml=>SimpleXMLElement,JFactory::getEditor=>JEditor::getInstance,Factory::getEditor=>JEditor::getInstance,JFactory::getUri=>Uri::getInstance,Factory::getUri=>Uri::getInstance,JBrowser::isSSLConnection=>JApplicationCms::isSSLConnection,JFilterInput::_,JNode,JTree,JGrid,JArrayHelper=>Joomla\\Utilities\\ArrayHelper,$_PROFILER=>Joomla\\CMS\\Profiler\\Profiler::getInstance,JProfiler::getmicrotime,JProfiler::getMemory,JMail::sendAdminMail,JString=>Joomla\\String\\StringHelper" deprecated="JHtmlBehavior::mootools,JHtml::_('behavior.mootools',JRequest,->assignRef" -deprecatedinj4="pagination_list_render,JHtmlSortablelist::sortable,JHtml::_('sortablelist.sortable',JApplicationBase" +deprecatedinj4="pagination_list_render=>JLayout joomla.pagination.list,JHtmlSortablelist::sortable=>JHtmlDraggablelist::draggable,JHtml::_('sortablelist.sortable'=>JHtml::_('draggablelist.draggable',JApplicationBase=>Joomla\\Application\\AbstractApplication" jerr="JError::" DS=" DS ,.DS., DS.,.DS " strict="&JFactory,&JModuleHelper" diff --git a/administrator/components/com_jedchecker/libraries/rules/framework.php b/administrator/components/com_jedchecker/libraries/rules/framework.php index a60d12a..3bbb9dc 100644 --- a/administrator/components/com_jedchecker/libraries/rules/framework.php +++ b/administrator/components/com_jedchecker/libraries/rules/framework.php @@ -169,24 +169,31 @@ class JedcheckerRulesFramework extends JEDcheckerRule } // Clean non-code - $content = JEDCheckerHelper::cleanPhpCode( + $cleanContent = JEDCheckerHelper::cleanPhpCode( $content, JEDCheckerHelper::CLEAN_HTML | JEDCheckerHelper::CLEAN_COMMENTS | JEDCheckerHelper::CLEAN_STRINGS ); - $cleanContent = JEDCheckerHelper::splitLines($content); // Check short PHP tag - if (preg_match('/<\?\s/', $content, $match, PREG_OFFSET_CAPTURE)) + if (preg_match('/<\?\s/', $cleanContent, $match, PREG_OFFSET_CAPTURE)) { - $lineno = substr_count($content, "\n", 0, $match[0][1]); + $lineno = substr_count($cleanContent, "\n", 0, $match[0][1]); $this->report->addError($file, Text::_('COM_JEDCHECKER_ERROR_FRAMEWORK_SHORT_PHP_TAG'), $lineno + 1, $origContent[$lineno]); $result = true; } + $cleanContentKeepStrings = JEDCheckerHelper::cleanPhpCode( + $content, + JEDCheckerHelper::CLEAN_HTML | JEDCheckerHelper::CLEAN_COMMENTS + ); + + $cleanContent = JEDCheckerHelper::splitLines($cleanContent); + $cleanContentKeepStrings = JEDCheckerHelper::splitLines($cleanContentKeepStrings); + // Run other tests foreach ($this->getTests() as $testObject) { - if ($this->runTest($file, $origContent, $cleanContent, $testObject)) + if ($this->runTest($file, $origContent, $cleanContent, $cleanContentKeepStrings, $testObject)) { $result = true; } @@ -201,11 +208,12 @@ class JedcheckerRulesFramework extends JEDcheckerRule * @param string $file The file name * @param array $origContent The file content * @param array $cleanContent The file content w/o non-code elements + * @param array $cleanContentKeepStrings The file content w/o comments and HTML * @param object $testObject The test object generated by getTests() * * @return boolean */ - private function runTest($file, $origContent, $cleanContent, $testObject) + private function runTest($file, $origContent, $cleanContent, $cleanContentKeepStrings, $testObject) { // @todo remove as unused? $error_count = 0; @@ -216,25 +224,18 @@ class JedcheckerRulesFramework extends JEDcheckerRule foreach ($testObject->tests as $singleTest) { - $regex = preg_quote($singleTest, '/'); + $lineContent = $singleTest->keepStrings ? $cleanContentKeepStrings[$line_number] : $line; - // Add word boundary check for rules staring/ending with a letter (to avoid false-positives because of partial match) - - if (ctype_alpha($singleTest[0])) + if (preg_match($singleTest->regex, $lineContent)) { - $regex = '\b' . $regex; - } - - if (ctype_alpha($singleTest[strlen($singleTest) - 1])) - { - $regex .= '\b'; - } - - if (preg_match('/' . $regex . '/i', $line)) - { - $origLine = str_ireplace($singleTest, '' . $singleTest . '', htmlspecialchars($origLine)); + $origLine = str_ireplace($singleTest->test, '' . $singleTest->test . '', htmlspecialchars($origLine)); $error_message = Text::_('COM_JEDCHECKER_ERROR_FRAMEWORK_' . strtoupper($testObject->group)) . ':
' . $origLine . '
'; + if ($singleTest->replacement !== false) + { + $error_message .= Text::_('COM_JEDCHECKER_ERROR_FRAMEWORK_INSTEAD_USE') . ': ' . $singleTest->replacement; + } + switch ($testObject->kind) { case 'error': @@ -290,7 +291,28 @@ class JedcheckerRulesFramework extends JEDcheckerRule $newTest = new stdClass; $newTest->group = $group; $newTest->kind = $test; - $newTest->tests = explode(",", $this->params->get($group)); + $newTest->tests = array(); + + foreach (explode(",", $this->params->get($group)) as $test) + { + if (strpos($test, '=>') !== false) + { + list($test, $replacement) = explode('=>', $test, 2); + } + else + { + $replacement = false; + } + + $testObj = new stdClass; + $testObj->test = $test; + $testObj->regex = $this->generateRegex($test); + $testObj->replacement = $replacement; + $testObj->keepStrings = strpos($test, "'") !== false; + + $newTest->tests[] = $testObj; + } + $this->tests[] = $newTest; } } @@ -298,4 +320,30 @@ class JedcheckerRulesFramework extends JEDcheckerRule return $this->tests; } + + /** + * Generates regular expression for a given test + * + * @param string $test The string to match + * @param boolean $matchCase True for case-sensitive matching + * + * @return string + */ + private function generateRegex($test, $matchCase = false) + { + $regex = preg_quote($test, '/'); + + // Add word boundary check for rules staring/ending with a letter (to avoid false-positives because of partial match) + if (ctype_alpha($test[0])) + { + $regex = '\b' . $regex; + } + + if (ctype_alpha($test[strlen($test) - 1])) + { + $regex .= '\b'; + } + + return '/' . $regex . '/' . ($matchCase ? '' : 'i'); + } }