379 lines
9.1 KiB
PHP
379 lines
9.1 KiB
PHP
<?php
|
|
/**
|
|
* @package solo
|
|
* @copyright Copyright (c)2014-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
|
* @license GNU General Public License version 3, or later
|
|
*/
|
|
|
|
namespace Solo\Controller;
|
|
|
|
use Akeeba\Engine\Factory;
|
|
use Akeeba\Engine\Platform;
|
|
use Akeeba\Engine\Util\RandomValue;
|
|
use AkeebaBackupWPUpdater;
|
|
use Awf\Application\Application;
|
|
use Awf\Mvc\Model;
|
|
use Awf\Text\Text;
|
|
use Exception;
|
|
use RuntimeException;
|
|
use Solo\Model\Update;
|
|
use Solo\View\Main\Html;
|
|
|
|
class Main extends ControllerDefault
|
|
{
|
|
public function switchProfile()
|
|
{
|
|
$this->csrfProtection();
|
|
|
|
// Switch the active profile
|
|
$session = Application::getInstance()->getContainer()->segment;
|
|
$session->profile = $this->input->getInt('profile', 1);
|
|
|
|
// Redirect
|
|
$url = $this->container->router->route('index.php?view=main');
|
|
|
|
$returnURL = $this->input->get('returnurl', '', 'raw');
|
|
if (!empty($returnURL))
|
|
{
|
|
$url = base64_decode($returnURL);
|
|
}
|
|
|
|
$this->setRedirect($url);
|
|
|
|
return true;
|
|
}
|
|
|
|
public function getUpdateInformation()
|
|
{
|
|
// Protect against direct access
|
|
$this->csrfProtection();
|
|
|
|
// Initialise
|
|
$ret = [
|
|
'hasUpdate' => false,
|
|
'version' => '',
|
|
'noticeHTML' => '',
|
|
];
|
|
|
|
// Am I running inside a CMS?
|
|
$inCMS = $this->container->segment->get('insideCMS', false);
|
|
|
|
/** @var Update $updateModel */
|
|
$updateModel = Model::getTmpInstance($this->container->application_name, 'Update', $this->container);
|
|
$ret['hasUpdate'] = $updateModel->getUpdateInformation()->get('hasUpdate', false);
|
|
$ret['version'] = $updateModel->getUpdateInformation()->get('version', 'dev');
|
|
|
|
if ($ret['hasUpdate'])
|
|
{
|
|
$router = $this->container->router;
|
|
$updateHeader = Text::sprintf('SOLO_UPDATE_LBL_MAINNOTICE_TEXT', '<span class="label label-success">' . $ret['version'] . '</span>');
|
|
$updateButton = Text::_('SOLO_UPDATE_BTN_UPDATE_NOW');
|
|
$updateLink = $router->route('index.php?view=update');
|
|
$ret['noticeHTML'] = <<< HTML
|
|
<div class="akeeba-block--warning">
|
|
<h3>
|
|
$updateHeader
|
|
</h3>
|
|
<p style="text-align: center">
|
|
<a href="$updateLink" class="akeeba-btn--large--teal">
|
|
<span class="akion-refresh"></span>
|
|
$updateButton
|
|
</a>
|
|
</p>
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
echo '#"\#\"#' . json_encode($ret) . '#"\#\"#';
|
|
$this->container->application->close();
|
|
}
|
|
|
|
public function applyDownloadId()
|
|
{
|
|
// Protect against direct access
|
|
$this->csrfProtection();
|
|
|
|
$msg = Text::_('COM_AKEEBA_CPANEL_ERR_INVALIDDOWNLOADID');
|
|
$msgType = 'error';
|
|
$dlid = $this->input->getString('dlid', '');
|
|
|
|
// If the Download ID seems legit let's apply it
|
|
if (preg_match('/^([0-9]{1,}:)?[0-9a-f]{32}$/i', $dlid))
|
|
{
|
|
$msg = null;
|
|
$msgType = null;
|
|
|
|
$config = $this->container->appConfig;
|
|
$config->set('options.update_dlid', $dlid);
|
|
$config->saveConfiguration();
|
|
}
|
|
|
|
// Akeeba Backup for WordPress: reset update information
|
|
if (defined('WPINC'))
|
|
{
|
|
$transient = (object) [
|
|
'response' => [],
|
|
];
|
|
AkeebaBackupWPUpdater::getupdates($transient);
|
|
}
|
|
|
|
// Redirect
|
|
$url = $this->container->router->route('index.php?view=main');
|
|
|
|
$returnURL = $this->input->get('returnurl', '', 'raw');
|
|
if (!empty($returnURL))
|
|
{
|
|
$url = base64_decode($returnURL);
|
|
}
|
|
|
|
$this->setRedirect($url, $msg, $msgType);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Reset the Secret Word for front-end and remote backup
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function resetSecretWord()
|
|
{
|
|
// CSRF prevention
|
|
$this->csrfProtection();
|
|
|
|
$session = $this->container->segment;
|
|
$newSecret = $session->get('newSecretWord', null);
|
|
|
|
if (empty($newSecret))
|
|
{
|
|
$random = new RandomValue();
|
|
$newSecret = $random->generateString(32);
|
|
$session->set('newSecretWord', $newSecret);
|
|
}
|
|
|
|
$config = $this->container->appConfig;
|
|
$config->set('options.frontend_secret_word', $newSecret);
|
|
$config->saveConfiguration();
|
|
|
|
$msg = Text::sprintf('COM_AKEEBA_CPANEL_MSG_FESECRETWORD_RESET', $newSecret);
|
|
|
|
$url = $this->container->router->route('index.php?view=Main');
|
|
$this->setRedirect($url, $msg);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Resets the "updatedb" flag and forces the database updates
|
|
*/
|
|
public function forceUpdateDb()
|
|
{
|
|
// Reset the flag so the updates could take place
|
|
$this->container->appConfig->set('updatedb', null);
|
|
$this->container->appConfig->saveConfiguration();
|
|
|
|
/** @var \Solo\Model\Main $model */
|
|
$model = $this->getModel();
|
|
|
|
try
|
|
{
|
|
$model->checkAndFixDatabase();
|
|
}
|
|
catch (RuntimeException $e)
|
|
{
|
|
// This should never happen, since we reset the flag before execute the update, but you never know
|
|
}
|
|
|
|
$url = $this->container->router->route('index.php?view=Main');
|
|
$this->setRedirect($url);
|
|
}
|
|
|
|
/**
|
|
* Dismisses the Core to Pro upsell for 15 days
|
|
*
|
|
* @return void
|
|
*/
|
|
public function dismissUpsell()
|
|
{
|
|
// Reset the flag so the updates could take place
|
|
$this->container->appConfig->set('lastUpsellDismiss', time());
|
|
$this->container->appConfig->saveConfiguration();
|
|
|
|
$url = $this->container->router->route('index.php?view=Main');
|
|
$this->setRedirect($url);
|
|
}
|
|
|
|
/**
|
|
* Check the security of the backup output directory and return the results for consumption through AJAX
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws Exception
|
|
*
|
|
* @since 7.0.3
|
|
*/
|
|
public function checkOutputDirectory()
|
|
{
|
|
/** @var \Solo\Model\Main $model */
|
|
$model = $this->getModel();
|
|
$outDir = $model->getOutputDirectory();
|
|
$inCMS = $this->container->segment->get('insideCMS', false);
|
|
|
|
try
|
|
{
|
|
$result = $model->getOutputDirectoryWebAccessibleState($outDir);
|
|
|
|
if (!$inCMS)
|
|
{
|
|
$altResult = $model->getOutputDirectoryWebAccessibleState($outDir, true);
|
|
|
|
foreach ($altResult as $k => $v)
|
|
{
|
|
$result[$k] = $result[$k] || $altResult[$k];
|
|
}
|
|
}
|
|
}
|
|
catch (RuntimeException $e)
|
|
{
|
|
$result = [
|
|
'readFile' => false,
|
|
'listFolder' => false,
|
|
'isSystem' => $model->isOutputDirectoryInSystemFolder(),
|
|
'hasRandom' => $model->backupFilenameHasRandom(),
|
|
];
|
|
}
|
|
|
|
@ob_end_clean();
|
|
|
|
echo '#"\#\"#' . json_encode($result) . '#"\#\"#';
|
|
|
|
$this->container->application->close();
|
|
}
|
|
|
|
/**
|
|
* Add security files to the output directory of the currently configured backup profile
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws Exception
|
|
*
|
|
* @since 7.0.3
|
|
*/
|
|
public function fixOutputDirectory()
|
|
{
|
|
// CSRF prevention
|
|
$this->csrfProtection();
|
|
|
|
/** @var \Solo\Model\Main $model */
|
|
$model = $this->getModel();
|
|
$outDir = $model->getOutputDirectory();
|
|
|
|
$fsUtils = Factory::getFilesystemTools();
|
|
$fsUtils->ensureNoAccess($outDir, true);
|
|
|
|
$this->setRedirect($this->container->router->route('index.php'));
|
|
}
|
|
|
|
/**
|
|
* Adds the [RANDOM] variable to the backup output filename, save the configuration and reload the Control Panel.
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws Exception
|
|
*
|
|
* @since 7.0.3
|
|
*/
|
|
public function addRandomToFilename()
|
|
{
|
|
// CSRF prevention
|
|
$this->csrfProtection();
|
|
$registry = Factory::getConfiguration();
|
|
$templateName = $registry->get('akeeba.basic.archive_name');
|
|
|
|
if (strpos($templateName, '[RANDOM]') === false)
|
|
{
|
|
$templateName .= '-[RANDOM]';
|
|
$registry->set('akeeba.basic.archive_name', $templateName);
|
|
Platform::getInstance()->save_configuration();
|
|
}
|
|
|
|
$this->setRedirect($this->container->router->route('index.php'));
|
|
}
|
|
|
|
protected function onBeforeDefault()
|
|
{
|
|
// If we are running inside a CMS but there is no active user we have to throw a 403
|
|
$inCMS = $this->container->segment->get('insideCMS', false);
|
|
|
|
if ($inCMS && !$this->container->userManager->getUser()->getId())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/** @var \Solo\Model\Main $model */
|
|
$model = $this->getModel();
|
|
|
|
try
|
|
{
|
|
$model->checkAndFixDatabase();
|
|
}
|
|
catch (RuntimeException $e)
|
|
{
|
|
// The update is stuck. We will display a warning in the Control Panel
|
|
}
|
|
|
|
try
|
|
{
|
|
if ($inCMS)
|
|
{
|
|
$model->updateAutomationConfiguration();
|
|
}
|
|
}
|
|
catch (RuntimeException $e)
|
|
{
|
|
// Oh, well.
|
|
}
|
|
|
|
// Run the update scripts, if necessary
|
|
if ($model->postUpgradeActions())
|
|
{
|
|
$url = $this->container->router->route('index.php?view=main');
|
|
$this->container->application->redirect($url);
|
|
}
|
|
|
|
// Let's make sure the temporary and output directories are set correctly and writable...
|
|
$wizmodel = new \Solo\Model\Wizard($this->container);
|
|
$wizmodel->autofixDirectories();
|
|
|
|
// Rebase Off-site Folder Inclusion filters to use site path variables
|
|
if (class_exists('\Solo\Model\Extradirs'))
|
|
{
|
|
$incFoldersModel = new \Solo\Model\Extradirs($this->container);
|
|
$incFoldersModel->rebaseFiltersToSiteDirs();
|
|
}
|
|
|
|
// Apply settings encryption preferences
|
|
$model->checkEngineSettingsEncryption();
|
|
|
|
// Convert existing log files to the new .log.php format
|
|
$model->convertLogFiles();
|
|
|
|
// Update magic configuration parameters
|
|
$model->updateMagicParameters();
|
|
|
|
// Flag stuck backups
|
|
$model->flagStuckBackups();
|
|
|
|
// Reload the quirks definitions, since flagging stuck backups will reset the factory state,
|
|
// deleting temp objects and their settings
|
|
Platform::getInstance()->apply_quirk_definitions();
|
|
|
|
// Copy the ACL checks to the view. We'll use that information to show or hide icons
|
|
/** @var Html $view */
|
|
$view = $this->getView();
|
|
$view->aclChecks = $this->aclChecks;
|
|
|
|
return true;
|
|
}
|
|
}
|