PageRenderTime 68ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/administrator/components/com_admintools/Model/ControlPanel.php

https://bitbucket.org/saltwaterdev/offshorefinancial.com
PHP | 611 lines | 355 code | 103 blank | 153 comment | 46 complexity | 6622d99465b2a1a7ffab62b6492634ef MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0, 0BSD, MIT, Apache-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @package AdminTools
  4. * @copyright 2010-2017 Akeeba Ltd / Nicholas K. Dionysopoulos
  5. * @license GNU General Public License version 3, or later
  6. */
  7. namespace Akeeba\AdminTools\Admin\Model;
  8. defined('_JEXEC') or die;
  9. use Akeeba\AdminTools\Admin\Helper\Storage;
  10. use Akeeba\Engine\Platform;
  11. use Akeeba\Engine\Util\Complexify;
  12. use FOF30\Database\Installer;
  13. use FOF30\Model\Model;
  14. use FOF30\Utils\CacheCleaner;
  15. use FOF30\Utils\Ip;
  16. use JText;
  17. class ControlPanel extends Model
  18. {
  19. /**
  20. * The extension ID of the System - Admin Tools plugin
  21. *
  22. * @var int
  23. */
  24. static $pluginId = null;
  25. /**
  26. * Get the extension ID of the System - Admin Tools plugin
  27. *
  28. * @return int
  29. */
  30. public function getPluginID()
  31. {
  32. if (empty(static::$pluginId))
  33. {
  34. $db = $this->container->db;
  35. $query = $db->getQuery(true)
  36. ->select($db->qn('extension_id'))
  37. ->from($db->qn('#__extensions'))
  38. ->where($db->qn('enabled') . ' >= ' . $db->q('1'))
  39. ->where($db->qn('folder') . ' = ' . $db->q('system'))
  40. ->where($db->qn('element') . ' = ' . $db->q('admintools'))
  41. ->where($db->qn('type') . ' = ' . $db->q('plugin'))
  42. ->order($db->qn('ordering') . ' ASC');
  43. static::$pluginId = $db->setQuery($query)->loadResult();
  44. }
  45. return static::$pluginId;
  46. }
  47. /**
  48. * Makes sure our system plugin is really the very first system plugin to execute
  49. *
  50. * @return void
  51. */
  52. public function reorderPlugin()
  53. {
  54. // Get our plugin's ID
  55. $id = $this->getPluginID();
  56. // The plugin is not enabled, there's no point in continuing
  57. if (!$id)
  58. {
  59. return;
  60. }
  61. // Get a list of ordering values per ID
  62. $db = $this->container->db;
  63. $query = $db->getQuery(true)
  64. ->select(array(
  65. $db->qn('extension_id'),
  66. $db->qn('ordering'),
  67. ))
  68. ->from($db->qn('#__extensions'))
  69. ->where($db->qn('type') . ' = ' . $db->q('plugin'))
  70. ->where($db->qn('folder') . ' = ' . $db->q('system'))
  71. ->order($db->qn('ordering') . ' ASC');
  72. $orderingPerId = $db->setQuery($query)->loadAssocList('extension_id', 'ordering');
  73. $orderings = array_values($orderingPerId);
  74. $orderings = array_unique($orderings);
  75. $minOrdering = reset($orderings);
  76. $myOrdering = $orderingPerId[ $id ];
  77. reset($orderings);
  78. $sharedOrderings = 0;
  79. foreach ($orderingPerId as $fooid => $order)
  80. {
  81. if ($order > $myOrdering)
  82. {
  83. break;
  84. }
  85. if ($order == $myOrdering)
  86. {
  87. $sharedOrderings++;
  88. }
  89. }
  90. // Do I need to reorder the plugin?
  91. if (($myOrdering > $minOrdering) || ($sharedOrderings > 1))
  92. {
  93. $query = $db->getQuery(true)
  94. ->update($db->qn('#__extensions'))
  95. ->set($db->qn('ordering') . ' = ' . $db->q($minOrdering - 1))
  96. ->where($db->qn('extension_id') . ' = ' . $db->q($id));
  97. $db->setQuery($query);
  98. $db->execute();
  99. // Reset the Joomla! plugins cache
  100. CacheCleaner::clearPluginsCache();
  101. }
  102. }
  103. /**
  104. * Does the user need to enter a Download ID in the component's Options page?
  105. *
  106. * @return bool
  107. */
  108. public function needsDownloadID()
  109. {
  110. // Do I need a Download ID?
  111. if (!ADMINTOOLS_PRO)
  112. {
  113. return false;
  114. }
  115. $dlid = $this->container->params->get('downloadid', '');
  116. if (!preg_match('/^([0-9]{1,}:)?[0-9a-f]{32}$/i', $dlid))
  117. {
  118. return true;
  119. }
  120. return false;
  121. }
  122. /**
  123. * Checks the database for missing / outdated tables using the $dbChecks
  124. * data and runs the appropriate SQL scripts if necessary.
  125. *
  126. * @throws \RuntimeException If the previous database update is stuck
  127. *
  128. * @return $this
  129. */
  130. public function checkAndFixDatabase()
  131. {
  132. $params = $this->container->params;
  133. // First of all let's check if we are already updating
  134. $stuck = $params->get('updatedb', 0);
  135. if ($stuck)
  136. {
  137. throw new \RuntimeException('Previous database update is flagged as stuck');
  138. }
  139. // Then set the flag
  140. $params->set('updatedb', 1);
  141. $params->save();
  142. // Install or update database
  143. $db = $this->container->db;
  144. $dbInstaller = new Installer($db, JPATH_ADMINISTRATOR . '/components/com_admintools/sql/xml');
  145. $dbInstaller->updateSchema();
  146. // Let's check and fix common tables, too
  147. /** @var Stats $statsModel */
  148. $statsModel = $this->container->factory->model('Stats')->tmpInstance();
  149. $statsModel->checkAndFixCommonTables();
  150. // And finally remove the flag if everything went fine
  151. $params->set('updatedb', null);
  152. $params->save();
  153. return $this;
  154. }
  155. /**
  156. * Checks all the available places if we just blocked our own IP?
  157. *
  158. * @param string $externalIp Additional IP address to check
  159. *
  160. * @return bool
  161. */
  162. public function isMyIPBlocked($externalIp = null)
  163. {
  164. // First let's get the current IP of the user
  165. $ipList[] = $this->getVisitorIP();
  166. if ($externalIp)
  167. {
  168. $ipList[] = $externalIp;
  169. }
  170. /** @var AutoBannedAddresses $autoban */
  171. $autoban = $this->container->factory->model('AutoBannedAddresses')->tmpInstance();
  172. /** @var IPAutoBanHistories $history */
  173. $history = $this->container->factory->model('IPAutoBanHistories')->tmpInstance();
  174. /** @var BlacklistedAddresses $black */
  175. $black = $this->container->factory->model('BlacklistedAddresses')->tmpInstance();
  176. // Then for each ip let's check if it's in any "blocked" list
  177. foreach ($ipList as $ip)
  178. {
  179. $autoban->reset()->setState('ip', $ip);
  180. $history->reset()->setState('ip', $ip);
  181. $black->reset()->setState('ip', $ip);
  182. if (count($autoban->get(true)))
  183. {
  184. return true;
  185. }
  186. if (count($history->get(true)))
  187. {
  188. return true;
  189. }
  190. if (count($black->get(true)))
  191. {
  192. return true;
  193. }
  194. }
  195. return false;
  196. }
  197. /**
  198. * Removed the current IP from all the "block" lists
  199. *
  200. * @param string $externalIp Additional IP address to check
  201. *
  202. * @return void
  203. */
  204. public function unblockMyIP($externalIp = null)
  205. {
  206. // First let's get the current IP of the user
  207. $ipList[] = $this->getVisitorIP();
  208. if ($externalIp)
  209. {
  210. $ipList[] = $externalIp;
  211. }
  212. /** @var AutoBannedAddresses $autoban */
  213. $autoban = $this->container->factory->model('AutoBannedAddresses')->tmpInstance();
  214. /** @var IPAutoBanHistories $history */
  215. $history = $this->container->factory->model('IPAutoBanHistories')->tmpInstance();
  216. /** @var BlacklistedAddresses $black */
  217. $black = $this->container->factory->model('BlacklistedAddresses')->tmpInstance();
  218. /** @var SecurityExceptions $log */
  219. $log = $this->container->factory->model('SecurityExceptions')->tmpInstance();
  220. $db = $this->container->db;
  221. // Let's delete all the IP. We are going to directly use the database since it would be faster
  222. // than loading the record and then deleting it
  223. foreach ($ipList as $ip)
  224. {
  225. $autoban->reset()->setState('ip', $ip);
  226. $history->reset()->setState('ip', $ip);
  227. $black->reset()->setState('ip', $ip);
  228. $log->reset()->setState('ip', $ip);
  229. if (count($autoban->get(true)))
  230. {
  231. $query = $db->getQuery(true)
  232. ->delete($db->qn('#__admintools_ipautoban'))
  233. ->where($db->qn('ip') . ' = ' . $db->q($ip));
  234. $db->setQuery($query)->execute();
  235. }
  236. if (count($history->get(true)))
  237. {
  238. $query = $db->getQuery(true)
  239. ->delete($db->qn('#__admintools_ipautobanhistory'))
  240. ->where($db->qn('ip') . ' = ' . $db->q($ip));
  241. $db->setQuery($query)->execute();
  242. }
  243. if (count($black->get(true)))
  244. {
  245. $query = $db->getQuery(true)
  246. ->delete($db->qn('#__admintools_ipblock'))
  247. ->where($db->qn('ip') . ' = ' . $db->q($ip));
  248. $db->setQuery($query)->execute();
  249. }
  250. // I have to delete the log of security exceptions, too. Otherwise at the next check the user will be
  251. // banned once again
  252. if (count($log->get(true)))
  253. {
  254. $query = $db->getQuery(true)
  255. ->delete($db->qn('#__admintools_log'))
  256. ->where($db->qn('ip') . ' = ' . $db->q($ip));
  257. $db->setQuery($query)->execute();
  258. }
  259. }
  260. }
  261. /**
  262. * Update the cached live site's URL for the front-end scheduling feature
  263. *
  264. * @return void
  265. */
  266. public function updateMagicParameters()
  267. {
  268. $this->container->params->set('siteurl', str_replace('/administrator', '', \JUri::base()));
  269. $this->container->params->save();
  270. }
  271. /**
  272. * Check the strength of the Secret Word for front-end and remote scans. If it is insecure return the reason it
  273. * is insecure as a string. If the Secret Word is secure return an empty string.
  274. *
  275. * @return string
  276. */
  277. public function getFrontendSecretWordError()
  278. {
  279. // Load the Akeeba Engine autoloader
  280. define('AKEEBAENGINE', 1);
  281. require_once JPATH_ADMINISTRATOR . '/components/com_admintools/engine/Autoloader.php';
  282. // Load the platform
  283. Platform::addPlatform('filescan', JPATH_ADMINISTRATOR . '/components/com_admintools/platform/Filescan');
  284. // Is frontend backup enabled?
  285. $febEnabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0) != 0;
  286. if (!$febEnabled)
  287. {
  288. return '';
  289. }
  290. $secretWord = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
  291. try
  292. {
  293. Complexify::isStrongEnough($secretWord);
  294. }
  295. catch (\RuntimeException $e)
  296. {
  297. // Ah, the current Secret Word is bad. Create a new one if necessary.
  298. $newSecret = $this->container->platform->getSessionVar('newSecretWord', null, 'admintools.cpanel');
  299. if (empty($newSecret))
  300. {
  301. $random = new \Akeeba\Engine\Util\RandomValue();
  302. $newSecret = $random->generateString(32);
  303. $this->container->platform->setSessionVar('newSecretWord', $newSecret, 'admintools.cpanel');
  304. }
  305. return $e->getMessage();
  306. }
  307. return '';
  308. }
  309. /**
  310. * Performs some checks about Joomla configuration (log and tmp path correctly set)
  311. *
  312. * @return string|bool Warning message. Boolean FALSE if no warning is found.
  313. */
  314. public function checkJoomlaConfiguration()
  315. {
  316. // Let's get the site root using the Platform code
  317. if (!defined('AKEEBAENGINE'))
  318. {
  319. define('AKEEBAENGINE', 1);
  320. }
  321. require_once JPATH_ADMINISTRATOR . '/components/com_admintools/engine/Autoloader.php';
  322. $siteroot = Platform::getInstance()->get_site_root();
  323. $siteroot_real = @realpath($siteroot);
  324. if (!empty($siteroot_real))
  325. {
  326. $siteroot = $siteroot_real;
  327. }
  328. //First of all, do we have a VALID log folder?
  329. $config = $this->container->platform->getConfig();
  330. $log_dir = $config->get('log_path');
  331. if (!$log_dir || !@is_writable($log_dir))
  332. {
  333. return JText::_('COM_ADMINTOOLS_ERR_CONTROLPANEL_JCONFIG_INVALID_LOGDIR');
  334. }
  335. if ($siteroot == $log_dir)
  336. {
  337. return JText::_('COM_ADMINTOOLS_ERR_CONTROLPANEL_JCONFIG_LOGDIR_SITEROOT');
  338. }
  339. // Do we have a VALID tmp folder?
  340. $tmp_dir = $config->get('tmp_path');
  341. if (!$tmp_dir || !@is_writable($tmp_dir))
  342. {
  343. return JText::_('COM_ADMINTOOLS_ERR_CONTROLPANEL_JCONFIG_INVALID_TMPDIR');
  344. }
  345. if ($siteroot == $tmp_dir)
  346. {
  347. return JText::_('COM_ADMINTOOLS_ERR_CONTROLPANEL_JCONFIG_TMPDIR_SITEROOT');
  348. }
  349. return false;
  350. }
  351. /**
  352. * Do I need to show the Quick Setup Wizard?
  353. *
  354. * @return bool
  355. */
  356. public function needsQuickSetupWizard()
  357. {
  358. $params = Storage::getInstance();
  359. return $params->getValue('quickstart', 0) == 0;
  360. }
  361. /**
  362. * Get the most likely visitor IP address, reported by the server
  363. *
  364. * @return string
  365. */
  366. public function getVisitorIP()
  367. {
  368. $internalIP = Ip::getIp();
  369. if ((strpos($internalIP, '::') === 0) && (strstr($internalIP, '.') !== false))
  370. {
  371. $internalIP = substr($internalIP, 2);
  372. }
  373. return $internalIP;
  374. }
  375. /**
  376. * Checks if we have detected private network IPs AND the IP Workaround feature is turned off
  377. *
  378. * @return bool
  379. */
  380. public function needsIpWorkarounds()
  381. {
  382. $WAFparams = Storage::getInstance();
  383. $params = $this->container->params;
  384. // If IP Workarounds is disabled AND we have detected private IPs, show the warning
  385. if (!$WAFparams->getValue('ipworkarounds', -1) && ($params->get('detected_exceptions_from_private_network') === 1))
  386. {
  387. return true;
  388. }
  389. return false;
  390. }
  391. /**
  392. * Sets the IP workarounds or ignores the warning
  393. *
  394. * @param $state
  395. */
  396. public function setIpWorkarounds($state)
  397. {
  398. if ($state)
  399. {
  400. $WAFparams = Storage::getInstance();
  401. $WAFparams->setValue('ipworkarounds', 1, true);
  402. }
  403. else
  404. {
  405. // If we user wants to ignore the warning, let's set the flag to -1 (ignore)
  406. $params = $this->container->params;
  407. $params->set('detected_exceptions_from_private_network', -1);
  408. $params->save();
  409. }
  410. }
  411. /**
  412. * Is the System - Admin Tools plugin installed?
  413. *
  414. * @return bool
  415. *
  416. * @since 4.3.0
  417. */
  418. public function isPluginInstalled()
  419. {
  420. $this->getPluginID();
  421. return self::$pluginId != 0;
  422. }
  423. /**
  424. * Is the System - Admin Tools plugin currently loaded?
  425. *
  426. * @return bool
  427. *
  428. * @since 4.3.0
  429. */
  430. public function isPluginLoaded()
  431. {
  432. return class_exists('plgSystemAdmintools');
  433. }
  434. /**
  435. * Is the main.php file renamed?
  436. *
  437. * @return bool
  438. *
  439. * @since 4.3.0
  440. */
  441. public function isMainPhpDisabled()
  442. {
  443. $folder = JPATH_PLUGINS . '/system/admintools/admintools';
  444. return @is_dir($folder) && !@file_exists($folder . '/main.php');
  445. }
  446. /**
  447. * Rename the disabled main.php file back to its proper, main.php, name.
  448. *
  449. * @return bool
  450. *
  451. * @since 4.3.0
  452. */
  453. public function reenableMainPhp()
  454. {
  455. $altName = $this->getRenamedMainPhp();
  456. if (!$altName)
  457. {
  458. return false;
  459. }
  460. $folder = JPATH_PLUGINS . '/system/admintools/admintools';
  461. $from = $folder . '/' . $altName;
  462. $to = $folder . '/main.php';
  463. $res = @rename($from, $to);
  464. if (!$res)
  465. {
  466. $res = @copy($from, $to);
  467. if ($res)
  468. {
  469. @unlink($from);
  470. }
  471. }
  472. if (!$res)
  473. {
  474. $res = \JFile::copy($from, $to);
  475. if ($res)
  476. {
  477. \JFile::delete($from);
  478. }
  479. }
  480. return $res;
  481. }
  482. /**
  483. * Get the file name under which main.php has been renamed to
  484. *
  485. * @return string|null
  486. *
  487. * @since 4.3.0
  488. */
  489. public function getRenamedMainPhp()
  490. {
  491. $possibleNames = array(
  492. 'main-disable.php',
  493. 'main.php.bak',
  494. 'main.bak.php',
  495. 'main.bak',
  496. '-main.php',
  497. );
  498. $folder = JPATH_PLUGINS . '/system/admintools/admintools';
  499. foreach ($possibleNames as $baseName)
  500. {
  501. if (@file_exists($folder . '/' . $baseName))
  502. {
  503. return $baseName;
  504. }
  505. }
  506. return null;
  507. }
  508. }