JEMBOT MAWOT Bypass Shell
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
namespace PrestaShop\PrestaShop\Core\Addon\Theme;
use Employee;
use ErrorException;
use Exception;
use Language;
use PrestaShop\PrestaShop\Core\Addon\AddonManagerInterface;
use PrestaShop\PrestaShop\Core\Addon\Module\ModuleManagerBuilder;
use PrestaShop\PrestaShop\Core\Addon\Theme\Exception\ThemeAlreadyExistsException;
use PrestaShop\PrestaShop\Core\ConfigurationInterface;
use PrestaShop\PrestaShop\Core\Domain\Theme\Exception\FailedToEnableThemeModuleException;
use PrestaShop\PrestaShop\Core\Domain\Theme\Exception\ThemeConstraintException;
use PrestaShop\PrestaShop\Core\Exception\FileNotFoundException;
use PrestaShop\PrestaShop\Core\Foundation\Filesystem\FileSystem as PsFileSystem;
use PrestaShop\PrestaShop\Core\Image\ImageTypeRepository;
use PrestaShop\PrestaShop\Core\Module\HookConfigurator;
use PrestaShopBundle\Service\TranslationService;
use PrestaShopBundle\Translation\Provider\TranslationFinder;
use PrestaShopLogger;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Shop;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Yaml\Parser;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tools;
class ThemeManager implements AddonManagerInterface
{
/**
* @var HookConfigurator
*/
private $hookConfigurator;
/**
* @var Shop
*/
private $shop;
/**
* @var Employee
*/
private $employee;
/**
* @var ThemeValidator
*/
private $themeValidator;
/**
* @var ConfigurationInterface
*/
private $appConfiguration;
/**
* @var Filesystem
*/
private $filesystem;
/**
* @var Finder
*/
private $finder;
/**
* @var string|null
*/
public $sandbox;
/**
* @var ThemeRepository
*/
private $themeRepository;
/**
* @var TranslatorInterface
*/
private $translator;
/**
* @var ImageTypeRepository
*/
private $imageTypeRepository;
/**
* @var TranslationFinder
*/
private $translationFinder;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @param Shop $shop
* @param ConfigurationInterface $configuration
* @param ThemeValidator $themeValidator
* @param TranslatorInterface $translator
* @param Employee $employee
* @param Filesystem $filesystem
* @param Finder $finder
* @param HookConfigurator $hookConfigurator
* @param ThemeRepository $themeRepository
* @param ImageTypeRepository $imageTypeRepository
*/
public function __construct(
Shop $shop,
ConfigurationInterface $configuration,
ThemeValidator $themeValidator,
TranslatorInterface $translator,
Employee $employee,
Filesystem $filesystem,
Finder $finder,
HookConfigurator $hookConfigurator,
ThemeRepository $themeRepository,
ImageTypeRepository $imageTypeRepository,
LoggerInterface $logger = null
) {
$this->translationFinder = new TranslationFinder();
$this->shop = $shop;
$this->appConfiguration = $configuration;
$this->themeValidator = $themeValidator;
$this->translator = $translator;
$this->employee = $employee;
$this->filesystem = $filesystem;
$this->finder = $finder;
$this->hookConfigurator = $hookConfigurator;
$this->themeRepository = $themeRepository;
$this->imageTypeRepository = $imageTypeRepository;
$this->logger = $logger ?? new NullLogger();
}
/**
* Add new theme from zipball. This will unzip the file and move the content
* to the right locations.
* A theme can bundle modules, resources, documentation, email templates and so on.
*
* @param string $source The source can be a module name (installed from either local disk or addons.prestashop.com).
* or a location (url or path to the zip file)
*
* @return bool true for success
*/
public function install($source)
{
if ((filter_var($source, FILTER_VALIDATE_URL))) {
$source = Tools::createFileFromUrl($source);
}
if (preg_match('/\.zip$/', $source)) {
$this->installFromZip($source);
}
return true;
}
/**
* Remove all theme files, resources, documentation and specific modules.
*
* @param string $name The source can be a module name (installed from either local disk or addons.prestashop.com).
* or a location (url or path to the zip file)
*
* @return bool true for success
*/
public function uninstall($name)
{
if (!$this->employee->can('delete', 'AdminThemes')) {
return false;
}
/** @var Theme $theme */
$theme = $this->themeRepository->getInstanceByName($name);
$theme->onUninstall();
$this->filesystem->remove($theme->getDirectory());
return true;
}
/**
* Download new files from source, backup old files, replace files with new ones
* and execute all necessary migration scripts form current version to the new one.
*
* @param string $name
* @param string $version the version you want to up upgrade to
* @param string $source if the upgrade is not coming from addons, you need to specify the path to the zipball
*
* @return bool true for success
*/
public function upgrade($name, $version, $source = null)
{
return true;
}
/**
* Actions to perform when switching from another theme to this one.
* Example:
* - update configuration
* - enable/disable modules.
*
* @param string $name The theme name to enable
* @param bool $force bypass user privilege checks
*
* @return bool True for success
*/
public function enable($name, $force = false)
{
if (!$force && !$this->employee->can('edit', 'AdminThemes')) {
return false;
}
/* if file exits, remove it and use YAML configuration file instead */
@unlink($this->appConfiguration->get('_PS_CONFIG_DIR_') . 'themes/' . $name . '/shop' . $this->shop->id . '.json');
/** @var Theme $theme */
$theme = $this->themeRepository->getInstanceByName($name);
if (!$this->themeValidator->isValid($theme)) {
return false;
}
$this->disable($this->shop->theme_name);
try {
$this->doCreateCustomHooks($theme->get('global_settings.hooks.custom_hooks', []))
->doApplyConfiguration($theme->get('global_settings.configuration', []))
->doDisableModules($theme->get('global_settings.modules.to_disable', []))
->doEnableModules($theme->getModulesToEnable())
->doResetModules($theme->get('global_settings.modules.to_reset', []))
->doApplyImageTypes($theme->get('global_settings.image_types', []))
->doHookModules($theme->get('global_settings.hooks.modules_to_hook', []));
$theme->onEnable();
$this->shop->theme_name = $theme->getName();
$this->shop->update();
$this->saveTheme($theme);
} catch (Exception $e) {
$this->logger->error($e->getMessage());
throw $e;
}
return true;
}
/**
* Actions to perform when switching from this theme to another one.
*
* @param string $name The theme name to enable
*
* @return bool True for success
*/
public function disable($name)
{
/** @var Theme $theme */
$theme = $this->themeRepository->getInstanceByName($name);
$theme->getModulesToDisable();
$this->doDisableModules($theme->getModulesToDisable());
@unlink($this->appConfiguration->get('_PS_CONFIG_DIR_') . 'themes/' . $name . '/shop' . $this->shop->id . '.json');
return true;
}
/**
* Actions to perform to restore default settings.
*
* @param string $themeName The theme name to reset
*
* @return bool True for success
*/
public function reset($themeName)
{
return $this->disable($themeName) && $this->enable($themeName);
}
/**
* Returns the last error, if found.
*
* @param string $themeName The technical theme name
*
* @return void
*/
public function getError($themeName)
{
}
/**
* Get all errors of theme install.
*
* @param string $themeName The technical theme name
*
* @return array|string|bool
*/
public function getErrors($themeName)
{
return $this->themeValidator->getErrors($themeName);
}
/**
* @param array $hooks
*
* @return self
*/
private function doCreateCustomHooks(array $hooks): self
{
foreach ($hooks as $hook) {
$this->hookConfigurator->addHook(
$hook['name'],
$hook['title'],
$hook['description']
);
}
return $this;
}
/**
* @param array $configuration
*
* @return self
*/
private function doApplyConfiguration(array $configuration): self
{
foreach ($configuration as $key => $value) {
$this->appConfiguration->set($key, $value);
}
return $this;
}
/**
* @param array $modules
*
* @return self
*
* @throws Exception
*/
private function doDisableModules(array $modules): self
{
$moduleManagerBuilder = ModuleManagerBuilder::getInstance();
$moduleManager = $moduleManagerBuilder->build();
foreach ($modules as $key => $moduleName) {
if ($moduleManager->isInstalled($moduleName) && $moduleManager->isEnabled($moduleName)) {
$moduleManager->disable($moduleName);
}
}
return $this;
}
/**
* @param array $modules
*
* @return self
*
* @throws FailedToEnableThemeModuleException
*/
private function doEnableModules(array $modules): self
{
$moduleManagerBuilder = ModuleManagerBuilder::getInstance();
$moduleManager = $moduleManagerBuilder->build();
foreach ($modules as $key => $moduleName) {
if (!$moduleManager->isInstalled($moduleName)
&& !$moduleManager->install($moduleName)
) {
throw new FailedToEnableThemeModuleException($moduleName, $moduleManager->getError($moduleName));
}
if (!$moduleManager->isEnabled($moduleName)) {
$moduleManager->enable($moduleName);
}
}
return $this;
}
/**
* Reset the modules received in parameters if they are installed and enabled.
*
* @param string[] $modules
*
* @return self
*/
private function doResetModules(array $modules): self
{
$moduleManagerBuilder = ModuleManagerBuilder::getInstance();
$moduleManager = $moduleManagerBuilder->build();
foreach ($modules as $moduleName) {
if ($moduleManager->isInstalled($moduleName)) {
$moduleManager->reset($moduleName);
}
}
return $this;
}
/**
* @param array $hooks
*
* @return self
*/
private function doHookModules(array $hooks): self
{
$this->hookConfigurator->setHooksConfiguration($hooks);
return $this;
}
/**
* @param array $types
*
* @return self
*/
private function doApplyImageTypes(array $types): self
{
$this->imageTypeRepository->setTypes($types);
return $this;
}
/**
* @param string $source
*
* @throws ThemeAlreadyExistsException
* @throws ThemeConstraintException
*/
private function installFromZip($source)
{
/** @var Finder $finderClass */
$finderClass = get_class($this->finder);
$this->finder = $finderClass::create();
$sandboxPath = $this->getSandboxPath();
Tools::ZipExtract($source, $sandboxPath);
$themeConfigurationFile = $sandboxPath . '/config/theme.yml';
if (!file_exists($themeConfigurationFile)) {
$this->logger->error(sprintf('Configuration file not found %s', $themeConfigurationFile));
throw new ThemeConstraintException('Missing theme configuration file which should be in located in /config/theme.yml', ThemeConstraintException::MISSING_CONFIGURATION_FILE);
}
$theme_data = (new Parser())->parse(file_get_contents($themeConfigurationFile));
$theme_data['directory'] = $sandboxPath;
try {
$theme = new Theme($theme_data);
} catch (ErrorException $exception) {
$errorMessage = sprintf('Theme data %s is not valid', var_export($theme_data, true));
$this->logger->error($errorMessage);
throw new ThemeConstraintException($errorMessage, ThemeConstraintException::INVALID_DATA, $exception);
}
if (!$this->themeValidator->isValid($theme)) {
$this->filesystem->remove($sandboxPath);
$this->themeValidator->getErrors($theme->getName());
$errorMessage = sprintf('Theme configuration file is not valid - %s', var_export($this->themeValidator->getErrors($theme->getName()), true));
$this->logger->error($errorMessage);
throw new ThemeConstraintException($errorMessage, ThemeConstraintException::INVALID_CONFIGURATION);
}
$module_root_dir = $this->appConfiguration->get('_PS_MODULE_DIR_');
$modules_parent_dir = $sandboxPath . '/dependencies/modules';
if ($this->filesystem->exists($modules_parent_dir)) {
$module_dirs = $this->finder->directories()
->in($modules_parent_dir)
->depth('== 0');
/** @var SplFileInfo $dir */
foreach (iterator_to_array($module_dirs) as $dir) {
$destination = $module_root_dir . basename($dir->getFileName());
if (!$this->filesystem->exists($destination)) {
$this->filesystem->mkdir($destination);
}
$this->filesystem->mirror($dir->getPathName(), $destination);
}
$this->filesystem->remove($modules_parent_dir);
}
$themePath = $this->appConfiguration->get('_PS_ALL_THEMES_DIR_') . $theme->getName();
if ($this->filesystem->exists($themePath)) {
$errorMessage = $this->translator->trans('There is already a theme named ' . $theme->getName() . ' in your themes/ folder. Remove it if you want to continue.', [], 'Admin.Design.Notification');
$this->logger->error($errorMessage);
throw new ThemeAlreadyExistsException($theme->getName(), $errorMessage);
}
$this->filesystem->mkdir($themePath);
$this->filesystem->mirror($sandboxPath, $themePath);
$this->importTranslationToDatabase($theme);
$this->filesystem->remove($sandboxPath);
}
private function getSandboxPath()
{
if (!isset($this->sandbox)) {
$this->sandbox = $this->appConfiguration->get('_PS_CACHE_DIR_') . 'sandbox/' . uniqid() . '/';
$this->filesystem->mkdir($this->sandbox, PsFileSystem::DEFAULT_MODE_FOLDER);
}
return $this->sandbox;
}
/**
* @param Theme $theme
*/
public function saveTheme($theme)
{
$jsonConfigFolder = $this->appConfiguration->get('_PS_CONFIG_DIR_') . 'themes/' . $theme->getName();
if (!$this->filesystem->exists($jsonConfigFolder) && !is_dir($jsonConfigFolder)) {
mkdir($jsonConfigFolder, PsFileSystem::DEFAULT_MODE_FOLDER, true);
}
file_put_contents(
$jsonConfigFolder . '/shop' . $this->shop->id . '.json',
json_encode($theme->get(null))
);
}
/**
* Import translation from Theme to Database.
*
* @param Theme $theme
*/
private function importTranslationToDatabase(Theme $theme)
{
global $kernel; // sf kernel
if (!(null !== $kernel && $kernel instanceof \Symfony\Component\HttpKernel\KernelInterface)) {
return;
}
$translationService = $kernel->getContainer()->get('prestashop.service.translation');
$themeProvider = $kernel->getContainer()->get('prestashop.translation.theme_provider');
$themeName = $theme->getName();
$themePath = $this->appConfiguration->get('_PS_ALL_THEMES_DIR_') . $themeName;
$translationFolder = $themePath . DIRECTORY_SEPARATOR . 'translations' . DIRECTORY_SEPARATOR;
$languages = Language::getLanguages();
foreach ($languages as $language) {
$locale = $language['locale'];
// retrieve Lang doctrine entity
try {
$lang = $translationService->findLanguageByLocale($locale);
} catch (Exception $exception) {
PrestaShopLogger::addLog('ThemeManager->importTranslationToDatabase() - Locale ' . $locale . ' does not exists');
continue;
}
// check if translation dir for this lang exists
if (!is_dir($translationFolder . $locale)) {
continue;
}
try {
// construct a new catalog for this lang and import in database if key and message are different
$messageCatalog = $this->translationFinder->getCatalogueFromPaths(
[$translationFolder . $locale],
$locale
);
// get all default domain from catalog
$allDomains = $this->getDefaultDomains($locale, $themeProvider);
// do the import
$this->handleImport($translationService, $messageCatalog, $allDomains, $lang, $locale, $themeName);
} catch (FileNotFoundException $e) {
// if the directory is there but there are no files, do nothing
}
}
}
/**
* Get all default domain from catalog.
*
* @param string $locale
* @param \PrestaShopBundle\Translation\Provider\ThemeProvider $themeProvider
*
* @return array
*/
private function getDefaultDomains($locale, $themeProvider)
{
$allDomains = [];
$defaultCatalogue = $themeProvider
->setLocale($locale)
->getDefaultCatalogue();
if (empty($defaultCatalogue)) {
return $allDomains;
}
$defaultCatalogue = $defaultCatalogue->all();
if (empty($defaultCatalogue)) {
return $allDomains;
}
foreach (array_keys($defaultCatalogue) as $domain) {
// AdminCatalogFeature.fr-FR to AdminCatalogFeature
$domain = str_replace('.' . $locale, '', $domain);
$allDomains[] = $domain;
}
return $allDomains;
}
/**
* @param TranslationService $translationService
* @param MessageCatalogue $messageCatalog
* @param array $allDomains
* @param \PrestaShopBundle\Entity\Lang $lang
* @param string $locale
* @param string $themeName
*/
private function handleImport(TranslationService $translationService, MessageCatalogue $messageCatalog, $allDomains, $lang, $locale, $themeName)
{
foreach ($messageCatalog->all() as $domain => $messages) {
$domain = str_replace('.' . $locale, '', $domain);
if (in_array($domain, $allDomains)) {
continue;
}
foreach ($messages as $key => $message) {
if ($key !== $message) {
$translationService->saveTranslationMessage($lang, $domain, $key, $message, $themeName);
}
}
}
}
}
xxxxx1.0, XXX xxxx